Add testing framework for EvMenu. Implements #1484
This commit is contained in:
parent
b6b112b70a
commit
d05495cc52
2 changed files with 205 additions and 8 deletions
|
|
@ -429,8 +429,13 @@ class EvMenu(object):
|
|||
self.nodetext = None
|
||||
self.helptext = None
|
||||
self.options = None
|
||||
self.nodename = None
|
||||
self.node_kwargs = {}
|
||||
|
||||
# used for testing
|
||||
self.test_options = {}
|
||||
self.test_nodetext = ""
|
||||
|
||||
# assign kwargs as initialization vars on ourselves.
|
||||
if set(("_startnode", "_menutree", "_session", "_persistent",
|
||||
"cmd_on_exit", "default", "nodetext", "helptext",
|
||||
|
|
@ -605,6 +610,11 @@ class EvMenu(object):
|
|||
except Exception:
|
||||
self.caller.msg(_ERR_GENERAL.format(nodename=nodename), session=self._session)
|
||||
raise
|
||||
|
||||
# store options to make them easier to test
|
||||
self.test_options = options
|
||||
self.test_nodetext = nodetext
|
||||
|
||||
return nodetext, options
|
||||
|
||||
def run_exec(self, nodename, raw_string, **kwargs):
|
||||
|
|
@ -750,6 +760,8 @@ class EvMenu(object):
|
|||
(goto, goto_kwargs, execute, exec_kwargs)
|
||||
|
||||
self.nodetext = self._format_node(nodetext, display_options)
|
||||
self.node_kwargs = kwargs
|
||||
self.nodename = nodename
|
||||
|
||||
# handle the helptext
|
||||
if helptext:
|
||||
|
|
@ -815,7 +827,7 @@ class EvMenu(object):
|
|||
should also report errors directly to the user.
|
||||
|
||||
"""
|
||||
cmd = raw_string.strip().lower()
|
||||
cmd = strip_ansi(raw_string.strip().lower())
|
||||
|
||||
if cmd in self.options:
|
||||
# this will take precedence over the default commands
|
||||
|
|
@ -1124,7 +1136,7 @@ def test_start_node(caller):
|
|||
|
||||
|
||||
def test_look_node(caller):
|
||||
text = ""
|
||||
text = "This is a custom look location!"
|
||||
options = {"key": ("|yL|nook", "l"),
|
||||
"desc": "Go back to the previous menu.",
|
||||
"goto": "test_start_node"}
|
||||
|
|
|
|||
|
|
@ -5,20 +5,205 @@ TODO: This need expansion.
|
|||
|
||||
"""
|
||||
|
||||
import copy
|
||||
from django.test import TestCase
|
||||
from evennia.utils import evmenu
|
||||
from mock import Mock
|
||||
from evennia.utils import ansi
|
||||
from mock import MagicMock
|
||||
|
||||
|
||||
class TestEvMenu(TestCase):
|
||||
"Run the EvMenu testing."
|
||||
menutree = {} # can also be the path to the menu tree
|
||||
startnode = "start"
|
||||
cmdset_mergetype = "Replace"
|
||||
cmdset_priority = 1
|
||||
auto_quit = True
|
||||
auto_look = True
|
||||
auto_help = True
|
||||
cmd_on_exit = "look"
|
||||
persistent = False
|
||||
startnode_input = ""
|
||||
kwargs = {}
|
||||
|
||||
# this is compared against the full tree structure generated
|
||||
expected_tree = []
|
||||
# this allows for verifying that a given node returns a given text. The
|
||||
# text is compared with .startswith, so the entire text need not be matched.
|
||||
expected_node_texts = {}
|
||||
# just check the number of options from each node
|
||||
expected_node_options_count = {}
|
||||
# check the actual options
|
||||
expected_node_options = {}
|
||||
|
||||
# set this to print the traversal as it happens (debugging)
|
||||
debug_output = False
|
||||
|
||||
def _debug_output(self, indent, msg):
|
||||
if self.debug_output:
|
||||
print(" " * indent + msg)
|
||||
|
||||
def _test_menutree(self, menu):
|
||||
"""
|
||||
This is a automatic tester of the menu tree by recursively progressing through the
|
||||
structure.
|
||||
"""
|
||||
|
||||
def _depth_first(menu, tree, visited, indent):
|
||||
|
||||
# we are in a given node here
|
||||
nodename = menu.nodename
|
||||
options = menu.test_options
|
||||
if isinstance(options, dict):
|
||||
options = (options, )
|
||||
|
||||
# run validation tests for this node
|
||||
compare_text = self.expected_node_texts.get(nodename, None)
|
||||
if compare_text is not None:
|
||||
compare_text = ansi.strip_ansi(compare_text.strip())
|
||||
node_text = menu.test_nodetext
|
||||
self.assertIsNotNone(
|
||||
bool(node_text),
|
||||
"node: {}: node-text is None, which was not expected.".format(nodename))
|
||||
node_text = ansi.strip_ansi(node_text.strip())
|
||||
self.assertTrue(
|
||||
node_text.startswith(compare_text),
|
||||
"\nnode \"{}\':\nOutput:\n{}\n\nExpected (startswith):\n{}".format(
|
||||
nodename, node_text, compare_text))
|
||||
compare_options_count = self.expected_node_options_count.get(nodename, None)
|
||||
if compare_options_count is not None:
|
||||
self.assertEqual(
|
||||
len(options), compare_options_count,
|
||||
"Not the right number of options returned from node {}.".format(nodename))
|
||||
compare_options = self.expected_node_options.get(nodename, None)
|
||||
if compare_options:
|
||||
self.assertEqual(
|
||||
options, compare_options,
|
||||
"Options returned from node {} does not match.".format(nodename))
|
||||
|
||||
self._debug_output(indent, "*{}".format(nodename))
|
||||
subtree = []
|
||||
|
||||
if not options:
|
||||
# an end node
|
||||
if nodename not in visited:
|
||||
visited.append(nodename)
|
||||
subtree = nodename
|
||||
else:
|
||||
for inum, optdict in enumerate(options):
|
||||
|
||||
key, desc, execute, goto = optdict.get("key", ""), optdict.get("desc", None),\
|
||||
optdict.get("exec", None), optdict.get("goto", None)
|
||||
|
||||
# prepare the key to pass to the menu
|
||||
if isinstance(key, (tuple, list)) and len(key) > 1:
|
||||
key = key[0]
|
||||
if key == "_default":
|
||||
key = "test raw input"
|
||||
if not key:
|
||||
key = str(inum + 1)
|
||||
|
||||
backup_menu = copy.copy(menu)
|
||||
|
||||
# step the menu
|
||||
menu.parse_input(key)
|
||||
|
||||
# from here on we are likely in a different node
|
||||
nodename = menu.nodename
|
||||
|
||||
if menu.close_menu.called:
|
||||
# this was an end node
|
||||
self._debug_output(indent, " .. menu exited! Back to previous node.")
|
||||
menu = backup_menu
|
||||
menu.close_menu = MagicMock()
|
||||
visited.append(nodename)
|
||||
subtree.append(nodename)
|
||||
elif nodename not in visited:
|
||||
visited.append(nodename)
|
||||
subtree.append(nodename)
|
||||
_depth_first(menu, subtree, visited, indent + 2)
|
||||
#self._debug_output(indent, " -> arrived at {}".format(nodename))
|
||||
else:
|
||||
subtree.append(nodename)
|
||||
#self._debug_output( indent, " -> arrived at {} (circular call)".format(nodename))
|
||||
self._debug_output(indent, "-- {} ({}) -> {}".format(key, desc, goto))
|
||||
|
||||
if subtree:
|
||||
tree.append(subtree)
|
||||
|
||||
# the start node has already fired at this point
|
||||
visited_nodes = [menu.nodename]
|
||||
traversal_tree = [menu.nodename]
|
||||
_depth_first(menu, traversal_tree, visited_nodes, 1)
|
||||
|
||||
self.assertGreaterEqual(len(menu._menutree), len(visited_nodes))
|
||||
self.assertEqual(traversal_tree, self.expected_tree)
|
||||
|
||||
def setUp(self):
|
||||
self.caller = Mock()
|
||||
self.caller.msg = Mock()
|
||||
self.menu = evmenu.EvMenu(self.caller, "evennia.utils.evmenu", startnode="test_start_node",
|
||||
persistent=True, cmdset_mergetype="Replace", testval="val",
|
||||
testval2="val2")
|
||||
self.menu = None
|
||||
if self.menutree:
|
||||
self.caller = MagicMock()
|
||||
self.caller.key = "Test"
|
||||
self.caller2 = MagicMock()
|
||||
self.caller2.key = "Test"
|
||||
self.caller.msg = MagicMock()
|
||||
self.caller2.msg = MagicMock()
|
||||
self.session = MagicMock()
|
||||
self.session2 = MagicMock()
|
||||
self.menu = evmenu.EvMenu(self.caller, self.menutree, startnode=self.startnode,
|
||||
cmdset_mergetype=self.cmdset_mergetype,
|
||||
cmdset_priority=self.cmdset_priority,
|
||||
auto_quit=self.auto_quit, auto_look=self.auto_look,
|
||||
auto_help=self.auto_help,
|
||||
cmd_on_exit=self.cmd_on_exit, persistent=False,
|
||||
startnode_input=self.startnode_input, session=self.session,
|
||||
**self.kwargs)
|
||||
# persistent version
|
||||
self.pmenu = evmenu.EvMenu(self.caller2, self.menutree, startnode=self.startnode,
|
||||
cmdset_mergetype=self.cmdset_mergetype,
|
||||
cmdset_priority=self.cmdset_priority,
|
||||
auto_quit=self.auto_quit, auto_look=self.auto_look,
|
||||
auto_help=self.auto_help,
|
||||
cmd_on_exit=self.cmd_on_exit, persistent=True,
|
||||
startnode_input=self.startnode_input, session=self.session2,
|
||||
**self.kwargs)
|
||||
|
||||
self.menu.close_menu = MagicMock()
|
||||
self.pmenu.close_menu = MagicMock()
|
||||
|
||||
def test_menu_structure(self):
|
||||
if self.menu:
|
||||
self._test_menutree(self.menu)
|
||||
self._test_menutree(self.pmenu)
|
||||
|
||||
|
||||
class TestEvMenuExample(TestEvMenu):
|
||||
|
||||
menutree = "evennia.utils.evmenu"
|
||||
startnode = "test_start_node"
|
||||
kwargs = {"testval": "val", "testval2": "val2"}
|
||||
debug_output = False
|
||||
|
||||
expected_node_texts = {
|
||||
"test_view_node": "Your name is"}
|
||||
|
||||
expected_tree = \
|
||||
['test_start_node',
|
||||
['test_set_node',
|
||||
['test_start_node'],
|
||||
'test_look_node',
|
||||
['test_start_node'],
|
||||
'test_view_node',
|
||||
['test_start_node'],
|
||||
'test_dynamic_node',
|
||||
['test_dynamic_node',
|
||||
'test_dynamic_node',
|
||||
'test_dynamic_node',
|
||||
'test_dynamic_node',
|
||||
'test_start_node'],
|
||||
'test_end_node',
|
||||
'test_displayinput_node',
|
||||
['test_start_node']]]
|
||||
|
||||
def test_kwargsave(self):
|
||||
self.assertTrue(hasattr(self.menu, "testval"))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue