Merge branch 'BlauFeuer-develop-muxcommand' into develop

This commit is contained in:
Griatch 2018-03-14 22:49:01 +01:00
commit 8987d3e5c2
11 changed files with 196 additions and 69 deletions

View file

@ -455,7 +455,7 @@ class CmdOption(COMMAND_DEFAULT_CLASS):
Usage:
@option[/save] [name = value]
Switch:
Switches:
save - Save the current option settings for future logins.
clear - Clear the saved options.
@ -467,6 +467,7 @@ class CmdOption(COMMAND_DEFAULT_CLASS):
"""
key = "@option"
aliases = "@options"
switch_options = ("save", "clear")
locks = "cmd:all()"
# this is used by the parent
@ -650,6 +651,7 @@ class CmdQuit(COMMAND_DEFAULT_CLASS):
game. Use the /all switch to disconnect from all sessions.
"""
key = "@quit"
switch_options = ("all",)
locks = "cmd:all()"
# this is used by the parent

View file

@ -36,6 +36,7 @@ class CmdBoot(COMMAND_DEFAULT_CLASS):
"""
key = "@boot"
switch_options = ("quiet", "sid")
locks = "cmd:perm(boot) or perm(Admin)"
help_category = "Admin"
@ -265,6 +266,7 @@ class CmdDelAccount(COMMAND_DEFAULT_CLASS):
"""
key = "@delaccount"
switch_options = ("delobj",)
locks = "cmd:perm(delaccount) or perm(Developer)"
help_category = "Admin"
@ -329,9 +331,9 @@ class CmdEmit(COMMAND_DEFAULT_CLASS):
@pemit [<obj>, <obj>, ... =] <message>
Switches:
room : limit emits to rooms only (default)
accounts : limit emits to accounts only
contents : send to the contents of matched objects too
room - limit emits to rooms only (default)
accounts - limit emits to accounts only
contents - send to the contents of matched objects too
Emits a message to the selected objects or to
your immediate surroundings. If the object is a room,
@ -341,6 +343,7 @@ class CmdEmit(COMMAND_DEFAULT_CLASS):
"""
key = "@emit"
aliases = ["@pemit", "@remit"]
switch_options = ("room", "accounts", "contents")
locks = "cmd:perm(emit) or perm(Builder)"
help_category = "Admin"
@ -442,14 +445,15 @@ class CmdPerm(COMMAND_DEFAULT_CLASS):
@perm[/switch] *<account> [= <permission>[,<permission>,...]]
Switches:
del : delete the given permission from <object> or <account>.
account : set permission on an account (same as adding * to name)
del - delete the given permission from <object> or <account>.
account - set permission on an account (same as adding * to name)
This command sets/clears individual permission strings on an object
or account. If no permission is given, list all permissions on <object>.
"""
key = "@perm"
aliases = "@setperm"
switch_options = ("del", "account")
locks = "cmd:perm(perm) or perm(Developer)"
help_category = "Admin"

View file

@ -237,6 +237,7 @@ class CmdBatchCommands(_COMMAND_DEFAULT_CLASS):
"""
key = "@batchcommands"
aliases = ["@batchcommand", "@batchcmd"]
switch_options = ("interactive",)
locks = "cmd:perm(batchcommands) or perm(Developer)"
help_category = "Building"
@ -347,6 +348,7 @@ class CmdBatchCode(_COMMAND_DEFAULT_CLASS):
"""
key = "@batchcode"
aliases = ["@batchcodes"]
switch_options = ("interactive", "debug")
locks = "cmd:superuser()"
help_category = "Building"

View file

