More work on unittests, still issues

This commit is contained in:
Griatch 2018-07-12 10:18:04 +02:00
parent 706ed47ccc
commit a721889fc1
3 changed files with 56 additions and 69 deletions

View file

@ -2795,17 +2795,17 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
spawn objects from prototype spawn objects from prototype
Usage: Usage:
@spawn[/noloc] <prototype_name> @spawn[/noloc] <prototype_key>
@spawn[/noloc] <prototype_dict> @spawn[/noloc] <prototype_dict>
@spawn/search [key][;tag[,tag]] @spawn/search [prototype_keykey][;tag[,tag]]
@spawn/list [tag, tag] @spawn/list [tag, tag, ...]
@spawn/show [<key>] @spawn/show [<prototype_key>]
@spawn/update <key> @spawn/update <prototype_key>
@spawn/save <key>[;desc[;tag,tag[,...][;lockstring]]] = <prototype_dict> @spawn/save <prototype_dict>
@spawn/menu [<key>] @spawn/edit [<prototype_key>]
@olc - equivalent to @spawn/menu @olc - equivalent to @spawn/edit
Switches: Switches:
noloc - allow location to be None if not specified explicitly. Otherwise, noloc - allow location to be None if not specified explicitly. Otherwise,
@ -2819,7 +2819,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
them with latest version of given prototype. If given with /save, them with latest version of given prototype. If given with /save,
will auto-update all objects with the old version of the prototype will auto-update all objects with the old version of the prototype
without asking first. without asking first.
menu, olc - create/manipulate prototype in a menu interface. edit, olc - create/manipulate prototype in a menu interface.
Example: Example:
@spawn GOBLIN @spawn GOBLIN
@ -2827,10 +2827,11 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
@spawn/save {"key": "grunt", prototype: "goblin"};;mobs;edit:all() @spawn/save {"key": "grunt", prototype: "goblin"};;mobs;edit:all()
Dictionary keys: Dictionary keys:
|wprototype |n - name of parent prototype to use. Can be a list for |wprototype_parent |n - name of parent prototype to use. Required if typeclass is
multiple inheritance (inherits left to right) not set. Can be a path or a list for multiple inheritance (inherits
left to right). If set one of the parents must have a typeclass.
|wtypeclass |n - string. Required if prototype_parent is not set.
|wkey |n - string, the main object identifier |wkey |n - string, the main object identifier
|wtypeclass |n - string, if not set, will use settings.BASE_OBJECT_TYPECLASS
|wlocation |n - this should be a valid object or #dbref |wlocation |n - this should be a valid object or #dbref
|whome |n - valid object or #dbref |whome |n - valid object or #dbref
|wdestination|n - only valid for exits (object or dbref) |wdestination|n - only valid for exits (object or dbref)
@ -2875,7 +2876,8 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
string = ("{}\n|RCritical Python syntax error in argument. Only primitive " string = ("{}\n|RCritical Python syntax error in argument. Only primitive "
"Python structures are allowed. \nYou also need to use correct " "Python structures are allowed. \nYou also need to use correct "
"Python syntax. Remember especially to put quotes around all " "Python syntax. Remember especially to put quotes around all "
"strings inside lists and dicts.|n".format(err)) "strings inside lists and dicts.|n For more advanced uses, embed "
"inline functions in the strings.".format(err))
else: else:
string = "Expected {}, got {}.".format(expect, type(prototype)) string = "Expected {}, got {}.".format(expect, type(prototype))
self.caller.msg(string) self.caller.msg(string)
@ -2896,9 +2898,9 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
def _search_show_prototype(query, prototypes=None): def _search_show_prototype(query, prototypes=None):
# prototype detail # prototype detail
if not prototypes: if not prototypes:
prototypes = spawner.search_prototype(key=query) prototypes = protlib.search_prototype(key=query)
if prototypes: if prototypes:
return "\n".join(spawner.prototype_to_str(prot) for prot in prototypes) return "\n".join(protlib.prototype_to_str(prot) for prot in prototypes)
else: else:
return False return False
@ -2947,64 +2949,36 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
if 'list' in self.switches: if 'list' in self.switches:
# for list, all optional arguments are tags # for list, all optional arguments are tags
# import pudb; pudb.set_trace()
EvMore(caller, unicode(protlib.list_prototypes(caller, EvMore(caller, unicode(protlib.list_prototypes(caller,
tags=self.lhslist)), exit_on_lastpage=True) tags=self.lhslist)), exit_on_lastpage=True)
return return
if 'save' in self.switches: if 'save' in self.switches:
# store a prototype to the database store # store a prototype to the database store
if not self.args or not self.rhs: if not self.args:
caller.msg( caller.msg(
"Usage: @spawn/save <key>[;desc[;tag,tag[,...][;lockstring]]] = <prototype_dict>") "Usage: @spawn/save <key>[;desc[;tag,tag[,...][;lockstring]]] = <prototype_dict>")
return return
# handle lhs
parts = self.lhs.split(";", 3)
nparts = len(parts)
if nparts == 1:
key = parts[0].strip()
elif nparts == 2:
key, desc = (part.strip() for part in parts)
elif nparts == 3:
key, desc, tags = (part.strip() for part in parts)
tags = [tag.strip().lower() for tag in tags.split(",") if tag]
else:
# lockstrings can itself contain ;
key, desc, tags, lockstring = (part.strip() for part in parts)
tags = [tag.strip().lower() for tag in tags.split(",") if tag]
if not key:
caller.msg("The prototype must have a key.")
return
if not desc:
desc = "User-created prototype"
if not tags:
tags = ["user"]
if not lockstring:
lockstring = "edit:id({}) or perm(Admin); use:all()".format(caller.id)
is_valid, err = caller.locks.validate(lockstring)
if not is_valid:
caller.msg("|rLock error|n: {}".format(err))
return
# handle rhs: # handle rhs:
prototype = _parse_prototype(self.rhs) prototype = _parse_prototype(self.lhs.strip())
if not prototype: if not prototype:
return return
# inject the prototype_* keys into the prototype to save
prototype['prototype_key'] = prototype.get('prototype_key', key)
prototype['prototype_desc'] = prototype.get('prototype_desc', desc)
prototype['prototype_tags'] = prototype.get('prototype_tags', tags)
prototype['prototype_locks'] = prototype.get('prototype_locks', lockstring)
# present prototype to save # present prototype to save
new_matchstring = _search_show_prototype("", prototypes=[prototype]) new_matchstring = _search_show_prototype("", prototypes=[prototype])
string = "|yCreating new prototype:|n\n{}".format(new_matchstring) string = "|yCreating new prototype:|n\n{}".format(new_matchstring)
question = "\nDo you want to continue saving? [Y]/N" question = "\nDo you want to continue saving? [Y]/N"
prototype_key = prototype.get("prototype_key")
if not prototype_key:
caller.msg("\n|yTo save a prototype it must have the 'prototype_key' set.")
return
# check for existing prototype, # check for existing prototype,
old_matchstring = _search_show_prototype(key) old_matchstring = _search_show_prototype(prototype_key)
if old_matchstring: if old_matchstring:
string += "\n|yExisting saved prototype found:|n\n{}".format(old_matchstring) string += "\n|yExisting saved prototype found:|n\n{}".format(old_matchstring)
@ -3017,14 +2991,10 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
# all seems ok. Try to save. # all seems ok. Try to save.
try: try:
prot = spawner.save_db_prototype( prot = protlib.save_prototype(**prototype)
caller, key, prototype, desc=desc, tags=tags, locks=lockstring)
if not prot: if not prot:
caller.msg("|rError saving:|R {}.|n".format(key)) caller.msg("|rError saving:|R {}.|n".format(key))
return return
prot.locks.append("edit", "perm(Admin)")
if not prot.locks.get("use"):
prot.locks.add("use:all()")
except PermissionError as err: except PermissionError as err:
caller.msg("|rError saving:|R {}|n".format(err)) caller.msg("|rError saving:|R {}|n".format(err))
return return

