async def test__on_member_remove(self, mmj_patch): """Unit tests for bot._on_member_remove function.""" # async def _on_member_remove(bot, member) _on_member_remove = bot._on_member_remove # bad guild member = mock.MagicMock(discord.Member, guild=3) await _on_member_remove(config.bot, member) config.Channel.logs.send.assert_not_called() mmj_patch.assert_not_called() # good guild member = mock.MagicMock(discord.Member, guild=config.guild) await _on_member_remove(config.bot, member) mock_discord.assert_sent(config.Channel.logs, [mmj_patch.return_value, "ALERTE", member.display_name])
async def test_interact(self, bloc_patch, aic_patch): """Unit tests for RealShell.interact method.""" # async def interact(self, banner=None, exitmsg="Byebye!") interact = realshell.RealShell.interact bloc_patch.side_effect = lambda data: f"<!<{data}>!>" # simple channel = mock_discord.chan("tezt") slf = mock.Mock(realshell.RealShell, channel=channel) await interact(slf) mock_discord.assert_sent(channel, "Launching Python shell") aic_patch.assert_called_once_with(mock.ANY, "Byebye!") banner = aic_patch.call_args.args[0] self.assertIn("Discord implementation", banner) slf.message.clear_reactions.assert_called_once() aic_patch.reset_mock() # complex channel = mock_discord.chan("tezt") slf = mock.Mock(realshell.RealShell, channel=channel) await interact(slf, banner="LULZ", exitmsg="allo?") mock_discord.assert_sent(channel, "Launching Python shell") aic_patch.assert_called_once_with("LULZ", "allo?") slf.message.clear_reactions.assert_called_once() aic_patch.reset_mock() # simple, exited aic_patch.side_effect = SystemExit channel = mock_discord.chan("tezt") slf = mock.Mock(realshell.RealShell, channel=channel) with self.assertRaises(realshell.RealShellExit): await interact(slf) mock_discord.assert_sent(channel, "Launching Python shell") aic_patch.assert_called_once_with(mock.ANY, "Byebye!") slf.write.assert_called_once_with(f"\nByebye!", refresh=True, show_caret=False) slf.message.clear_reactions.assert_called_once() aic_patch.reset_mock() # complex, exited channel = mock_discord.chan("tezt") slf = mock.Mock(realshell.RealShell, channel=channel) aic_patch.side_effect = SystemExit with self.assertRaises(realshell.RealShellExit): await interact(slf, banner="LULZ", exitmsg="allo?") mock_discord.assert_sent(channel, "Launching Python shell") aic_patch.assert_called_once_with("LULZ", "allo?") slf.write.assert_called_once_with(f"\nallo?", refresh=True, show_caret=False) slf.message.clear_reactions.assert_called_once()
async def test__on_error(self): """Unit tests for bot._on_error function.""" # async def _on_error(bot, event, *args, **kwargs) _on_error = bot._on_error # SQLAlchemyError exc = bdd.SQLAlchemyError("bzzt") with self.assertRaises(bdd.SQLAlchemyError): # re-raised try: raise exc except bdd.SQLAlchemyError: # called within a running except block await _on_error(config.bot, "event") mock_discord.assert_sent( config.Channel.logs, "Rollback session", [f"{config.Role.mj.mention} ALED : Exception Python", "Traceback", "SQLAlchemyError", "bzzt"]) config.Channel.logs.send.reset_mock() config.session.rollback.assert_called_once() config.session.rollback.reset_mock() # DriverOperationalError exc = bdd.DriverOperationalError("koook") with self.assertRaises(bdd.DriverOperationalError): # re-raised try: raise exc except bdd.DriverOperationalError: # called within a running except block await _on_error(config.bot, "event") mock_discord.assert_sent( config.Channel.logs, "Rollback session", [f"{config.Role.mj.mention} ALED : Exception Python", "Traceback", bdd.DriverOperationalError.__name__, "koook"]) config.Channel.logs.send.reset_mock() config.session.rollback.assert_called_once() config.session.rollback.reset_mock() # BDD error - session not ready : on vérifie juste que pas d'erreur exc = bdd.SQLAlchemyError("bzzt") _session = config.session del config.session with self.assertRaises(bdd.SQLAlchemyError): # re-raised try: raise exc except bdd.SQLAlchemyError: # called within a running except block await _on_error(config.bot, "event") mock_discord.assert_sent( config.Channel.logs, [f"{config.Role.mj.mention} ALED : Exception Python", "Traceback", "SQLAlchemyError", "bzzt"]) config.Channel.logs.send.reset_mock() config.session = _session # other exception class SomeException(Exception): pass with self.assertRaises(SomeException): # re-raised try: raise SomeException("!a!", "@b@", "^c^") except SomeException: # called within a running except block await _on_error(config.bot, "event") mock_discord.assert_sent( config.Channel.logs, [f"{config.Role.mj.mention} ALED : Exception Python", "Traceback", "SomeException", "!a!", "@b@", "^c^"]) config.Channel.logs.send.reset_mock()
async def test__on_command_error(self): """Unit tests for bot._on_command_error function.""" # async def _on_command_error(bot, ctx, exc) _on_command_error = bot._on_command_error # mauvais serveur ctx = mock.NonCallableMock(commands.Context, guild=10) await _on_command_error(config.bot, ctx, None) ctx.send.assert_not_called() # STOP ctx = mock_discord.get_ctx() exc = commands.CommandInvokeError(blocs.tools.CommandExit()) await _on_command_error(config.bot, ctx, exc) ctx.assert_sent("Mission aborted") # STOP custom message ctx = mock_discord.get_ctx() exc = commands.CommandInvokeError(blocs.tools.CommandExit("cust0m")) await _on_command_error(config.bot, ctx, exc) ctx.assert_sent("cust0m") # BDD error - MJ ctx = mock_discord.get_ctx() ctx.author.top_role = mock.MagicMock(discord.Role, __ge__=lambda s, o: True) # >= MJ exc = commands.CommandInvokeError(bdd.SQLAlchemyError("bzzt")) try: raise exc.original # creating traceback except bdd.SQLAlchemyError: pass await _on_command_error(config.bot, ctx, exc) mock_discord.assert_sent(config.Channel.logs, "Rollback session") config.Channel.logs.send.reset_mock() config.session.rollback.assert_called_once() config.session.rollback.reset_mock() ctx.assert_sent(["Un problème est survenu", "Traceback", "SQLAlchemyError", "bzzt"]) # BDD error - not MJ ctx = mock_discord.get_ctx() ctx.author.top_role = mock.MagicMock(discord.Role, __ge__=lambda s, o: False) # < MJ exc = commands.CommandInvokeError(bdd.DriverOperationalError("bzoozt")) try: raise exc.original # creating traceback except bdd.DriverOperationalError: pass await _on_command_error(config.bot, ctx, exc) mock_discord.assert_sent(config.Channel.logs, "Rollback session") config.Channel.logs.send.reset_mock() config.session.rollback.assert_called_once() config.session.rollback.reset_mock() ctx.assert_sent(["Un problème est survenu", bdd.DriverOperationalError.__name__, "bzoozt"]) ctx.assert_not_sent("Traceback") # BDD error - session not ready : on vérifie juste que pas d'erreur ctx = mock_discord.get_ctx() _session = config.session del config.session ctx.author.top_role = mock.MagicMock(discord.Role, __ge__=lambda s, o: True) # >= MJ exc = commands.CommandInvokeError(bdd.SQLAlchemyError("bzzt")) await _on_command_error(config.bot, ctx, exc) mock_discord.assert_sent(config.Channel.logs) # nothing config.Channel.logs.send.reset_mock() ctx.assert_sent(["Un problème est survenu", "SQLAlchemyError", "bzzt"]) config.session = _session # CommandNotFound ctx = mock_discord.get_ctx() await _on_command_error(config.bot, ctx, commands.CommandNotFound()) ctx.assert_sent("je ne connais pas cette commande") # DisabledCommand ctx = mock_discord.get_ctx() await _on_command_error(config.bot, ctx, commands.DisabledCommand()) ctx.assert_sent("Cette commande est désactivée") # ConversionError command = mock.Mock() ctx = mock_discord.get_ctx(command) exc = commands.ConversionError("bkrkr", "kak") await _on_command_error(config.bot, ctx, exc) ctx.assert_sent(["ce n'est pas comme ça qu'on utilise cette commande", "ConversionError", "bkrkr", "kak"]) config.bot.get_context.assert_called_with(ctx.message) self.assertEqual(ctx.message.content, f"!help {command.name}") config.bot.get_context.return_value.reinvoke.assert_called() # UserInputError command = mock.Mock() ctx = mock_discord.get_ctx(command) exc = commands.UserInputError("bakaka") await _on_command_error(config.bot, ctx, exc) ctx.assert_sent(["ce n'est pas comme ça qu'on utilise cette commande", "UserInputError", "bakaka"]) config.bot.get_context.assert_called_with(ctx.message) self.assertEqual(ctx.message.content, f"!help {command.name}") config.bot.get_context.return_value.reinvoke.assert_called() # UserInputError derivate command = mock.Mock() ctx = mock_discord.get_ctx(command) exc = commands.BadArgument("bakaka") await _on_command_error(config.bot, ctx, exc) ctx.assert_sent(["ce n'est pas comme ça qu'on utilise cette commande", "BadArgument", "bakaka"]) config.bot.get_context.assert_called_with(ctx.message) self.assertEqual(ctx.message.content, f"!help {command.name}") config.bot.get_context.return_value.reinvoke.assert_called() # CheckAnyFailure ctx = mock_discord.get_ctx() exc = commands.CheckAnyFailure(mock.ANY, mock.ANY) await _on_command_error(config.bot, ctx, exc) ctx.assert_sent("cette commande est réservée aux MJs") # MissingAnyRole ctx = mock_discord.get_ctx() exc = commands.MissingAnyRole([mock.ANY]) await _on_command_error(config.bot, ctx, exc) ctx.assert_sent("Cette commande est réservée aux joueurs") # MissingRole ctx = mock_discord.get_ctx() exc = commands.MissingRole(mock.ANY) await _on_command_error(config.bot, ctx, exc) ctx.assert_sent("cette commande est réservée aux joueurs en vie") # one_command.AlreadyInCommand, not addIA/modifIA command = mock.Mock() command.configure_mock(name="blabla") ctx = mock_discord.get_ctx(command) exc = blocs.one_command.AlreadyInCommand() await _on_command_error(config.bot, ctx, exc) ctx.assert_sent("Impossible d'utiliser une commande pendant") # one_command.AlreadyInCommand, addIA command = mock.Mock() command.configure_mock(name="addIA") ctx = mock_discord.get_ctx(command) exc = blocs.one_command.AlreadyInCommand() await _on_command_error(config.bot, ctx, exc) ctx.assert_sent() # one_command.AlreadyInCommand, modifIA command = mock.Mock() command.configure_mock(name="modifIA") ctx = mock_discord.get_ctx(command) exc = blocs.one_command.AlreadyInCommand() await _on_command_error(config.bot, ctx, exc) ctx.assert_sent() # CheckFailure (autre check erreur) ctx = mock_discord.get_ctx() exc = commands.CheckFailure("jojo") with mock.patch("lgrez.blocs.tools.mention_MJ") as mmj_patch: await _on_command_error(config.bot, ctx, exc) mmj_patch.assert_called_once_with(ctx) ctx.assert_sent(["cette commande ne puisse pas être exécutée", "CheckFailure", "jojo"]) # other exception ctx = mock_discord.get_ctx() exc = AttributeError("oh") with mock.patch("lgrez.blocs.tools.mention_MJ") as mmj_patch: await _on_command_error(config.bot, ctx, exc) mmj_patch.assert_called_once_with(ctx) ctx.assert_sent(["Une erreur inattendue est survenue", "AttributeError", "oh"]) # other exception ctx = mock_discord.get_ctx() class SomeException(Exception): pass exc = SomeException("p!wet") with mock.patch("lgrez.blocs.tools.mention_MJ") as mmj_patch: await _on_command_error(config.bot, ctx, exc) mmj_patch.assert_called_once_with(ctx) ctx.assert_sent(["Une erreur inattendue est survenue", "SomeException", "p!wet"])
async def test__on_ready(self, emo_patch, role_patch, ch_patch, ppatch): """Unit tests for bot._on_ready function.""" # async def _on_ready(bot) _on_ready = bot._on_ready # guild not found config.bot.get_guild.return_value = None with self.assertRaises(RuntimeError) as cm: await _on_ready(config.bot) self.assertEqual(config.loop, config.bot.loop) config.bot.i_am_alive.assert_not_called() config.bot.get_guild.assert_called_once_with(config.bot.GUILD_ID) self.assertIn(str(config.bot.GUILD_ID), cm.exception.args[0]) ppatch.assert_not_called() config.bot.get_guild.reset_mock(return_value=True) config.bot.reset_mock() # guild found, everything ok config.output_liveness = False ch_patch.side_effect=functools.partial(mock.Mock, discord.TextChannel) role_patch.side_effect=functools.partial(mock.Mock, discord.Role) emo_patch.side_effect=functools.partial(mock.Mock, discord.Emoji) await _on_ready(config.bot) guild = config.bot.get_guild.return_value self.assertEqual(config.loop, config.bot.loop) config.bot.i_am_alive.assert_not_called() config.bot.get_guild.assert_called_once_with(config.bot.GUILD_ID) self.assertEqual(config.guild, guild) printed = "\n".join(call.args[0] for call in ppatch.call_args_list) self.assertIn("Connected", printed) self.assertIn(str(guild.name), printed) self.assertIn("Initialization", printed) self.assertIn("Initialization", printed) self.assertIn("Initialization complete", printed) self.assertIn("Listening for events", printed) mock_discord.assert_sent(config.Channel.logs, "Just rebooted") mock_discord.assert_not_sent(config.Channel.logs, ["tâches planifiées", "ERREURS"]) ppatch.reset_mock() try: for name in config.Channel: getattr(config.Channel, name) for name in config.Role: getattr(config.Role, name) for name in config.Emoji: getattr(config.Emoji, name) config.private_chan_category_name except ready_check.NotReadyError as e: raise AssertionError from e config.bot.change_presence.assert_called_once() config.bot.reset_mock() mock_discord._unprepare_attributes(config.Role) mock_discord._unprepare_attributes(config.Channel) mock_discord._unprepare_attributes(config.Emoji) # guild found, some missing Discord elements (not #logs / @MJ) def _channel(name): if name in ["rôles", "débats", config.private_chan_category_name]: raise ValueError else: return mock.NonCallableMock(discord.TextChannel) def _role(name): if name in ["Joueur en vie", "Maire"]: raise ValueError else: return mock.NonCallableMock(discord.Role) def _emoji(name): if name == "ro": raise ValueError else: return mock.NonCallableMock(discord.Emoji) ch_patch.side_effect = _channel role_patch.side_effect = _role emo_patch.side_effect = _emoji await _on_ready(config.bot) guild = config.bot.get_guild.return_value self.assertEqual(config.loop, config.bot.loop) config.bot.i_am_alive.assert_not_called() config.bot.get_guild.assert_called_once_with(config.bot.GUILD_ID) self.assertEqual(config.guild, guild) printed = "\n".join(call.args[0] for call in ppatch.call_args_list) self.assertIn("Connected", printed) self.assertIn(str(guild.name), printed) self.assertIn("Initialization", printed) self.assertIn("Initialization complete", printed) self.assertIn("Listening for events", printed) mock_discord.assert_sent( config.Channel.logs, ["ERREURS", "6 errors", 'config.Channel.roles = "rôles"', 'config.Channel.debats = "débats"', str(config.Role.mj.mention), 'catégorie config.private_chan_category_name = ' f'"{config.private_chan_category_name}"', 'config.Role.joueur_en_vie = "Joueur en vie"', 'config.Role.maire = "Maire"', 'config.Emoji.ro = "ro"'], "Just rebooted") mock_discord.assert_not_sent(config.Channel.logs, "tâches planifiées", "tâches planifiées") ppatch.reset_mock() try: for attr in config.Channel: if attr not in ["roles", "debats"]: getattr(config.Channel, attr) for attr in config.Role: if attr not in ["joueur_en_vie", "maire"]: getattr(config.Role, attr) for attr in config.Emoji: if attr != "ro": getattr(config.Emoji, attr) config.private_chan_category_name except ready_check.NotReadyError as e: raise AssertionError from e config.bot.change_presence.assert_called_once() config.bot.reset_mock() mock_discord._unprepare_attributes(config.Role) mock_discord._unprepare_attributes(config.Channel) mock_discord._unprepare_attributes(config.Emoji) # guild found, missing @MJ def _channel(name): return mock.NonCallableMock(discord.TextChannel) def _role(name): if name == "MJ": raise ValueError else: return mock.NonCallableMock(discord.Role) def _emoji(name): return mock.NonCallableMock(discord.Emoji) ch_patch.side_effect = _channel role_patch.side_effect = _role emo_patch.side_effect = _emoji await _on_ready(config.bot) guild = config.bot.get_guild.return_value self.assertEqual(config.loop, config.bot.loop) config.bot.i_am_alive.assert_not_called() config.bot.get_guild.assert_called_once_with(config.bot.GUILD_ID) self.assertEqual(config.guild, guild) printed = "\n".join(call.args[0] for call in ppatch.call_args_list) self.assertIn("Connected", printed) self.assertIn(str(guild.name), printed) self.assertIn("Initialization", printed) self.assertIn("Initialization complete", printed) self.assertIn("Listening for events", printed) mock_discord.assert_sent( config.Channel.logs, ["ERREURS", "1 error", 'config.Role.mj = "MJ"', "@everyone"], "Just rebooted") mock_discord.assert_not_sent(config.Channel.logs, "tâches planifiées", "tâches planifiées") ppatch.reset_mock() try: for attr in config.Channel: getattr(config.Channel, attr) for attr in config.Role: if attr != "mj": getattr(config.Role, attr) for attr in config.Emoji: getattr(config.Emoji, attr) config.private_chan_category_name except ready_check.NotReadyError as e: raise AssertionError from e config.bot.change_presence.assert_called_once() config.bot.reset_mock() mock_discord._unprepare_attributes(config.Role) mock_discord._unprepare_attributes(config.Channel) mock_discord._unprepare_attributes(config.Emoji) # guild found, missing @MJ / #logs def _channel(name): if name == "logs": raise ValueError else: return mock.NonCallableMock(discord.TextChannel) def _role(name): return mock.NonCallableMock(discord.Role) def _emoji(name): return mock.NonCallableMock(discord.Emoji) ch_patch.side_effect = _channel role_patch.side_effect = _role emo_patch.side_effect = _emoji defchan = mock.NonCallableMock(discord.TextChannel) config.guild.text_channels.__getitem__.return_value = defchan await _on_ready(config.bot) guild = config.bot.get_guild.return_value self.assertEqual(config.loop, config.bot.loop) config.bot.i_am_alive.assert_not_called() config.bot.get_guild.assert_called_once_with(config.bot.GUILD_ID) self.assertEqual(config.guild, guild) printed = "\n".join(call.args[0] for call in ppatch.call_args_list) self.assertIn("Connected", printed) self.assertIn(str(guild.name), printed) self.assertIn("Initialization", printed) self.assertIn("Initialization complete", printed) self.assertIn("Listening for events", printed) mock_discord.assert_sent( defchan, ["ERREURS", "1 error", 'config.Channel.logs = "logs"', "Routing logs", str(config.Role.mj.mention)], "Just rebooted") ppatch.reset_mock() try: for attr in config.Channel: if attr != "logs": getattr(config.Channel, attr) for attr in config.Role: getattr(config.Role, attr) for attr in config.Emoji: getattr(config.Emoji, attr) config.private_chan_category_name except ready_check.NotReadyError as e: raise AssertionError from e config.bot.change_presence.assert_called_once() config.bot.reset_mock() mock_discord._unprepare_attributes(config.Role) mock_discord._unprepare_attributes(config.Channel) mock_discord._unprepare_attributes(config.Emoji) # guild found, missing @MJ / #logs def _channel(name): return mock.NonCallableMock(discord.TextChannel) def _role(name): return mock.NonCallableMock(discord.Role) def _emoji(name): return mock.NonCallableMock(discord.Emoji) taches = [ bdd.Tache(timestamp=datetime.datetime.now(), commande="cmdz"), bdd.Tache(timestamp=datetime.datetime.now(), commande="cmd2"), bdd.Tache(timestamp=datetime.datetime.now(), commande="cmd3"), ] bdd.Tache.add(*taches) ch_patch.side_effect = _channel role_patch.side_effect = _role emo_patch.side_effect = _emoji await _on_ready(config.bot) guild = config.bot.get_guild.return_value self.assertEqual(config.loop, config.bot.loop) config.bot.i_am_alive.assert_not_called() config.bot.get_guild.assert_called_once_with(config.bot.GUILD_ID) self.assertEqual(config.guild, guild) printed = "\n".join(call.args[0] for call in ppatch.call_args_list) self.assertIn("Connected", printed) self.assertIn(str(guild.name), printed) self.assertIn("Initialization", printed) self.assertIn("Initialization complete", printed) self.assertIn("Listening for events", printed) mock_discord.assert_sent(config.Channel.logs, "Just rebooted", "3 tâches planifiées") ppatch.reset_mock() try: for attr in config.Channel: if attr != "logs": getattr(config.Channel, attr) for attr in config.Role: getattr(config.Role, attr) for attr in config.Emoji: getattr(config.Emoji, attr) config.private_chan_category_name except ready_check.NotReadyError as e: raise AssertionError from e config.bot.change_presence.assert_called_once() config.loop.call_later.assert_has_calls( [mock.call(mock.ANY, tache.execute) for tache in taches] )
async def test_close_action(self, da_patch): """Unit tests for gestion_actions.close_action function.""" # async def close_action(action) close_action = gestion_actions.close_action mock_bdd.add_campsroles() j1 = bdd.Joueur(discord_id=1, chan_id_=11, nom="Joueur1") j1.add() # pas de décision, no base_cooldown, no temporel/perma ba1 = bdd.BaseAction(slug="ba1", instant=False, base_cooldown=0, trigger_debut=bdd.ActionTrigger.open_cond) ba1.add() act1 = bdd.Action(base=ba1, joueur=j1, decision_="rien") act1.add() await close_action(act1) self.assertIsNone(act1.decision_) self.assertEqual(bdd.Tache.query.all(), []) da_patch.assert_not_called() # pas de décision, base_cooldown = 4, no temporel/perma ba2 = bdd.BaseAction(slug="ba2", instant=False, base_cooldown=4, trigger_debut=bdd.ActionTrigger.open_cond) ba2.add() act2 = bdd.Action(base=ba2, joueur=j1, cooldown=0, decision_="rien") act2.add() await close_action(act2) self.assertIsNone(act2.decision_) self.assertEqual(act2.cooldown, 4) self.assertEqual(bdd.Tache.query.all(), []) da_patch.assert_not_called() # pas de décision, no base_cooldown, temporel ba3 = bdd.BaseAction(slug="ba3", instant=False, base_cooldown=0, trigger_debut=bdd.ActionTrigger.temporel, heure_debut=datetime.time(15, 2)) ba3.add() act3 = bdd.Action(id=3, base=ba3, joueur=j1, decision_="rien") act3.add() with mock.patch("lgrez.blocs.tools.next_occurence") as no_patch: no_patch.return_value = datetime.datetime(1, 1, 1, 15, 2) await close_action(act3) no_patch.assert_called_once_with(datetime.time(15, 2)) self.assertIsNone(act3.decision_) self.assertEqual(len(bdd.Tache.query.all()), 1) tache = bdd.Tache.query.one() self.assertEqual(tache.timestamp, no_patch.return_value) self.assertEqual(tache.commande, "!open 3") self.assertEqual(tache.action, act3) tache.delete() da_patch.assert_not_called() # pas de décision, no base_cooldown, perma ba4 = bdd.BaseAction(slug="ba4", instant=False, base_cooldown=0, trigger_debut=bdd.ActionTrigger.perma) ba4.add() act4 = bdd.Action(id=4, base=ba4, joueur=j1, decision_="rien") act4.add() with mock.patch("lgrez.blocs.tools.fin_pause") as fp_patch: fp_patch.return_value = datetime.datetime(1, 1, 1, 10, 4) await close_action(act4) fp_patch.assert_called_once() self.assertIsNone(act4.decision_) self.assertEqual(len(bdd.Tache.query.all()), 1) tache = bdd.Tache.query.one() self.assertEqual(tache.timestamp, fp_patch.return_value) self.assertEqual(tache.commande, "!open 4") self.assertEqual(tache.action, act4) tache.delete() da_patch.assert_not_called() # décision, no base_cooldown, no temporel/perma, no charges ==> no diff act11 = bdd.Action(base=ba1, joueur=j1, decision_="ach ja", charges=None) act11.add() await close_action(act11) self.assertIsNone(act11.decision_) self.assertIsNone(act11.charges) self.assertEqual(bdd.Tache.query.all(), []) da_patch.assert_not_called() # décision, no base_cooldown, no temporel/perma, 4 charges act12 = bdd.Action(base=ba1, joueur=j1, decision_="ach ja", charges=4) act12.add() with mock_discord.mock_members_and_chans(j1): chan = j1.private_chan await close_action(act12) self.assertIsNone(act12.decision_) self.assertEqual(act12.charges, 3) mock_discord.assert_sent(chan, "Il te reste 3 charge") mock_discord.assert_not_sent(chan, "pour cette semaine") self.assertEqual(bdd.Tache.query.all(), []) da_patch.assert_not_called() # décision, no base_cooldown, no temporel/perma, 4 charges, refill WE ba1b = bdd.BaseAction(slug="ba1b", instant=False, base_cooldown=0, trigger_debut=bdd.ActionTrigger.open_cond, refill="weekends, other") ba1b.add() act13 = bdd.Action(base=ba1b, joueur=j1, decision_="ach ja", charges=4) act13.add() with mock_discord.mock_members_and_chans(j1): chan = j1.private_chan await close_action(act13) self.assertIsNone(act13.decision_) self.assertEqual(act13.charges, 3) mock_discord.assert_sent(chan, "Il te reste 3 charge") mock_discord.assert_sent(chan, "pour cette semaine") self.assertEqual(bdd.Tache.query.all(), []) da_patch.assert_not_called() # décision, no base_cooldown, no temporel/perma, 1 charge act14 = bdd.Action(id=37, base=ba1, joueur=j1, decision_="ach ja", charges=1) act14.add() with mock_discord.mock_members_and_chans(j1): chan = j1.private_chan await close_action(act14) da_patch.assert_called_once_with(act14) # deleted mock_discord.assert_sent(chan, "Il te reste 0 charge") mock_discord.assert_not_sent(chan, "pour cette semaine") self.assertEqual(bdd.Tache.query.all(), []) da_patch.reset_mock() # décision, no base_cooldown, no temporel/perma, 1 charge, refill WE act13 = bdd.Action(base=ba1b, joueur=j1, decision_="ach ja", charges=1) act13.add() with mock_discord.mock_members_and_chans(j1): chan = j1.private_chan await close_action(act13) self.assertIsNone(act13.decision_) self.assertEqual(act13.charges, 0) # not deleted mock_discord.assert_sent(chan, "Il te reste 0 charge") mock_discord.assert_sent(chan, "pour cette semaine") self.assertEqual(bdd.Tache.query.all(), []) da_patch.assert_not_called() # décision, no base_cooldown, no temporel/perma, 1 charge, refill autre ba1c = bdd.BaseAction(slug="ba1c", instant=False, base_cooldown=0, trigger_debut=bdd.ActionTrigger.open_cond, refill="brzzz") ba1c.add() act13 = bdd.Action(base=ba1c, joueur=j1, decision_="ach ja", charges=1) act13.add() with mock_discord.mock_members_and_chans(j1): chan = j1.private_chan await close_action(act13) self.assertIsNone(act13.decision_) self.assertEqual(act13.charges, 0) # not deleted mock_discord.assert_sent(chan, "Il te reste 0 charge") mock_discord.assert_not_sent(chan, "pour cette semaine") self.assertEqual(bdd.Tache.query.all(), []) da_patch.assert_not_called() # deleted et plein d'autre trucs batro = bdd.BaseAction(slug="batro", instant=False, base_cooldown=2, trigger_debut=bdd.ActionTrigger.perma, refill="brzzz") act14 = bdd.Action(base=ba1, joueur=j1, decision_="ach ja", charges=1) act14.add() with mock_discord.mock_members_and_chans(j1): chan = j1.private_chan await close_action(act14) da_patch.assert_called_once_with(act14) # deleted mock_discord.assert_sent(chan, "Il te reste 0 charge") mock_discord.assert_not_sent(chan, "pour cette semaine") self.assertEqual(bdd.Tache.query.all(), []) da_patch.reset_mock()
async def test_open_action(self, log_patch, ca_patch): """Unit tests for gestion_actions.open_action function.""" # async def open_action(action) open_action = gestion_actions.open_action mock_bdd.add_campsroles() j1 = bdd.Joueur(discord_id=1, chan_id_=11, nom="Joueur1", role_actif=True) j1.add() # test préliminaire 1 - en cooldown, non temporel ba1 = bdd.BaseAction(slug="ba1") ba1.add() act1 = bdd.Action(base=ba1, joueur=j1, cooldown=3) act1.add() with mock_discord.mock_members_and_chans(j1): await open_action(act1) self.assertEqual(act1.cooldown, 2) log_patch.assert_called_once() self.assertIn(repr(act1), log_patch.call_args.args[0]) self.assertIn("en cooldown", log_patch.call_args.args[0]) self.assertEqual(bdd.Tache.query.all(), []) ca_patch.assert_not_called() log_patch.reset_mock() # test préliminaire 2 - en cooldown, temporel ba2 = bdd.BaseAction(slug="ba2", trigger_debut=bdd.ActionTrigger.temporel, heure_debut=datetime.time(15, 2)) ba2.add() act2 = bdd.Action(id=23, base=ba2, joueur=j1, cooldown=3) act2.add() with mock_discord.mock_members_and_chans(j1): await open_action(act2) self.assertEqual(act2.cooldown, 2) log_patch.assert_called_once() self.assertIn(repr(act2), log_patch.call_args.args[0]) self.assertIn("en cooldown", log_patch.call_args.args[0]) self.assertEqual(len(bdd.Tache.query.all()), 1) tache = bdd.Tache.query.one() self.assertEqual(tache.timestamp.time(), datetime.time(15, 2)) self.assertEqual(tache.commande, "!open 23") self.assertEqual(tache.action, act2) log_patch.reset_mock() ca_patch.assert_not_called() tache.delete() # test préliminaire 3 - role non actif, non temporel j2 = bdd.Joueur(discord_id=2, chan_id_=21, nom="Joueur2", role_actif=False) j2.add() act3 = bdd.Action(id=24, base=ba1, joueur=j2, cooldown=0) act3.add() with mock_discord.mock_members_and_chans(j2): await open_action(act3) self.assertEqual(act3.cooldown, 0) log_patch.assert_called_once() self.assertIn(repr(act3), log_patch.call_args.args[0]) self.assertIn("role_actif == False", log_patch.call_args.args[0]) self.assertEqual(bdd.Tache.query.all(), []) ca_patch.assert_not_called() log_patch.reset_mock() # test préliminaire 4 - role non actif, temporel act4 = bdd.Action(id=25, base=ba2, joueur=j2, cooldown=0) act4.add() with mock_discord.mock_members_and_chans(j2): await open_action(act4) self.assertEqual(act4.cooldown, 0) log_patch.assert_called_once() self.assertIn(repr(act4), log_patch.call_args.args[0]) self.assertIn("role_actif == False", log_patch.call_args.args[0]) self.assertEqual(len(bdd.Tache.query.all()), 1) tache = bdd.Tache.query.one() self.assertEqual(tache.timestamp.time(), datetime.time(15, 2)) self.assertEqual(tache.commande, "!open 25") self.assertEqual(tache.action, act4) log_patch.reset_mock() ca_patch.assert_not_called() tache.delete() # test préliminaire 5 - action automatique, non temporelle ba3 = bdd.BaseAction(slug="ba3", trigger_debut=bdd.ActionTrigger.perma, trigger_fin=bdd.ActionTrigger.auto) ba3.add() act5 = bdd.Action(id=27, base=ba3, joueur=j1, cooldown=0) act5.add() with mock_discord.mock_members_and_chans(j1): await open_action(act5) self.assertEqual(act5.cooldown, 0) log_patch.assert_called_once() self.assertIn(repr(act5), log_patch.call_args.args[0]) self.assertIn("automatique", log_patch.call_args.args[0]) self.assertEqual(bdd.Tache.query.all(), []) ca_patch.assert_called_once_with(act5) log_patch.reset_mock() ca_patch.reset_mock() # test préliminaire 6 - action automatique, temporelle ba4 = bdd.BaseAction(slug="ba4", trigger_debut=bdd.ActionTrigger.temporel, heure_debut=datetime.time(15, 2), trigger_fin=bdd.ActionTrigger.auto) ba4.add() act6 = bdd.Action(id=28, base=ba4, joueur=j1, cooldown=0) act6.add() with mock_discord.mock_members_and_chans(j1): chan = j1.private_chan await open_action(act6) self.assertEqual(act6.cooldown, 0) log_patch.assert_called_once() self.assertIn("ba4", log_patch.call_args.args[0]) self.assertIn("Joueur1", log_patch.call_args.args[0]) self.assertIn("pas vraiment automatique", log_patch.call_args.args[0]) self.assertIn(str(config.Role.mj.mention), log_patch.call_args.args[0]) self.assertIn(str(chan.mention), log_patch.call_args.args[0]) self.assertEqual(bdd.Tache.query.all(), []) ca_patch.assert_called_once_with(act6) log_patch.reset_mock() ca_patch.reset_mock() # --- fin des tests préliminaires # fin hors temp/delta/perma, déjà ouverte ba5 = bdd.BaseAction(slug="ba5", trigger_debut=bdd.ActionTrigger.open_cond, trigger_fin=bdd.ActionTrigger.close_cond) ba5.add() act7 = bdd.Action(base=ba5, joueur=j1, decision_="rien") act7.add() with mock_discord.mock_members_and_chans(j1): chan = j1.private_chan await open_action(act7) mock_discord.assert_sent(chan, [ "tu peux utiliser quand tu le souhaites", "ba5", "!action", ]) mock_discord.assert_not_sent(chan, "tu as jusqu'à") self.assertEqual(act7.decision_, "rien") chan.send.return_value.add_reaction.assert_called_once_with( config.Emoji.action ) self.assertEqual(bdd.Tache.query.all(), []) log_patch.assert_not_called() ca_patch.assert_not_called() # fin hors temp/delta/perma, fermée ba6 = bdd.BaseAction(slug="ba6", trigger_debut=bdd.ActionTrigger.open_cond, trigger_fin=bdd.ActionTrigger.close_cond) ba6.add() act8 = bdd.Action(id=30, base=ba6, joueur=j1, decision_=None) act8.add() with mock_discord.mock_members_and_chans(j1): chan = j1.private_chan await open_action(act8) mock_discord.assert_sent(chan, [ "Tu peux maintenant utiliser", "ba6", "!action", ]) mock_discord.assert_not_sent(chan, "tu as jusqu'à") chan.send.return_value.add_reaction.assert_called_once_with( config.Emoji.action ) self.assertEqual(act8.decision_, "rien") self.assertEqual(bdd.Tache.query.all(), []) log_patch.assert_not_called() ca_patch.assert_not_called() # fin temp, déjà ouverte ba7 = bdd.BaseAction(slug="ba7", trigger_debut=bdd.ActionTrigger.open_cond, trigger_fin=bdd.ActionTrigger.temporel, heure_fin=datetime.time(15, 2)) ba7.add() act9 = bdd.Action(id=31, base=ba7, joueur=j1, decision_="rien") act9.add() with mock_discord.mock_members_and_chans(j1): chan = j1.private_chan await open_action(act9) mock_discord.assert_sent(chan, [ "tu peux utiliser quand tu le souhaites", "ba7", "!action", f"Tu as jusqu'à {datetime.time(15, 2)}" ]) chan.send.return_value.add_reaction.assert_called_once_with( config.Emoji.action ) self.assertEqual(act9.decision_, "rien") taches = bdd.Tache.query.all() self.assertEqual(len(taches), 2) self.assertEqual([tache.action for tache in taches], [act9]*2) self.assertEqual( {(tache.commande, tache.timestamp.time()) for tache in taches}, {("!close 31", datetime.time(15, 2)), ("!remind 31", datetime.time(14, 32))} ) bdd.Tache.delete(*taches) log_patch.assert_not_called() ca_patch.assert_not_called() # fin temp, fermée ba8 = bdd.BaseAction(slug="ba8", trigger_debut=bdd.ActionTrigger.open_cond, trigger_fin=bdd.ActionTrigger.temporel, heure_fin=datetime.time(15, 2)) ba8.add() act10 = bdd.Action(id=32, base=ba8, joueur=j1, decision_=None) act10.add() with mock_discord.mock_members_and_chans(j1): chan = j1.private_chan await open_action(act10) mock_discord.assert_sent(chan, [ "Tu peux maintenant utiliser", "ba8", "!action", f"Tu as jusqu'à {datetime.time(15, 2)}" ]) self.assertEqual(act10.decision_, "rien") chan.send.return_value.add_reaction.assert_called_once_with( config.Emoji.action ) taches = bdd.Tache.query.all() self.assertEqual(len(taches), 2) self.assertEqual([tache.action for tache in taches], [act10]*2) self.assertEqual( {(tache.commande, tache.timestamp.time()) for tache in taches}, {("!close 32", datetime.time(15, 2)), ("!remind 32", datetime.time(14, 32))} ) bdd.Tache.delete(*taches) log_patch.assert_not_called() ca_patch.assert_not_called() # fin delta (fermée) ba9 = bdd.BaseAction(slug="ba9", trigger_debut=bdd.ActionTrigger.open_cond, trigger_fin=bdd.ActionTrigger.delta, heure_fin=datetime.time(1, 10, 7)) ba9.add() act11 = bdd.Action(id=33, base=ba9, joueur=j1, decision_=None) act11.add() with mock_discord.mock_members_and_chans(j1): chan = j1.private_chan with freezegun.freeze_time(datetime.datetime(1, 1, 1, 16, 28, 4)): await open_action(act11) mock_discord.assert_sent(chan, [ "Tu peux maintenant utiliser", "ba9", "!action", f"Tu as jusqu'à {datetime.time(17, 38, 11)}" ]) self.assertEqual(act11.decision_, "rien") chan.send.return_value.add_reaction.assert_called_once_with( config.Emoji.action ) taches = bdd.Tache.query.all() self.assertEqual(len(taches), 2) self.assertEqual([tache.action for tache in taches], [act11]*2) self.assertEqual( {(tache.commande, tache.timestamp.time()) for tache in taches}, {("!close 33", datetime.time(17, 38, 11)), ("!remind 33", datetime.time(17, 8, 11))} ) bdd.Tache.delete(*taches) log_patch.assert_not_called() ca_patch.assert_not_called() # fin perma (fermée) - WE d'abord ba10 = bdd.BaseAction(slug="ba10", trigger_debut=bdd.ActionTrigger.open_cond, trigger_fin=bdd.ActionTrigger.perma) ba10.add() act12 = bdd.Action(id=34, base=ba10, joueur=j1, decision_=None) act12.add() with mock.patch("lgrez.blocs.tools.next_occurence", return_value=datetime.datetime(1, 1, 1, 16, 28, 4)), \ mock.patch("lgrez.blocs.tools.debut_pause", return_value=datetime.datetime(1, 1, 1, 15, 28, 4)), \ mock_discord.mock_members_and_chans(j1): chan = j1.private_chan await open_action(act12) mock_discord.assert_sent(chan, [ "Tu peux maintenant utiliser", "ba10", "!action", ]) self.assertEqual(act12.decision_, "rien") mock_discord.assert_not_sent(chan, "Tu as jusqu'à",) chan.send.return_value.add_reaction.assert_called_once_with( config.Emoji.action ) self.assertEqual(len(bdd.Tache.query.all()), 1) tache = bdd.Tache.query.one() self.assertEqual(tache.action, act12) self.assertEqual(tache.commande, "!close 34") self.assertEqual(tache.timestamp.time(), datetime.time(15, 28, 4)) tache.delete() log_patch.assert_not_called() ca_patch.assert_not_called() # fin perma (fermée) - prochaine ouverture d'abord ba11 = bdd.BaseAction(slug="ba11", trigger_debut=bdd.ActionTrigger.open_cond, trigger_fin=bdd.ActionTrigger.perma) ba11.add() act13 = bdd.Action(id=35, base=ba11, joueur=j1, decision_=None) act13.add() with mock.patch("lgrez.blocs.tools.next_occurence", return_value=datetime.datetime(1, 1, 1, 16, 28, 4)), \ mock.patch("lgrez.blocs.tools.debut_pause", return_value=datetime.datetime(1, 1, 1, 17, 28, 4)), \ mock_discord.mock_members_and_chans(j1): chan = j1.private_chan await open_action(act13) mock_discord.assert_sent(chan, [ "Tu peux maintenant utiliser", "ba11", "!action", ]) self.assertEqual(act13.decision_, "rien") mock_discord.assert_not_sent(chan, "Tu as jusqu'à",) chan.send.return_value.add_reaction.assert_called_once_with( config.Emoji.action ) self.assertEqual(len(bdd.Tache.query.all()), 1) tache = bdd.Tache.query.one() self.assertEqual(tache.action, act13) self.assertEqual(tache.commande, "!open 35") self.assertEqual(tache.timestamp.time(), datetime.time(16, 28, 4)) tache.delete() log_patch.assert_not_called() ca_patch.assert_not_called()
async def test_main(self, sleep_patch, reg_patch, newchan_patch): """Unit tests for inscription.main function.""" # async def main(member) main = inscription.main mock_bdd.add_campsroles() joueur1 = bdd.Joueur(discord_id=1, chan_id_=11, nom="Joueur 1") joueur1.add() newchan_patch.return_value = mock_discord.chan("bzzt", id=798) # Joueur inscrit en base with mock_discord.mock_members_and_chans(joueur1): member = joueur1.member chan = joueur1.private_chan await main(member) chan.set_permissions.assert_called_once_with(member, read_messages=True, send_messages=True) mock_discord.assert_sent(chan, f"{member.mention} tu es déjà inscrit") reg_patch.assert_not_called() newchan_patch.assert_not_called() sleep_patch.assert_not_called() joueur1.delete() # Joueur en cours d'inscription -> abort chan = mock_discord.chan("bzz", topic="123456") config.guild.text_channels = [chan] member = mock.Mock(discord.Member, id=123456) with mock_discord.interact(("yes_no", False)): await main(member) chan.set_permissions.assert_called_once_with(member, read_messages=True, send_messages=True) mock_discord.assert_sent(chan, f"{member.mention}, par ici", f"Bienvenue {member.mention}", f"finalisons ton inscription", f"C'est bon pour toi ?", "Pas de soucis") reg_patch.assert_not_called() newchan_patch.assert_not_called() sleep_patch.assert_called() sleep_patch.reset_mock() # Joueur arrivant -> abort member = mock.Mock(discord.Member, id=145) with mock_discord.interact(("yes_no", False)): await main(member) newchan_patch.assert_called_once_with(member) chan = newchan_patch.return_value mock_discord.assert_sent(chan, f"Bienvenue {member.mention}", f"finalisons ton inscription", f"C'est bon pour toi ?", "Pas de soucis") reg_patch.assert_not_called() newchan_patch.reset_mock() sleep_patch.assert_called() sleep_patch.reset_mock() # Joueur arrivant -> ok -> name -> troll -> good name # demande_chambre False config.demande_chambre = False member = mock.Mock(discord.Member, id=145) member.top_role.__lt__ = lambda s, o: True # role < MJ member.display_name = "Pr-Z N0 N" with mock_discord.interact( ("yes_no", True), ("wait_for_message", mock.NonCallableMock(discord.Message, content="préz")), ("wait_for_message", mock.NonCallableMock(discord.Message, content="no n")), ("yes_no", False), ("wait_for_message", mock.NonCallableMock(discord.Message, content="pr-z")), ("wait_for_message", mock.NonCallableMock(discord.Message, content="n0 n")), ("yes_no", True), ): await main(member) newchan_patch.assert_called_once_with(member) chan = newchan_patch.return_value mock_discord.assert_sent( chan, f"Bienvenue {member.mention}", "finalisons ton inscription", f"C'est bon pour toi ?", ["Parfait", "prénom"], "prénom", "nom de famille", "Préz No N", "prénom", "nom de famille", "Pr-Z N0 N", "Je t'ai renommé", "Je t'inscris", "Tu es maintenant inscrit", "quelques dernières choses", "c'est tout bon") chan.edit.assert_any_call( name=f"{config.private_chan_prefix}Pr-Z N0 N") member.edit.assert_called_once_with(nick="Pr-Z N0 N") member.edit.reset_mock() self.assertEqual(len(bdd.Joueur.query.all()), 1) jr = bdd.Joueur.query.one() self.assertEqual([ jr.discord_id, jr.chan_id_, jr.nom, jr.chambre, jr.statut, jr.role, jr.camp, jr.votant_village, jr.votant_loups, jr.role_actif ], [ 145, 798, "Pr-Z N0 N", None, bdd.Statut.vivant, bdd.Role.default(), bdd.Camp.default(), True, False, False ]) member.add_roles.assert_called_once_with(config.Role.joueur_en_vie) chan.edit.assert_any_call(topic=mock.ANY) reg_patch.assert_called_once_with(jr) reg_patch.reset_mock() newchan_patch.reset_mock() sleep_patch.assert_called() sleep_patch.reset_mock() jr.delete() # Joueur arrivant -> ok -> name -> chambre -> pas à la Rez config.demande_chambre = True member = mock.Mock(discord.Member, id=145) member.top_role.__lt__ = lambda s, o: True # role < MJ member.display_name = "Pr-Z N0 N" with mock_discord.interact( ("yes_no", True), ("wait_for_message", mock.NonCallableMock(discord.Message, content="pr-z")), ("wait_for_message", mock.NonCallableMock(discord.Message, content="n0 n")), ("yes_no", True), ("yes_no", False), ): await main(member) newchan_patch.assert_called_once_with(member) chan = newchan_patch.return_value mock_discord.assert_sent( chan, f"Bienvenue {member.mention}", "finalisons ton inscription", f"C'est bon pour toi ?", ["Parfait", "prénom"], "prénom", "nom de famille", "Pr-Z N0 N", "Je t'ai renommé", "habites-tu à la Rez", "Je t'inscris", "Tu es maintenant inscrit", "quelques dernières choses", "c'est tout bon") chan.edit.assert_any_call( name=f"{config.private_chan_prefix}Pr-Z N0 N") member.edit.assert_called_once_with(nick="Pr-Z N0 N") member.edit.reset_mock() self.assertEqual(len(bdd.Joueur.query.all()), 1) jr = bdd.Joueur.query.one() self.assertEqual([ jr.discord_id, jr.chan_id_, jr.nom, jr.chambre, jr.statut, jr.role, jr.camp, jr.votant_village, jr.votant_loups, jr.role_actif ], [ 145, 798, "Pr-Z N0 N", config.chambre_mj, bdd.Statut.vivant, bdd.Role.default(), bdd.Camp.default(), True, False, False ]) member.add_roles.assert_called_once_with(config.Role.joueur_en_vie) chan.edit.assert_any_call(topic=mock.ANY) reg_patch.assert_called_once_with(jr) reg_patch.reset_mock() newchan_patch.reset_mock() sleep_patch.assert_called() sleep_patch.reset_mock() jr.delete() # Joueur arrivant -> ok -> name -> chambre -> à la Rez config.demande_chambre = True member = mock.Mock(discord.Member, id=145) member.top_role.__lt__ = lambda s, o: True # role < MJ member.display_name = "Pr-Z N0 N" with mock_discord.interact( ("yes_no", True), ("wait_for_message", mock.NonCallableMock(discord.Message, content="pr-z")), ("wait_for_message", mock.NonCallableMock(discord.Message, content="n0 n")), ("yes_no", True), ("yes_no", True), ("wait_for_message", mock.NonCallableMock(discord.Message, content="214")), ): await main(member) newchan_patch.assert_called_once_with(member) chan = newchan_patch.return_value mock_discord.assert_sent( chan, f"Bienvenue {member.mention}", "finalisons ton inscription", f"C'est bon pour toi ?", ["Parfait", "prénom"], "prénom", "nom de famille", "Pr-Z N0 N", "Je t'ai renommé", "habites-tu à la Rez", "quelle est ta chambre", "Je t'inscris", "Tu es maintenant inscrit", "quelques dernières choses", "c'est tout bon") chan.edit.assert_any_call( name=f"{config.private_chan_prefix}Pr-Z N0 N") member.edit.assert_called_once_with(nick="Pr-Z N0 N") member.edit.reset_mock() self.assertEqual(len(bdd.Joueur.query.all()), 1) jr = bdd.Joueur.query.one() self.assertEqual([ jr.discord_id, jr.chan_id_, jr.nom, jr.chambre, jr.statut, jr.role, jr.camp, jr.votant_village, jr.votant_loups, jr.role_actif ], [ 145, 798, "Pr-Z N0 N", "214", bdd.Statut.vivant, bdd.Role.default(), bdd.Camp.default(), True, False, False ]) member.add_roles.assert_called_once_with(config.Role.joueur_en_vie) chan.edit.assert_any_call(topic=mock.ANY) reg_patch.assert_called_once_with(jr) reg_patch.reset_mock() newchan_patch.reset_mock() sleep_patch.assert_called() sleep_patch.reset_mock() jr.delete()