@ -124,6 +124,7 @@ class CmdSetObjAlias(COMMAND_DEFAULT_CLASS):
key = "@alias"
aliases = "@setobjalias"
switch_options = ("category",)
locks = "cmd:perm(setobjalias) or perm(Builder)"
help_category = "Building"
@ -218,6 +219,7 @@ class CmdCopy(ObjManipCommand):
"""
key = "@copy"
switch_options = ("reset",)
locks = "cmd:perm(copy) or perm(Builder)"
help_category = "Building"
@ -299,6 +301,7 @@ class CmdCpAttr(ObjManipCommand):
If you don't supply a source object, yourself is used.
"""
key = "@cpattr"
switch_options = ("move",)
locks = "cmd:perm(cpattr) or perm(Builder)"
help_category = "Building"
@ -440,6 +443,7 @@ class CmdMvAttr(ObjManipCommand):
object. If you don't supply a source object, yourself is used.
"""
key = "@mvattr"
switch_options = ("copy",)
locks = "cmd:perm(mvattr) or perm(Builder)"
help_category = "Building"
@ -488,6 +492,7 @@ class CmdCreate(ObjManipCommand):
"""
key = "@create"
switch_options = ("drop",)
locks = "cmd:perm(create) or perm(Builder)"
help_category = "Building"
@ -573,6 +578,7 @@ class CmdDesc(COMMAND_DEFAULT_CLASS):
"""
key = "@desc"
aliases = "@describe"
switch_options = ("edit",)
locks = "cmd:perm(desc) or perm(Builder)"
help_category = "Building"
@ -634,11 +640,11 @@ class CmdDestroy(COMMAND_DEFAULT_CLASS):
Usage:
@destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...]
switches:
Switches:
override - The @destroy command will usually avoid accidentally
destroying account objects. This switch overrides this safety.
force - destroy without confirmation.
examples:
Examples:
@destroy house, roof, door, 44-78
@destroy 5-10, flower, 45
@destroy/force north
@ -651,6 +657,7 @@ class CmdDestroy(COMMAND_DEFAULT_CLASS):
key = "@destroy"
aliases = ["@delete", "@del"]
switch_options = ("override", "force")
locks = "cmd:perm(destroy) or perm(Builder)"
help_category = "Building"
@ -774,6 +781,7 @@ class CmdDig(ObjManipCommand):
would be 'north;no;n'.
"""
key = "@dig"
switch_options = ("teleport",)
locks = "cmd:perm(dig) or perm(Builder)"
help_category = "Building"
@ -883,7 +891,7 @@ class CmdDig(ObjManipCommand):
new_back_exit.dbref,
alias_string)
caller.msg("%s%s%s" % (room_string, exit_to_string, exit_back_string))
if new_room and ('teleport' in self.switches or "tel" in self.switches):
if new_room and 'teleport' in self.switches:
caller.move_to(new_room)
@ -916,6 +924,7 @@ class CmdTunnel(COMMAND_DEFAULT_CLASS):
key = "@tunnel"
aliases = ["@tun"]
switch_options = ("oneway", "tel")
locks = "cmd: perm(tunnel) or perm(Builder)"
help_category = "Building"
@ -2276,6 +2285,7 @@ class CmdFind(COMMAND_DEFAULT_CLASS):
key = "@find"
aliases = "@search, @locate"
switch_options = ("room", "exit", "char", "exact", "loc")
locks = "cmd:perm(find) or perm(Builder)"
help_category = "Building"
@ -2312,7 +2322,7 @@ class CmdFind(COMMAND_DEFAULT_CLASS):
restrictions = ""
if self.switches:
restrictions = ", %s" % (",".join(self.switches))
restrictions = ", %s" % (", ".join(self.switches))
if is_dbref or is_account:
@ -2392,7 +2402,7 @@ class CmdTeleport(COMMAND_DEFAULT_CLASS):
teleport object to another location
Usage:
@tel/switch [<object> =] <target location>
@tel/switch [<object> to||=] <target location>
Examples:
@tel Limbo
@ -2416,6 +2426,8 @@ class CmdTeleport(COMMAND_DEFAULT_CLASS):
"""
key = "@tel"
aliases = "@teleport"
switch_options = ("quiet", "intoexit", "tonone", "loc")
rhs_split = ("=", " to ") # Prefer = delimiter, but allow " to " usage.
locks = "cmd:perm(teleport) or perm(Builder)"
help_category = "Building"
@ -2523,6 +2535,7 @@ class CmdScript(COMMAND_DEFAULT_CLASS):
key = "@script"
aliases = "@addscript"
switch_options = ("start", "stop")
locks = "cmd:perm(script) or perm(Builder)"
help_category = "Building"
@ -2622,6 +2635,7 @@ class CmdTag(COMMAND_DEFAULT_CLASS):
key = "@tag"
aliases = ["@tags"]
options = ("search", "del")
locks = "cmd:perm(tag) or perm(Builder)"
help_category = "Building"
arg_regex = r"(/\w+?(\s|$))|\s|$"
@ -2763,6 +2777,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
"""
key = "@spawn"
switch_options = ("noloc", )
locks = "cmd:perm(spawn) or perm(Builder)"
help_category = "Building"

