Skip to content

Commit

Permalink
Minimum 80 perc test coverage (#20)
Browse files Browse the repository at this point in the history
* clean up models dir

* use dedicated test resources

* create dedicated test resources

* add close Action coverage

* add exits Action tests

* add say Action tests

* add open Action tests

* add quit Action tests

* add logout Action tests, update existing tests

* update command and output tests

* add missing client test coverage

* add missing door test coverage

* add register Action tests, improve database factory

* add login Action tests

* add inventory Action tests

* update github workflow

* speed up database fixture, and remove test sleep

* only hash db fixture password once

* add drop Action tests

* add get Action tests

* add finalize Action tests

* add move Action tests

* add look Action tests, improve existing tests

* add schedule event tests
  • Loading branch information
wesker-albert authored Sep 1, 2023
1 parent 642e041 commit a0ced2e
Show file tree
Hide file tree
Showing 50 changed files with 1,299 additions and 295 deletions.
10 changes: 5 additions & 5 deletions .env.test
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
DATABASE_PATH=test_database.db
DATABASE_PATH=:memory:
SERVER_PORT=51234

MOTD_PATH=/cibo/resources/motd.txt
ROOMS_PATH=/cibo/resources/rooms.json
DOORS_PATH=/cibo/resources/doors.json
ITEMS_PATH=/cibo/resources/items.json
MOTD_PATH=/tests/resources/motd.txt
ROOMS_PATH=/tests/resources/rooms.json
DOORS_PATH=/tests/resources/doors.json
ITEMS_PATH=/tests/resources/items.json
4 changes: 2 additions & 2 deletions .github/workflows/quality-control.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ jobs:
with:
filename: coverage.xml
badge: false
fail_below_min: false
fail_below_min: true
format: markdown
hide_branch_rate: false
hide_branch_rate: true
hide_complexity: true
indicators: true
output: both
Expand Down
19 changes: 10 additions & 9 deletions cibo/actions/commands/finalize.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""Finalizes the creation of a new player."""

from sqlite3 import IntegrityError
from typing import List

from peewee import IntegrityError

from cibo.actions.__action__ import Action
from cibo.client import Client
from cibo.exception import ClientIsLoggedIn, PlayerAlreadyExists, PlayerNotRegistered
Expand Down Expand Up @@ -31,14 +32,6 @@ def not_registered_message(self) -> str:

return "You'll need to [green]register[/] before you can [green]finalize[/]."

def successfully_registered_message(self, player_name: str) -> str:
"""Finalization was successful."""

return (
f"[cyan]{player_name}[/] has been created. You can now [green]login[/] "
"with this player."
)

def player_already_exists_message(self, player_name: str) -> str:
"""Player name is already taken."""

Expand All @@ -47,6 +40,14 @@ def player_already_exists_message(self, player_name: str) -> str:
"Please [green]register[/] again with a different name."
)

def successfully_registered_message(self, player_name: str) -> str:
"""Finalization was successful."""

return (
f"[cyan]{player_name}[/] has been created. You can now [green]login[/] "
"with this player."
)

def save_player_registration(self, client: Client) -> None:
"""Save the registered Player to the database.
Expand Down
4 changes: 2 additions & 2 deletions cibo/actions/commands/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def logging_in_message(self, player_name: str) -> Announcement:
)

