def test_mark_delete_valid(rescue_sop_fx: Rescue, reporter: str, reason: str): """ Verifies Rescue.mark functions as expected when marking a case for deletion """ rescue_sop_fx.mark_delete(reporter, reason) assert rescue_sop_fx.marked_for_deletion.marked assert reporter == rescue_sop_fx.marked_for_deletion.reporter assert reason == rescue_sop_fx.marked_for_deletion.reason
def test_mark_for_deletion_unset(rescue_sop_fx: Rescue): """ Verify unmarking a case that was MD'ed works as expected """ rescue_sop_fx.marked_for_deletion = MarkForDeletion( True, "unit_test[BOT]", "unit test reasons!") rescue_sop_fx.unmark_delete() assert rescue_sop_fx.marked_for_deletion.marked is False assert rescue_sop_fx.marked_for_deletion.reporter is None assert rescue_sop_fx.marked_for_deletion.reason is None
def rescue_sop_fx(request) -> Rescue: """ A Rescue fixture providing Rescue objects for the 3 supported platforms Args: request (): Provided by fixture Parametrization Returns: Rescue : Rescue objects """ params = request.param myRescue = Rescue(uuid4(), client=params[0], system=params[2], irc_nickname=params[0], board_index=params[3]) myRescue.platform = params[1] return myRescue
def append(self, rescue: Rescue, overwrite: bool = False) -> None: """ Accept a Rescue object and attach it to the board Args: rescue (Rescue): Rescue object to attach overwrite(bool) : **overwrite** existing keys, if necessary. requires `rescue` to have a `board_index` set, otherwise it does nothing. Returns: None Raises: IndexNotFreeError: Attempt to write a rescue to a key that is already set. """ # if the rescue already has a board index defined if rescue.board_index is not None: # check if the board index is not in use, or the overwrite flag is set if overwrite or rescue.board_index not in self.rescues: # write the key,value self.rescues[rescue.board_index] = rescue else: raise IndexNotFreeError( f"Index {rescue.board_index} is in use. If you want to overwrite this you must" f"set the `overwrite` flag.") # we need to give it one else: rescue.board_index = self.next_free_index() self.rescues[rescue.board_index] = rescue
def test_rescue_creation_with_overwrite(self): """ Verifies a rescue can be added as to overwrite an existing entry. """ self.board.append(rescue=self.some_rescue) my_rescue = Rescue(uuid4(), "foo", "bar", "foo", board_index=-42) self.board.append(rescue=my_rescue, overwrite=True) self.assertEqual(self.board.rescues[-42], my_rescue)
def test_set_unidentified_rats_garbage_in_list(rescue_plain_fx: Rescue): """ Verifies a ValueError is raised if the list passed to Rat.unidentified_Rats contains illegal values """ garbage = [12, -42.2, None] with pytest.raises(ValueError): rescue_plain_fx.unidentified_rats = garbage
def rescue_plain_fx() -> Rescue: """ A plain initialized Rescue without parametrization Returns: Rescue : Plain initialized Rescue """ return Rescue(uuid4(), "UNIT_TEST", "ki", "UNIT_TEST", board_index=42)
def test_lang_id_garbage(garbage, rescue_plain_fx: Rescue): """ Verifies throwing garbage types at Rescue.lang_id results in a TypeError Args: garbage (): Garbage to throw rescue_plain_fx (Rescue): Plain rescue Fixture """ with pytest.raises(TypeError): rescue_plain_fx.lang_id = garbage
def test_irc_nickname_garbage(garbage, rescue_plain_fx: Rescue): """ Verifies throwing garbage types at Rescue.irc_nickname results in a TypeError Args: garbage (): Garbage to throw rescue_plain_fx (Rescue): Plain rescue Fixture """ with pytest.raises(TypeError): rescue_plain_fx.irc_nickname = garbage
def test_search_garbage_raises_exception(self, test_input, rat_board_fx: RatBoard, rescue_plain_fx: Rescue): rescue_plain_fx.uuid = UUID('12345678-9876-53d1-ea5e-0000deadbeef') rat_board_fx.append(rescue_plain_fx) with pytest.raises(( TypeError, ValueError, )): rat_board_fx.search(test_input)
def test_rescue_board_index(rescue_plain_fx): """ Verifies board index is NOT set without a rescue attached """ # Do not set board index test_rescue = Rescue(uuid4(), 'Test_Client', 'AliothJr', 'TestClient') assert test_rescue.board_index is None # Add rescue fixture test_rescue = rescue_plain_fx assert test_rescue.board_index == 42 # Add a negative int for board index, ensuring ValueError is thrown with pytest.raises(ValueError): test_rescue.board_index = -99 # Add incorrect type, ensuring TypeError is thrown with pytest.raises(TypeError): test_rescue.board_index = 'Index!'
def setUp(self): """ Set up for each test """ super().setUp() self.board = RatBoard() self.some_rescue = Rescue(uuid4(), "unit_test[BOT]", "snafu", "unit_test", board_index=-42)
def test_irc_nickname_strings(test_input, rescue_plain_fx: Rescue): """ Verifies the irc nickname can be set when passed a string Args: test_input (str): values to test rescue_plain_fx (Rescue): Rescue fixture """ rescue_plain_fx.irc_nickname = test_input assert rescue_plain_fx.irc_nickname == test_input
def test_lang_id_strings(test_input, rescue_plain_fx: Rescue): """ Verifies the lang id can be set when passed a string Args: test_input (str): values to test rescue_plain_fx (Rescue): Rescue fixture """ rescue_plain_fx.lang_id = test_input assert rescue_plain_fx.lang_id == test_input
def test_rescue_Creation_without_index(self): """ Verifies a Rescue can be added without a defined index. the board should give our rescue one. """ guid = uuid4() name = "SicklyTadPole" my_rescue = Rescue(guid, name, "NLTT 48288", name) self.board.append(my_rescue) found = self.board.find_by_uuid(guid) self.assertIsNotNone(found) self.assertEqual(found.client, name)
def test_contains_existing_by_uuid(self): """ Verifies `RatBoard.__contains__` returns true when the a case with the same api UUID is known and tracked by the board Notes: This branch should only verify a rescue exists *with the same uuid*, it should do no further checks. """ # add a case self.board.append(self.some_rescue) # make our assertion self.assertTrue( # spawn a case with the same uuid, and make our check Rescue(self.some_rescue.uuid, "nope", "i have no idea!", "nope") in self.board)
def test_epic_rescue_attached(epic_fx): """ Verifies attached epic object referenced by rescue is the same object, and that only one rescue has been added. """ # Create local rescue object test_rescue = Rescue(uuid4(), 'TestClient', 'Alioth', 'Test_Client', epic=[epic_fx]) # One rescue added, the List should return only ONE Epic. assert len(test_rescue.epic) == 1 # Check that the epic object in list is epic_fx assert test_rescue.epic[0] is epic_fx
def test_contains_by_key_attributes(self, rescue_sop_fx: Rescue, rat_board_fx: RatBoard): """ Verifies `Ratboard.__contains__` returns true when looking for a case by key attributes only Args: rescue_sop_fx (Rescue): rescue fixture rat_board_fx (RatBoard): RatBoard fixture """ # add our rescue to the board rat_board_fx.append(rescue=rescue_sop_fx) # overwrite our local rescue objects id rescue_sop_fx._api_id = None assert rescue_sop_fx in rat_board_fx
def test_mark_delete_invalid(rescue_sop_fx: Rescue): """ Verify what happens when garbage gets thrown at `rescue.mark` """ with pytest.raises(TypeError): rescue_sop_fx.mark_delete(None, "sna") with pytest.raises(TypeError): rescue_sop_fx.mark_delete("sna", None) with pytest.raises(ValueError): rescue_sop_fx.mark_delete("unit_test", "")
def test_set_unidentified_rats_incorrect_type(rescue_plain_fx: Rescue): """ Verifies a TypeError is raised if another type other than list is passed. """ with pytest.raises(TypeError): rescue_plain_fx.unidentified_rats = 'Snozzberry, Wonka, Doc'
def test_search_garbage_returns_none(self, test_input, rat_board_fx: RatBoard, rescue_plain_fx: Rescue): rescue_plain_fx.uuid = UUID('12345678-9876-53d1-ea5e-0000deadbeef') rat_board_fx.append(rescue_plain_fx) assert rat_board_fx.search(test_input) is None
def test_search_valid(self, test_input, rat_board_fx: RatBoard, rescue_plain_fx: Rescue): rescue_plain_fx.uuid = UUID('12345678-9876-53d1-ea5e-0000deadbeef') rat_board_fx.append(rescue_plain_fx) assert rat_board_fx.search(test_input) == rescue_plain_fx
def test_rescue_defaults(): """ Verifies a Rescue can be initialized with all defaults """ Rescue()
async def handle_ratmama_announcement(ctx: Context) -> None: """ Handles the Announcement made by RatMama. Details are extracted, wrapped in a Rescue object and appended to the Rescue board. An appropriate answer will be sent to IRC. Args: ctx: Context of the announcement Returns: None """ if ctx.user.nickname.casefold() not in ( k.casefold() for k in config.config["ratsignal_parser"]["announcer_nicks"]): return message: str = ctx.words_eol[0] result = re.fullmatch(ratmama_regex, message) client_name: str = result.group("cmdr") system_name: str = result.group("system") platform_name: str = result.group("platform") o2_status: bool = result.group("o2") == "OK" # false is CR lang_code: str = result.group("language_code") nickname: Optional[str] = result.group("nick") exist_rescue: Optional[Rescue] = ctx.bot.board.find_by_name(client_name) if exist_rescue: # we got a case already! await ctx.reply( f"{client_name} has reconnected! Case #{exist_rescue.board_index}") # now let's make it more visible if stuff changed diff_response = "" if system_name.casefold() != exist_rescue.system.casefold(): diff_response += f"System changed! " if platform_name.casefold() != exist_rescue.platform.name.casefold(): diff_response += "Platform changed! " if not o2_status != exist_rescue.code_red: diff_response += "O2 Status changed!" if o2_status else\ "O2 Status changed, it is now CODE RED!" if diff_response: await ctx.reply(diff_response) else: platform = None if platform_name.casefold() in ("pc", "ps", "xb"): platform = Platforms[platform_name.upper()] else: LOG.warning( f"Got unknown platform from {ctx.user.nickname}: {platform_name}" ) # no case for that name, we have to make our own rescue: Rescue = Rescue(client=client_name, system=system_name, irc_nickname=nickname, code_red=not o2_status, lang_id=lang_code, platform=platform) ctx.bot.board.append(rescue, overwrite=False) index = ctx.bot.board.find_by_name(client=client_name).board_index await ctx.reply( f"RATSIGNAL - CMDR {client_name} - " f"Reported System: {system_name} (distance to be implemented) - " f"Platform: {platform_name} - " f"O2: {'OK' if o2_status else 'NOT OK'} - " f"Language: {result.group('full_language')}" f" (Case #{index}) ({platform_name.upper()}_SIGNAL)")
async def handle_ratsignal(ctx: Context) -> None: """ Tries to extract as much details as possible from a self-issued ratsignal and appends these details to the rescue board. Should it be unable to extract the details, it will open a case and ask for the details to be set and will only set the name and nick fields of the rescue. Args: ctx: Context of the self-issued ratsignal Returns: None """ message: str = ctx.words_eol[0] # the ratsignal is nothing we are interested anymore message = re.sub("ratsignal", "", message, flags=re.I) for rescue in ctx.bot.board.rescues.values(): if rescue.irc_nickname.casefold() == ctx.user.nickname.casefold(): await ctx.reply( "You already sent a signal, please be patient while a dispatch is underway." ) return sep: Optional[str] = None if ',' in message: sep = ',' elif ';' in message: sep = ';' elif '|' in message: sep = '|' elif '-' in message: sep = '-' if not sep: ctx.bot.board.append( Rescue(irc_nickname=ctx.user.nickname, client=ctx.user.nickname)) index = ctx.bot.board.find_by_name(ctx.user.nickname) await ctx.reply( f"Case #{index} created for {ctx.user.nickname}, please set details" ) return system: str = None cr: bool = False platform: Platforms = None for part in message.split(sep): part = part.strip() if part.casefold() in ("pc", ): platform = Platforms["PC"] elif part.casefold() in ("ps", "ps4", "playstation", "playstation4", "playstation 4"): platform = Platforms["PS"] elif part.casefold() in ("xb", "xb1", "xbox", "xboxone", "xbox one"): platform = Platforms["XB"] elif "o2" in part.casefold(): cr = "o2 ok" not in part.casefold() else: system = part rescue = Rescue(client=ctx.user.nickname, system=system, irc_nickname=ctx.user.nickname, code_red=cr, platform=platform) ctx.bot.board.append(rescue) await ctx.reply(f"Case created for {ctx.user.nickname}" f" on {platform.name} in {system}. " f"{'O2 status is okay' if not cr else 'This is a CR!'} " f"- {platform.name.upper()}_SIGNAL")