View file

@ -377,7 +377,7 @@ class CmdCBoot(COMMAND_DEFAULT_CLASS):
Usage:
@cboot[/quiet] <channel> = <account> [:reason]
Switches:
Switch:
quiet - don't notify the channel
Kicks an account or object from a channel you control.
@ -385,6 +385,7 @@ class CmdCBoot(COMMAND_DEFAULT_CLASS):
"""
key = "@cboot"
switch_options = ("quiet",)
locks = "cmd: not pperm(channel_banned)"
help_category = "Comms"
@ -453,6 +454,7 @@ class CmdCemit(COMMAND_DEFAULT_CLASS):
key = "@cemit"
aliases = ["@cmsg"]
switch_options = ("sendername", "quiet")
locks = "cmd: not pperm(channel_banned) and pperm(Player)"
help_category = "Comms"
@ -683,6 +685,7 @@ class CmdPage(COMMAND_DEFAULT_CLASS):
key = "page"
aliases = ['tell']
switch_options = ("last", "list")
locks = "cmd:not pperm(page_banned)"
help_category = "Comms"
@ -850,6 +853,7 @@ class CmdIRC2Chan(COMMAND_DEFAULT_CLASS):
"""
key = "@irc2chan"
switch_options = ("delete", "remove", "disconnect", "list", "ssl")
locks = "cmd:serversetting(IRC_ENABLED) and pperm(Developer)"
help_category = "Comms"
@ -1016,6 +1020,7 @@ class CmdRSS2Chan(COMMAND_DEFAULT_CLASS):
"""
key = "@rss2chan"
switch_options = ("disconnect", "remove", "list")
locks = "cmd:serversetting(RSS_ENABLED) and pperm(Developer)"
help_category = "Comms"

View file

@ -88,8 +88,7 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
Switches:
inputline - replace on the inputline (default)
object - replace on object-lookup
account - replace on account-lookup
account - replace on account-lookup
list - show all defined aliases (also "nicks" works)
delete - remove nick by index in /list
clearall - clear all nicks
@ -118,6 +117,7 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
"""
key = "nick"
switch_options = ("inputline", "object", "account", "list", "delete", "clearall")
aliases = ["nickname", "nicks"]
locks = "cmd:all()"
@ -442,12 +442,13 @@ class CmdGive(COMMAND_DEFAULT_CLASS):
give away something to someone
Usage:
give <inventory obj> = <target>
give <inventory obj> <to||=> <target>
Gives an items from your inventory to another character,
placing it in their inventory.
"""
key = "give"
rhs_split = ("=", " to ") # Prefer = delimiter, but allow " to " usage.
locks = "cmd:all()"
arg_regex = r"\s|$"

View file

@ -317,6 +317,7 @@ class CmdSetHelp(COMMAND_DEFAULT_CLASS):
"""
key = "@sethelp"
switch_options = ("edit", "replace", "append", "extend", "delete")
locks = "cmd:perm(Helper)"
help_category = "Building"

View file

