Add unit tests for syscmds, refactor cmdparser

This commit is contained in:
Griatch 2019-02-01 23:23:41 +01:00
parent 55eb026e95
commit 11d39a57b5
4 changed files with 170 additions and 119 deletions

View file

@ -20,6 +20,7 @@ the line is just added to the editor buffer).
from evennia.comms.models import ChannelDB
from evennia.utils import create
from evennia.utils.utils import at_search_result
# The command keys the engine is calling
# (the actual names all start with __)
@ -76,57 +77,30 @@ class SystemMultimatch(COMMAND_DEFAULT_CLASS):
The cmdhandler adds a special attribute 'matches' to this
system command.
matches = [(candidate, cmd) , (candidate, cmd), ...],
matches = [(cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname) , (cmdname, ...), ...]
Here, `cmdname` is the command's name and `args` the rest of the incoming string,
without said command name. `cmdobj` is the Command instance, the cmdlen is
the same as len(cmdname) and mratio is a measure of how big a part of the
full input string the cmdname takes up - an exact match would be 1.0. Finally,
the `raw_cmdname` is the cmdname unmodified by eventual prefix-stripping.
where candidate is an instance of evennia.commands.cmdparser.CommandCandidate
and cmd is an an instantiated Command object matching the candidate.
"""
key = CMD_MULTIMATCH
locks = "cmd:all()"
def format_multimatches(self, caller, matches):
"""
Format multiple command matches to a useful error.
This is copied directly from the default method in
evennia.commands.cmdhandler.
"""
string = "There were multiple matches:"
for num, match in enumerate(matches):
# each match is a tuple (candidate, cmd)
candidate, cmd = match
is_channel = hasattr(cmd, "is_channel") and cmd.is_channel
if is_channel:
is_channel = " (channel)"
else:
is_channel = ""
is_exit = hasattr(cmd, "is_exit") and cmd.is_exit
if is_exit and cmd.destination:
is_exit = " (exit to %s)" % cmd.destination
else:
is_exit = ""
id1 = ""
id2 = ""
if not (is_channel or is_exit) and (hasattr(cmd, 'obj') and cmd.obj != caller):
# the command is defined on some other object
id1 = "%s-" % cmd.obj.name
id2 = " (%s-%s)" % (num + 1, candidate.cmdname)
else:
id1 = "%s-" % (num + 1)
id2 = ""
string += "\n %s%s%s%s%s" % (id1, candidate.cmdname, id2, is_channel, is_exit)
return string
def func(self):
"""
argument to cmd is a comma-separated string of
all the clashing matches.
Handle multiple-matches by using the at_search_result default handler.
"""
string = self.format_multimatches(self.caller, self.matches)
self.msg(string)
# this was set by the cmdparser and is a tuple
# (cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname). See
# evennia.commands.cmdparse.create_match for more details.
matches = self.matches
# at_search_result will itself msg the multimatch options to the caller.
at_search_result(
[match[2] for match in matches], self.caller, query=matches[0][0])
# Command called when the command given at the command line

View file

@ -21,9 +21,12 @@ from mock import Mock, mock
from evennia.commands.default.cmdset_character import CharacterCmdSet
from evennia.utils.test_resources import EvenniaTest
from evennia.commands.default import help, general, system, admin, account, building, batchprocess, comms, unloggedin
from evennia.commands.default import help, general, system, admin, account, building, batchprocess, comms, unloggedin, syscommands
from evennia.commands.cmdparser import build_matches
from evennia.commands.default.muxcommand import MuxCommand
from evennia.commands.command import Command, InterruptCommand
from evennia.commands import cmdparser
from evennia.commands.cmdset import CmdSet
from evennia.utils import ansi, utils, gametime
from evennia.server.sessionhandler import SESSIONS
from evennia import search_object
@ -283,30 +286,30 @@ class TestAccount(CommandTest):
def test_char_create(self):
self.call(account.CmdCharCreate(), "Test1=Test char",
"Created new character Test1. Use @ic Test1 to enter the game", caller=self.account)
def test_char_delete(self):
# Chardelete requires user input; this test is mainly to confirm
# Chardelete requires user input; this test is mainly to confirm
# whether permissions are being checked
# Add char to account playable characters
self.account.db._playable_characters.append(self.char1)
# Try deleting as Developer
self.call(account.CmdCharDelete(), "Char", "This will permanently destroy 'Char'. This cannot be undone. Continue yes/[no]?", caller=self.account)
# Downgrade permissions on account
self.account.permissions.add('Player')
self.account.permissions.remove('Developer')
# Set lock on character object to prevent deletion
self.char1.locks.add('delete:none()')
# Try deleting as Player
self.call(account.CmdCharDelete(), "Char", "You do not have permission to delete this character.", caller=self.account)
# Set lock on character object to allow self-delete
self.char1.locks.add('delete:pid(%i)' % self.account.id)
# Try deleting as Player again
self.call(account.CmdCharDelete(), "Char", "This will permanently destroy 'Char'. This cannot be undone. Continue yes/[no]?", caller=self.account)
@ -657,3 +660,33 @@ class TestUnconnectedCommand(CommandTest):
datetime.datetime.fromtimestamp(gametime.SERVER_START_TIME).ctime(),
SESSIONS.account_count(), utils.get_evennia_version())
self.call(unloggedin.CmdUnconnectedInfo(), "", expected)
# Test syscommands
class TestSystemCommands(CommandTest):
def test_simple_defaults(self):
self.call(syscommands.SystemNoInput(), "")
self.call(syscommands.SystemNoMatch(), "Huh?")
def test_multimatch(self):
# set up fake matches and store on command instance
cmdset = CmdSet()
cmdset.add(general.CmdLook())
cmdset.add(general.CmdLook())
matches = cmdparser.build_matches("look", cmdset)
multimatch = syscommands.SystemMultimatch()
multimatch.matches = matches
self.call(multimatch, "look", "")
@mock.patch("evennia.commands.default.syscommands.ChannelDB")
def test_channelcommand(self, mock_channeldb):
channel = mock.MagicMock()
channel.msg = mock.MagicMock()
mock_channeldb.objects.get_channel = mock.MagicMock(return_value=channel)
self.call(syscommands.SystemSendToChannel(), "public:Hello")
channel.msg.assert_called()