def check_for_player_session(self, name: str) -> None:
"""Checks to see if the Player is already logged into and active session, by
"""Checks to see if the Player is already logged into an active session, by
a different client.
Args:
Expand All @@ -77,7 +77,7 @@ def check_for_player_session(self, name: str) -> None:
"""

for client in self._telnet.get_connected_clients():
if client.is_logged_in and client.player and client.player.name == name:
if client.is_logged_in and client.player.name == name:
raise PlayerSessionActive

def process(self, client: Client, _command: str, args: List[str]) -> None:
Expand Down
8 changes: 5 additions & 3 deletions cibo/actions/commands/logout.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ def logging_out_message(self, player_name: str) -> Announcement:
"You slowly fade away into obscurity, like you always feared you would...",
"A black van pulls up, and 2 large men in labcoats abduct "
f"[cyan]{player_name}[/]. The van speeds away. You wonder if "
"you'll ever see your them again...",
"you'll ever see them again...",
)

def process(self, client: Client, command: str, args: List[str]) -> None:
def process(
self, client: Client, command: str, args: List[str], sleep_time: int = 1
) -> None:
try:
if not client.is_logged_in:
raise ClientNotLoggedIn
Expand All @@ -47,7 +49,7 @@ def process(self, client: Client, command: str, args: List[str]) -> None:
self.logging_out_message(player_name), client, player_room, prompt=False
)

sleep(1)
sleep(sleep_time)

# process the connection Action, so the client knows they can now register
# or login again
Expand Down
7 changes: 3 additions & 4 deletions cibo/actions/commands/move.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,9 @@ def process(self, client: Client, command: str, _args: List[str]) -> None:
self.output.send_private_message(client, self.exit_not_found_message)

except (DoorIsClosed, DoorIsLocked):
if door:
self.output.send_private_message(
client, self.door_is_closed_message(door.name)
)
self.output.send_private_message(
client, self.door_is_closed_message(door.name)
)

except (DoorNotFound, DoorIsOpen):
# update the player's current room to the one they're navigating to
Expand Down
6 changes: 4 additions & 2 deletions cibo/actions/commands/quit.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ def quitting_message(self, player_name: Optional[str]) -> Announcement:
"then proceed to drop their microphone, and walk off the stage.",
)

def process(self, client: Client, _command: str, _args: List[str]) -> None:
def process(
self, client: Client, _command: str, _args: List[str], sleep_time: int = 1
) -> None:
try:
if client.is_logged_in:
raise ClientIsLoggedIn
Expand All @@ -49,5 +51,5 @@ def process(self, client: Client, _command: str, _args: List[str]) -> None:
client, self.quitting_message(None).self_message, prompt=False
)

sleep(1)
sleep(sleep_time)
client.disconnect()
2 changes: 1 addition & 1 deletion cibo/actions/commands/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ def process(self, client: Client, _command: str, args: List[str]) -> None:
player_name = args[0]
password = args[1]

self.check_for_existing_player(player_name)
self.validate_player_info(player_name, password)
self.check_for_existing_player(player_name)

except ClientIsLoggedIn:
self.output.send_private_message(client, self.is_logged_in_message)
Expand Down
2 changes: 1 addition & 1 deletion cibo/actions/scheduled/every_minute.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ def required_args(self) -> List[str]:
def process(
self, client: Client, _command: Optional[str], _args: List[str]
) -> None:
if client.is_logged_in and client.player:
if client.is_logged_in:
client.player.save()
5 changes: 3 additions & 2 deletions cibo/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,9 @@ def log_out(self) -> None:
"""Log the client out of their current Player session."""

self.login_state = ClientLoginState.PRE_LOGIN
if self.player:
self.player.save()

self.player.save()

self.player = Player()

def log_in(self, player: Player) -> None:
Expand Down
2 changes: 1 addition & 1 deletion cibo/events/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@ def process(self) -> None:
client, None, []
)

if isinstance(ex, Exception):
if isinstance(ex, Exception): # pytest: no cover
raise ex
2 changes: 1 addition & 1 deletion cibo/models/door.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def is_closed(self) -> bool:
bool: True, if closed.
"""

return not self.flags or DoorFlag.CLOSED in self.flags
return DoorFlag.CLOSED in self.flags

@property
def is_open(self) -> bool:
Expand Down
59 changes: 55 additions & 4 deletions tests/actions/commands/test_close.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,63 @@
from tests.conftest import ClientFactory, CloseActionFactory
from cibo.client import ClientLoginState
from cibo.output import Announcement
from tests.conftest import CloseActionFactory


class TestCloseAction(ClientFactory, CloseActionFactory):
class TestCloseAction(CloseActionFactory):
def test_action_close_aliases(self):
assert self.close.aliases() == ["close"]

def test_action_close_required_args(self):
assert not self.close.required_args()

def test_action_close_process(self):
self.close.process(self.mock_client, "close", ["north"])
def test_action_close_process_not_logged_in(self):
self.client.login_state = ClientLoginState.PRE_LOGIN

self.close.process(self.client, "close", ["n"])

self.output.send_prompt.assert_called_once_with(self.client)

def test_action_close_process_missing_args(self):
self.close.process(self.client, "close", [])

self.output.send_private_message.assert_called_with(
self.client, "You close your eyes and daydream about money and success."
)

def test_action_close_process_door_is_closed(self):
self.close.process(self.client, "close", ["n"])

self.output.send_private_message.assert_called_with(
self.client, "A wooden door is already closed."
)

def test_action_close_process_door_is_locked(self):
self.close.process(self.client, "close", ["s"])

self.output.send_private_message.assert_called_with(
self.client, "A steel security door is already closed."
)

def test_action_close_process_door_not_found(self):
self.close.process(self.client, "close", ["w"])

self.output.send_private_message.assert_called_with(
self.client, "There's nothing to close."
)

def test_action_close_process_close_door(self):
self.close.process(self.client, "close", ["e"])

door = self.close.doors.get_by_room_ids(1, 3)
assert door.is_closed