@ -79,6 +79,13 @@ class MuxCommand(Command):
it here). The rest of the command is stored in self.args, which can
start with the switch indicator /.
Optional variables to aid in parsing, if set:
self.switch_options - (tuple of valid /switches expected by this
command (without the /))
self.rhs_split - Alternate string delimiter or tuple of strings
to separate left/right hand sides. tuple form
gives priority split to first string delimiter.
This parser breaks self.args into its constituents and stores them in the
following variables:
self.switches = [list of /switches (without the /)]
@ -97,9 +104,18 @@ class MuxCommand(Command):
"""
raw = self.args
args = raw.strip()
# Without explicitly setting these attributes, they assume default values:
if not hasattr(self, "switch_options"):
self.switch_options = None
if not hasattr(self, "rhs_split"):
self.rhs_split = "="
if not hasattr(self, "account_caller"):
self.account_caller = False
# split out switches
switches = []
switches, delimiters = [], self.rhs_split
if self.switch_options:
self.switch_options = [opt.lower() for opt in self.switch_options]
if args and len(args) > 1 and raw[0] == "/":
# we have a switch, or a set of switches. These end with a space.
switches = args[1:].split(None, 1)
@ -109,16 +125,50 @@ class MuxCommand(Command):
else:
args = ""
switches = switches[0].split('/')
# If user-provides switches, parse them with parser switch options.
if switches and self.switch_options:
valid_switches, unused_switches, extra_switches = [], [], []
for element in switches:
option_check = [opt for opt in self.switch_options if opt == element]
if not option_check:
option_check = [opt for opt in self.switch_options if opt.startswith(element)]
match_count = len(option_check)
if match_count > 1:
extra_switches.extend(option_check) # Either the option provided is ambiguous,
elif match_count == 1:
valid_switches.extend(option_check) # or it is a valid option abbreviation,
elif match_count == 0:
unused_switches.append(element) # or an extraneous option to be ignored.
if extra_switches: # User provided switches
self.msg('|g%s|n: |wAmbiguous switch supplied: Did you mean /|C%s|w?' %
(self.cmdstring, ' |nor /|C'.join(extra_switches)))
if unused_switches:
plural = '' if len(unused_switches) == 1 else 'es'
self.msg('|g%s|n: |wExtra switch%s "/|C%s|w" ignored.' %
(self.cmdstring, plural, '|n, /|C'.join(unused_switches)))
switches = valid_switches # Only include valid_switches in command function call
arglist = [arg.strip() for arg in args.split()]
# check for arg1, arg2, ... = argA, argB, ... constructs
lhs, rhs = args, None
lhslist, rhslist = [arg.strip() for arg in args.split(',')], []
if args and '=' in args:
lhs, rhs = [arg.strip() for arg in args.split('=', 1)]
lhslist = [arg.strip() for arg in lhs.split(',')]
rhslist = [arg.strip() for arg in rhs.split(',')]
lhs, rhs = args.strip(), None
if lhs:
if delimiters and hasattr(delimiters, '__iter__'): # If delimiter is iterable,
best_split = delimiters[0] # (default to first delimiter)
for this_split in delimiters: # try each delimiter
if this_split in lhs: # to find first successful split
best_split = this_split # to be the best split.
break
else:
best_split = delimiters
# Parse to separate left into left/right sides using best_split delimiter string
if best_split in lhs:
lhs, rhs = lhs.split(best_split, 1)
# Trim user-injected whitespace
rhs = rhs.strip() if rhs is not None else None
lhs = lhs.strip()
# Further split left/right sides by comma delimiter
lhslist = [arg.strip() for arg in lhs.split(',')] if lhs is not None else ""
rhslist = [arg.strip() for arg in rhs.split(',')] if rhs is not None else ""
# save to object properties:
self.raw = raw
self.switches = switches
@ -133,7 +183,7 @@ class MuxCommand(Command):
# sure that self.caller is always the account if possible. We also create
# a special property "character" for the puppeted object, if any. This
# is convenient for commands defined on the Account only.
if hasattr(self, "account_caller") and self.account_caller:
if self.account_caller:
if utils.inherits_from(self.caller, "evennia.objects.objects.DefaultObject"):
# caller is an Object/Character
self.character = self.caller
@ -169,6 +219,8 @@ class MuxCommand(Command):
string += "\nraw argument (self.raw): |w%s|n \n" % self.raw
string += "cmd args (self.args): |w%s|n\n" % self.args
string += "cmd switches (self.switches): |w%s|n\n" % self.switches
string += "cmd options (self.switch_options): |w%s|n\n" % self.switch_options
string += "cmd parse left/right using (self.rhs_split): |w%s|n\n" % self.rhs_split
string += "space-separated arg list (self.arglist): |w%s|n\n" % self.arglist
string += "lhs, left-hand side of '=' (self.lhs): |w%s|n\n" % self.lhs
string += "lhs, comma separated (self.lhslist): |w%s|n\n" % self.lhslist
@ -193,18 +245,4 @@ class MuxAccountCommand(MuxCommand):
character is actually attached to this Account and Session.
"""
def parse(self):
"""
We run the parent parser as usual, then fix the result
"""
super(MuxAccountCommand, self).parse()
if utils.inherits_from(self.caller, "evennia.objects.objects.DefaultObject"):
# caller is an Object/Character
self.character = self.caller
self.caller = self.caller.account
elif utils.inherits_from(self.caller, "evennia.accounts.accounts.DefaultAccount"):
# caller was already an Account
self.character = self.caller.get_puppet(self.session)
else:
self.character = None
account_caller = True # Using MuxAccountCommand explicitly defaults the caller to an account