View file

@ -360,6 +360,7 @@ class TestBuilding(CommandTest):
# check that it exists in the process. # check that it exists in the process.
query = search_object(objKeyStr) query = search_object(objKeyStr)
commandTest.assertIsNotNone(query) commandTest.assertIsNotNone(query)
commandTest.assertTrue(bool(query))
obj = query[0] obj = query[0]
commandTest.assertIsNotNone(obj) commandTest.assertIsNotNone(obj)
return obj return obj
@ -368,18 +369,20 @@ class TestBuilding(CommandTest):
self.call(building.CmdSpawn(), " ", "Usage: @spawn") self.call(building.CmdSpawn(), " ", "Usage: @spawn")
# Tests "@spawn <prototype_dictionary>" without specifying location. # Tests "@spawn <prototype_dictionary>" without specifying location.
with mock.patch('evennia.commands.default.func', return_value=iter(['y'])) as mock_iter:
self.call(building.CmdSpawn(), self.call(building.CmdSpawn(),
"{'prototype_key': 'testprot', 'key':'goblin', " "/save {'prototype_key': 'testprot', 'key':'Test Char', "
"'typeclass':'evennia.DefaultCharacter'}", "Spawned goblin") "'typeclass':'evennia.objects.objects.DefaultCharacter'}", "")
goblin = getObject(self, "goblin") mock_iter.assert_called()
# Tests that the spawned object's type is a DefaultCharacter. self.call(building.CmdSpawn(), "/list", "foo")
self.assertIsInstance(goblin, DefaultCharacter)
self.call(building.CmdSpawn(), 'testprot', "Spawned Test Char")
# Tests that the spawned object's location is the same as the caharacter's location, since # Tests that the spawned object's location is the same as the caharacter's location, since
# we did not specify it. # we did not specify it.
self.assertEqual(goblin.location, self.char1.location) testchar = getObject(self, "Test Char")
goblin.delete() self.assertEqual(testchar.location, self.char1.location)
testchar.delete()
# Test "@spawn <prototype_dictionary>" with a location other than the character's. # Test "@spawn <prototype_dictionary>" with a location other than the character's.
spawnLoc = self.room2 spawnLoc = self.room2
@ -389,10 +392,13 @@ class TestBuilding(CommandTest):
spawnLoc = self.room1 spawnLoc = self.room1
self.call(building.CmdSpawn(), self.call(building.CmdSpawn(),
"{'prototype_key':'GOBLIN', 'key':'goblin', 'location':'%s'}" "{'prototype_key':'GOBLIN', 'typeclass':'evennia.objects.objects.DefaultCharacter', "
% spawnLoc.dbref, "Spawned goblin") "'key':'goblin', 'location':'%s'}" % spawnLoc.dbref, "Spawned goblin")
goblin = getObject(self, "goblin") goblin = getObject(self, "goblin")
# Tests that the spawned object's type is a DefaultCharacter.
self.assertIsInstance(goblin, DefaultCharacter)
self.assertEqual(goblin.location, spawnLoc) self.assertEqual(goblin.location, spawnLoc)
goblin.delete() goblin.delete()
protlib.create_prototype(**{'key': 'Ball', 'prototype': 'GOBLIN', 'prototype_key': 'testball'}) protlib.create_prototype(**{'key': 'Ball', 'prototype': 'GOBLIN', 'prototype_key': 'testball'})

View file

@ -506,7 +506,7 @@ def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_ed
",".join(ptags))) ",".join(ptags)))
if not display_tuples: if not display_tuples:
return None return ""
table = [] table = []
width = 78 width = 78
@ -607,3 +607,14 @@ def validate_prototype(prototype, protkey=None, protparents=None,
raise RuntimeError("Error: " + "\nError: ".join(_flags['errors'])) raise RuntimeError("Error: " + "\nError: ".join(_flags['errors']))
if _flags['warnings']: if _flags['warnings']:
raise RuntimeWarning("Warning: " + "\nWarning: ".join(_flags['warnings'])) raise RuntimeWarning("Warning: " + "\nWarning: ".join(_flags['warnings']))
# make sure prototype_locks are set to defaults
prototype_locks = [lstring.split(":", 1)
for lstring in prototype.get("prototype_locks", "").split(';')]
locktypes = [tup[0].strip() for tup in prototype_locks]
if "spawn" not in locktypes:
prototype_locks.append(("spawn", "all()"))
if "edit" not in locktypes:
prototype_locks.append(("edit", "all()"))
prototype_locks = ";".join(":".join(tup) for tup in prototype_locks)
prototype['prototype_locks'] = prototype_locks