self.output.send_local_announcement.assert_called_once_with(
Announcement(
self_message="You close a propped-open door.",
room_message="[cyan]frank[/] closes a propped-open door.",
adjoining_room_message="A propped-open door closes.",
),
self.client,
1,
3,
)
58 changes: 58 additions & 0 deletions tests/actions/commands/test_drop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from cibo.client import ClientLoginState
from cibo.models.data.item import Item
from cibo.models.data.player import Player
from cibo.output import Announcement
from tests.conftest import DropActionFactory


class TestDropAction(DropActionFactory):
def test_action_drop_aliases(self):
assert self.drop.aliases() == ["drop"]

def test_action_drop_required_args(self):
assert not self.drop.required_args()

def test_action_drop_process_not_logged_in(self):
self.client.login_state = ClientLoginState.PRE_LOGIN

self.drop.process(self.client, "drop", [])

self.output.send_prompt.assert_called_once_with(self.client)

def test_action_drop_process_missing_args(self):
self.drop.process(self.client, "drop", [])

self.output.send_private_message.assert_called_with(
self.client, "Drop what? Your pants? No way!"
)

def test_action_drop_process_inventory_item_not_found(self, _fixture_database):
self.client.player = Player.get_by_name("frank")
self.give_item_to_player(2, self.client.player)

self.drop.process(self.client, "drop", ["spoon"])

self.output.send_private_message.assert_called_with(
self.client, "You scour your inventory, but can't find that."
)

def test_action_drop_process_dropped_tem(self, _fixture_database):
self.client.player = Player.get_by_name("frank")
self.give_item_to_player(2, self.client.player)

self.drop.process(self.client, "drop", ["fork"])

item = Item.get_by_id(2)

assert not item.player
assert item.room_id == 1

self.output.send_local_announcement.assert_called_once_with(
Announcement(
self_message="You drop a metal fork.",
room_message="[cyan]frank[/] drops a metal fork.",
adjoining_room_message=None,
),
self.client,
1,
)
24 changes: 24 additions & 0 deletions tests/actions/commands/test_exits.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from cibo.client import ClientLoginState
from tests.conftest import ExitsActionFactory


class TestExitsAction(ExitsActionFactory):
def test_action_exits_aliases(self):
assert self.exits.aliases() == ["exits"]

def test_action_exits_required_args(self):
assert not self.exits.required_args()

def test_action_exits_process_not_logged_in(self):
self.client.login_state = ClientLoginState.PRE_LOGIN

self.exits.process(self.client, "exits", [])

self.output.send_prompt.assert_called_once_with(self.client)

def test_action_exits_process(self):
self.exits.process(self.client, "exits", [])

self.output.send_private_message.assert_called_with(
self.client, "[green]Exits:[/] east, north, south, west"
)
57 changes: 57 additions & 0 deletions tests/actions/commands/test_finalize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from cibo.client import ClientLoginState
from cibo.models.data.player import Player
from tests.conftest import FinalizeActionFactory


class TestFinalizeAction(FinalizeActionFactory):
def test_action_finalize_aliases(self):
assert self.finalize.aliases() == ["finalize"]

def test_action_finalize_required_args(self):
assert not self.finalize.required_args()

def test_action_finalize_process_logged_in(self):
self.client.login_state = ClientLoginState.LOGGED_IN

self.finalize.process(self.client, "finalize", [])

self.output.send_private_message.assert_called_with(
self.client,
"You finalize your written will, leaving your whole estate to your cat.",
)

def test_action_finalize_process_not_registered(self):
self.finalize.process(self.client, "finalize", [])

self.output.send_private_message.assert_called_with(
self.client,
"You'll need to [green]register[/] before you can [green]finalize[/].",
)

def test_action_finalize_process_player_already_exists(self, _fixture_database):
self.client.registration = Player(
name="frank", password="abcd1234", current_room_id=1
)

self.finalize.process(self.client, "finalize", [])

self.output.send_private_message.assert_called_with(
self.client,
"Sorry, turns out the name [cyan]frank[/] is already taken. Please [green]register[/] again with a different name.",
)

def test_action_finalize_process_create_player(self, _fixture_database):
self.client.registration = Player(
name="jennifer", password="abcd1234", current_room_id=1
)

self.finalize.process(self.client, "finalize", [])

assert not self.client.is_registered
player = Player.get_by_name("jennifer")
assert len(player.inventory) == 1

self.output.send_private_message.assert_called_with(
self.client,
"[cyan]jennifer[/] has been created. You can now [green]login[/] with this player.",
)
Loading

0 comments on commit a0ced2e

Please sign in to comment.