From 1d746db2ddae5d27f592f332d0f80f776f30bb60 Mon Sep 17 00:00:00 2001 From: Ben Longden Date: Mon, 19 Aug 2024 14:18:48 +0100 Subject: [PATCH 1/2] Check msg from at_pre_cmd It's possible to display a msg from at_pre_cmd but it's not possible to test it. Rather than return when at_pre_cmd returns True, the handler should still run the msg checks is they're present. --- evennia/utils/test_resources.py | 46 +++++++++++++++------------------ 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/evennia/utils/test_resources.py b/evennia/utils/test_resources.py index 9aee64842a..dfd7c2ec88 100644 --- a/evennia/utils/test_resources.py +++ b/evennia/utils/test_resources.py @@ -433,7 +433,6 @@ class EvenniaCommandTestMixin: cmdobj.raw_string = raw_string if raw_string is not None else cmdobj.key + " " + input_args cmdobj.obj = obj or (caller if caller else self.char1) inputs = inputs or [] - # set up receivers receiver_mapping = {} if isinstance(msg, dict): @@ -453,37 +452,34 @@ class EvenniaCommandTestMixin: unmocked_msg_methods[receiver] = receiver.msg # replace normal `.msg` with a mock receiver.msg = Mock() - # Run the methods of the Command. This mimics what happens in the # cmdhandler. This will have the mocked .msg be called as part of the # execution. Mocks remembers what was sent to them so we will be able # to retrieve what was sent later. try: - if cmdobj.at_pre_cmd(): - return - cmdobj.parse() - ret = cmdobj.func() - - # handle func's with yield in them (making them generators) - if isinstance(ret, types.GeneratorType): - while True: - try: - inp = inputs.pop() if inputs else None - if inp: - try: - # this mimics a user's reply to a prompt - ret.send(inp) - except TypeError: + if not cmdobj.at_pre_cmd(): + cmdobj.parse() + ret = cmdobj.func() + # handle func's with yield in them (making them generators) + if isinstance(ret, types.GeneratorType): + while True: + try: + inp = inputs.pop() if inputs else None + if inp: + try: + # this mimics a user's reply to a prompt + ret.send(inp) + except TypeError: + next(ret) + ret = ret.send(inp) + else: + # non-input yield, like yield(10). We don't pause + # but fire it immediately. next(ret) - ret = ret.send(inp) - else: - # non-input yield, like yield(10). We don't pause - # but fire it immediately. - next(ret) - except StopIteration: - break + except StopIteration: + break - cmdobj.at_post_cmd() + cmdobj.at_post_cmd() except StopIteration: pass except InterruptCommand: From 8501c478a2bc9dbc89df522f58ed3de063011106 Mon Sep 17 00:00:00 2001 From: Ben Longden Date: Tue, 2 Sep 2025 16:28:41 +0100 Subject: [PATCH 2/2] Include execute_cmd in if statement, and add test --- evennia/commands/default/tests.py | 13 +++++++++++++ evennia/utils/test_resources.py | 23 ++++++++++++----------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/evennia/commands/default/tests.py b/evennia/commands/default/tests.py index 852e4c6b2f..8ab5fa50bb 100644 --- a/evennia/commands/default/tests.py +++ b/evennia/commands/default/tests.py @@ -2263,3 +2263,16 @@ class TestSystemCommands(BaseEvenniaCommandTest): multimatch.matches = matches self.call(multimatch, "look", "") + +class TestPreCmdOutputTestable(BaseEvenniaCommandTest): + def test_pre_cmd(self): + class CmdTest(Command): + def at_pre_cmd(self): + self.msg("This should be testable") + return True + + def func(self): + self.msg("This should never be executed") + return + + self.call(CmdTest(), "test", "This should be testable") \ No newline at end of file diff --git a/evennia/utils/test_resources.py b/evennia/utils/test_resources.py index dfd7c2ec88..e351367cad 100644 --- a/evennia/utils/test_resources.py +++ b/evennia/utils/test_resources.py @@ -452,12 +452,13 @@ class EvenniaCommandTestMixin: unmocked_msg_methods[receiver] = receiver.msg # replace normal `.msg` with a mock receiver.msg = Mock() + # Run the methods of the Command. This mimics what happens in the # cmdhandler. This will have the mocked .msg be called as part of the # execution. Mocks remembers what was sent to them so we will be able # to retrieve what was sent later. - try: - if not cmdobj.at_pre_cmd(): + if not cmdobj.at_pre_cmd(): + try: cmdobj.parse() ret = cmdobj.func() # handle func's with yield in them (making them generators) @@ -480,16 +481,16 @@ class EvenniaCommandTestMixin: break cmdobj.at_post_cmd() - except StopIteration: - pass - except InterruptCommand: - pass + except StopIteration: + pass + except InterruptCommand: + pass - for inp in inputs: - # if there are any inputs left, we may have a non-generator - # input to handle (get_input/ask_yes_no that uses a separate - # cmdset rather than a yield - caller.execute_cmd(inp) + for inp in inputs: + # if there are any inputs left, we may have a non-generator + # input to handle (get_input/ask_yes_no that uses a separate + # cmdset rather than a yield + caller.execute_cmd(inp) # At this point the mocked .msg methods on each receiver will have # stored all calls made to them (that's a basic function of the Mock