View file

@ -245,6 +245,7 @@ class CmdPy(COMMAND_DEFAULT_CLASS):
"""
key = "@py"
aliases = ["!"]
switch_options = ("time", "edit")
locks = "cmd:perm(py) or perm(Developer)"
help_category = "System"
@ -328,6 +329,7 @@ class CmdScripts(COMMAND_DEFAULT_CLASS):
"""
key = "@scripts"
aliases = ["@globalscript", "@listscripts"]
switch_options = ("start", "stop", "kill", "validate")
locks = "cmd:perm(listscripts) or perm(Admin)"
help_category = "System"
@ -521,6 +523,7 @@ class CmdService(COMMAND_DEFAULT_CLASS):
key = "@service"
aliases = ["@services"]
switch_options = ("list", "start", "stop", "delete")
locks = "cmd:perm(service) or perm(Developer)"
help_category = "System"
@ -672,7 +675,7 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS):
Usage:
@server[/mem]
Switch:
Switches:
mem - return only a string of the current memory usage
flushmem - flush the idmapper cache
@ -703,6 +706,7 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS):
"""
key = "@server"
aliases = ["@serverload", "@serverprocess"]
switch_options = ("mem", "flushmem")
locks = "cmd:perm(list) or perm(Developer)"
help_category = "System"

View file

@ -21,6 +21,7 @@ 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
from evennia.commands.default.muxcommand import MuxCommand
from evennia.commands.command import Command, InterruptCommand
from evennia.utils import ansi, utils
from evennia.server.sessionhandler import SESSIONS
@ -72,7 +73,6 @@ class CommandTest(EvenniaTest):
cmdobj.obj = obj or (caller if caller else self.char1)
# test
old_msg = receiver.msg
returned_msg = ""
try:
receiver.msg = Mock()
cmdobj.at_pre_cmd()
@ -126,9 +126,12 @@ class TestGeneral(CommandTest):
self.call(general.CmdPose(), "looks around", "Char looks around")
def test_nick(self):
self.call(general.CmdNick(), "testalias = testaliasedstring1", "Inputlinenick 'testalias' mapped to 'testaliasedstring1'.")
self.call(general.CmdNick(), "/account testalias = testaliasedstring2", "Accountnick 'testalias' mapped to 'testaliasedstring2'.")
self.call(general.CmdNick(), "/object testalias = testaliasedstring3", "Objectnick 'testalias' mapped to 'testaliasedstring3'.")
self.call(general.CmdNick(), "testalias = testaliasedstring1",
"Inputlinenick 'testalias' mapped to 'testaliasedstring1'.")
self.call(general.CmdNick(), "/account testalias = testaliasedstring2",
"Accountnick 'testalias' mapped to 'testaliasedstring2'.")
self.call(general.CmdNick(), "/object testalias = testaliasedstring3",
"Objectnick 'testalias' mapped to 'testaliasedstring3'.")
self.assertEqual(u"testaliasedstring1", self.char1.nicks.get("testalias"))
self.assertEqual(u"testaliasedstring2", self.char1.nicks.get("testalias", category="account"))
self.assertEqual(None, self.char1.account.nicks.get("testalias", category="account"))
@ -138,6 +141,33 @@ class TestGeneral(CommandTest):
self.call(general.CmdGet(), "Obj", "You pick up Obj.")
self.call(general.CmdDrop(), "Obj", "You drop Obj.")
def test_give(self):
self.call(general.CmdGive(), "Obj to Char2", "You aren't carrying Obj.")
self.call(general.CmdGive(), "Obj = Char2", "You aren't carrying Obj.")
self.call(general.CmdGet(), "Obj", "You pick up Obj.")
self.call(general.CmdGive(), "Obj to Char2", "You give")
self.call(general.CmdGive(), "Obj = Char", "You give", caller=self.char2)
def test_mux_command(self):
class CmdTest(MuxCommand):
key = 'test'
switch_options = ('test', 'testswitch', 'testswitch2')
def func(self):
self.msg("Switches matched: {}".format(self.switches))
self.call(CmdTest(), "/test/testswitch/testswitch2", "Switches matched: ['test', 'testswitch', 'testswitch2']")
self.call(CmdTest(), "/test", "Switches matched: ['test']")
self.call(CmdTest(), "/test/testswitch", "Switches matched: ['test', 'testswitch']")
self.call(CmdTest(), "/testswitch/testswitch2", "Switches matched: ['testswitch', 'testswitch2']")
self.call(CmdTest(), "/testswitch", "Switches matched: ['testswitch']")
self.call(CmdTest(), "/testswitch2", "Switches matched: ['testswitch2']")
self.call(CmdTest(), "/t", "test: Ambiguous switch supplied: "
"Did you mean /test or /testswitch or /testswitch2?|Switches matched: []")
self.call(CmdTest(), "/tests", "test: Ambiguous switch supplied: "
"Did you mean /testswitch or /testswitch2?|Switches matched: []")
def test_say(self):
self.call(general.CmdSay(), "Testing", "You say, \"Testing\"")
@ -225,7 +255,8 @@ class TestAccount(CommandTest):
self.call(account.CmdColorTest(), "ansi", "ANSI colors:", caller=self.account)
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)
self.call(account.CmdCharCreate(), "Test1=Test char",
"Created new character Test1. Use @ic Test1 to enter the game", caller=self.account)
def test_quell(self):
self.call(account.CmdQuell(), "", "Quelling to current puppet's permissions (developer).", caller=self.account)
@ -234,7 +265,8 @@ class TestAccount(CommandTest):
class TestBuilding(CommandTest):
def test_create(self):
name = settings.BASE_OBJECT_TYPECLASS.rsplit('.', 1)[1]
self.call(building.CmdCreate(), "/drop TestObj1", "You create a new %s: TestObj1." % name)
self.call(building.CmdCreate(), "/d TestObj1", # /d switch is abbreviated form of /drop
"You create a new %s: TestObj1." % name)
def test_examine(self):
self.call(building.CmdExamine(), "Obj", "Name/key: Obj")
@ -244,7 +276,8 @@ class TestBuilding(CommandTest):
self.call(building.CmdSetObjAlias(), "Obj = TestObj1b", "Alias(es) for 'Obj(#4)' set to 'testobj1b'.")
def test_copy(self):
self.call(building.CmdCopy(), "Obj = TestObj2;TestObj2b, TestObj3;TestObj3b", "Copied Obj to 'TestObj3' (aliases: ['TestObj3b']")
self.call(building.CmdCopy(), "Obj = TestObj2;TestObj2b, TestObj3;TestObj3b",
"Copied Obj to 'TestObj3' (aliases: ['TestObj3b']")
def test_attribute_commands(self):
self.call(building.CmdSetAttribute(), "Obj/test1=\"value1\"", "Created attribute Obj/test1 = 'value1'")
@ -287,7 +320,8 @@ class TestBuilding(CommandTest):
def test_typeclass(self):
self.call(building.CmdTypeclass(), "Obj = evennia.objects.objects.DefaultExit",
"Obj changed typeclass from evennia.objects.objects.DefaultObject to evennia.objects.objects.DefaultExit.")
"Obj changed typeclass from evennia.objects.objects.DefaultObject "
"to evennia.objects.objects.DefaultExit.")
def test_lock(self):
self.call(building.CmdLock(), "Obj = test:perm(Developer)", "Added lock 'test:perm(Developer)' to Obj.")
@ -297,15 +331,24 @@ class TestBuilding(CommandTest):
expect = "One Match(#1#7, loc):\n " +\
"Char2(#7) evennia.objects.objects.DefaultCharacter (location: Room(#1))"
self.call(building.CmdFind(), "Char2", expect, cmdstring="locate")
self.call(building.CmdFind(), "/ex Char2", # /ex is an ambiguous switch
"locate: Ambiguous switch supplied: Did you mean /exit or /exact?|" + expect,
cmdstring="locate")
self.call(building.CmdFind(), "Char2", expect, cmdstring="@locate")
self.call(building.CmdFind(), "/loc Char2", expect, cmdstring="find")
self.call(building.CmdFind(), "/l Char2", expect, cmdstring="find") # /l switch is abbreviated form of /loc
self.call(building.CmdFind(), "Char2", "One Match", cmdstring="@find")
def test_script(self):
self.call(building.CmdScript(), "Obj = scripts.Script", "Script scripts.Script successfully added")
def test_teleport(self):
self.call(building.CmdTeleport(), "Room2", "Room2(#2)\n|Teleported to Room2.")
self.call(building.CmdTeleport(), "/quiet Room2", "Room2(#2)\n|Teleported to Room2.")
self.call(building.CmdTeleport(), "/t", # /t switch is abbreviated form of /tonone
"Cannot teleport a puppeted object (Char, puppeted by TestAccount(account 1)) to a Nonelocation.")
self.call(building.CmdTeleport(), "/l Room2", # /l switch is abbreviated form of /loc
"Destination has no location.")
self.call(building.CmdTeleport(), "/q me to Room2", # /q switch is abbreviated form of /quiet
"Char is already at Room2.")
def test_spawn(self):
def getObject(commandTest, objKeyStr):
@ -321,7 +364,7 @@ class TestBuilding(CommandTest):
self.call(building.CmdSpawn(), " ", "Usage: @spawn")
# Tests "@spawn <prototype_dictionary>" without specifying location.
self.call(building.CmdSpawn(), \
self.call(building.CmdSpawn(),
"{'key':'goblin', 'typeclass':'evennia.DefaultCharacter'}", "Spawned goblin")
goblin = getObject(self, "goblin")
@ -340,8 +383,8 @@ class TestBuilding(CommandTest):
# char1's default location in the future...
spawnLoc = self.room1
self.call(building.CmdSpawn(), \
"{'prototype':'GOBLIN', 'key':'goblin', 'location':'%s'}" \
self.call(building.CmdSpawn(),
"{'prototype':'GOBLIN', 'key':'goblin', 'location':'%s'}"
% spawnLoc.dbref, "Spawned goblin")
goblin = getObject(self, "goblin")
self.assertEqual(goblin.location, spawnLoc)
@ -354,70 +397,81 @@ class TestBuilding(CommandTest):
self.assertIsInstance(ball, DefaultObject)
ball.delete()
# Tests "@spawn/noloc ..." without specifying a location.
# Tests "@spawn/n ..." without specifying a location.
# Location should be "None".
self.call(building.CmdSpawn(), "/noloc 'BALL'", "Spawned Ball")
self.call(building.CmdSpawn(), "/n 'BALL'", "Spawned Ball") # /n switch is abbreviated form of /noloc
ball = getObject(self, "Ball")
self.assertIsNone(ball.location)
ball.delete()
# Tests "@spawn/noloc ...", but DO specify a location.
# Location should be the specified location.
self.call(building.CmdSpawn(), \
"/noloc {'prototype':'BALL', 'location':'%s'}" \
self.call(building.CmdSpawn(),
"/noloc {'prototype':'BALL', 'location':'%s'}"
% spawnLoc.dbref, "Spawned Ball")
ball = getObject(self, "Ball")
self.assertEqual(ball.location, spawnLoc)
ball.delete()
# test calling spawn with an invalid prototype.
self.call(building.CmdSpawn(), \
"'NO_EXIST'", "No prototype named 'NO_EXIST'")
self.call(building.CmdSpawn(), "'NO_EXIST'", "No prototype named 'NO_EXIST'")
class TestComms(CommandTest):
def setUp(self):
super(CommandTest, self).setUp()
self.call(comms.CmdChannelCreate(), "testchan;test=Test Channel", "Created channel testchan and connected to it.", receiver=self.account)
self.call(comms.CmdChannelCreate(), "testchan;test=Test Channel",
"Created channel testchan and connected to it.", receiver=self.account)
def test_toggle_com(self):
self.call(comms.CmdAddCom(), "tc = testchan", "You are already connected to channel testchan. You can now", receiver=self.account)
self.call(comms.CmdAddCom(), "tc = testchan",
"You are already connected to channel testchan. You can now", receiver=self.account)
self.call(comms.CmdDelCom(), "tc", "Your alias 'tc' for channel testchan was cleared.", receiver=self.account)
def test_channels(self):
self.call(comms.CmdChannels(), "", "Available channels (use comlist,addcom and delcom to manage", receiver=self.account)
self.call(comms.CmdChannels(), "",
"Available channels (use comlist,addcom and delcom to manage", receiver=self.account)
def test_all_com(self):
self.call(comms.CmdAllCom(), "", "Available channels (use comlist,addcom and delcom to manage", receiver=self.account)
self.call(comms.CmdAllCom(), "",
"Available channels (use comlist,addcom and delcom to manage", receiver=self.account)
def test_clock(self):
self.call(comms.CmdClock(), "testchan=send:all()", "Lock(s) applied. Current locks on testchan:", receiver=self.account)
self.call(comms.CmdClock(),
"testchan=send:all()", "Lock(s) applied. Current locks on testchan:", receiver=self.account)
def test_cdesc(self):
self.call(comms.CmdCdesc(), "testchan = Test Channel", "Description of channel 'testchan' set to 'Test Channel'.", receiver=self.account)
self.call(comms.CmdCdesc(), "testchan = Test Channel",
"Description of channel 'testchan' set to 'Test Channel'.", receiver=self.account)
def test_cemit(self):
self.call(comms.CmdCemit(), "testchan = Test Message", "[testchan] Test Message|Sent to channel testchan: Test Message", receiver=self.account)
self.call(comms.CmdCemit(), "testchan = Test Message",
"[testchan] Test Message|Sent to channel testchan: Test Message", receiver=self.account)
def test_cwho(self):
self.call(comms.CmdCWho(), "testchan", "Channel subscriptions\ntestchan:\n TestAccount", receiver=self.account)
def test_page(self):
self.call(comms.CmdPage(), "TestAccount2 = Test", "TestAccount2 is offline. They will see your message if they list their pages later.|You paged TestAccount2 with: 'Test'.", receiver=self.account)
self.call(comms.CmdPage(), "TestAccount2 = Test",
"TestAccount2 is offline. They will see your message if they list their pages later."
"|You paged TestAccount2 with: 'Test'.", receiver=self.account)
def test_cboot(self):
# No one else connected to boot
self.call(comms.CmdCBoot(), "", "Usage: @cboot[/quiet] <channel> = <account> [:reason]", receiver=self.account)
def test_cdestroy(self):
self.call(comms.CmdCdestroy(), "testchan", "[testchan] TestAccount: testchan is being destroyed. Make sure to change your aliases.|Channel 'testchan' was destroyed.", receiver=self.account)
self.call(comms.CmdCdestroy(), "testchan",
"[testchan] TestAccount: testchan is being destroyed. Make sure to change your aliases."
"|Channel 'testchan' was destroyed.", receiver=self.account)
class TestBatchProcess(CommandTest):
def test_batch_commands(self):
# cannot test batchcode here, it must run inside the server process
self.call(batchprocess.CmdBatchCommands(), "example_batch_cmds", "Running Batchcommand processor Automatic mode for example_batch_cmds")
self.call(batchprocess.CmdBatchCommands(), "example_batch_cmds",
"Running Batchcommand processor Automatic mode for example_batch_cmds")
# we make sure to delete the button again here to stop the running reactor
confirm = building.CmdDestroy.confirm
building.CmdDestroy.confirm = False

View file

@ -367,6 +367,7 @@ class CmdExtendedDesc(default_cmds.CmdDesc):
"""
aliases = ["describe", "detail"]
switch_options = () # Inherits from default_cmds.CmdDesc, but unused here
def reset_times(self, obj):
"""By deleteting the caches we force a re-load."""