Fix unittests

This commit is contained in:
Griatch 2018-07-21 13:40:46 +02:00
parent a721889fc1
commit a4b8b12e63
5 changed files with 128 additions and 60 deletions

View file

@ -2993,22 +2993,22 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
try: try:
prot = protlib.save_prototype(**prototype) prot = protlib.save_prototype(**prototype)
if not prot: if not prot:
caller.msg("|rError saving:|R {}.|n".format(key)) caller.msg("|rError saving:|R {}.|n".format(prototype_key))
return return
except PermissionError as err: except protlib.PermissionError as err:
caller.msg("|rError saving:|R {}|n".format(err)) caller.msg("|rError saving:|R {}|n".format(err))
return return
caller.msg("|gSaved prototype:|n {}".format(key)) caller.msg("|gSaved prototype:|n {}".format(prototype_key))
# check if we want to update existing objects # check if we want to update existing objects
existing_objects = spawner.search_objects_with_prototype(key) existing_objects = protlib.search_objects_with_prototype(prototype_key)
if existing_objects: if existing_objects:
if 'update' not in self.switches: if 'update' not in self.switches:
n_existing = len(existing_objects) n_existing = len(existing_objects)
slow = " (note that this may be slow)" if n_existing > 10 else "" slow = " (note that this may be slow)" if n_existing > 10 else ""
string = ("There are {} objects already created with an older version " string = ("There are {} objects already created with an older version "
"of prototype {}. Should it be re-applied to them{}? [Y]/N".format( "of prototype {}. Should it be re-applied to them{}? [Y]/N".format(
n_existing, key, slow)) n_existing, prototype_key, slow))
answer = yield(string) answer = yield(string)
if answer.lower() in ["n", "no"]: if answer.lower() in ["n", "no"]:
caller.msg("|rNo update was done of existing objects. " caller.msg("|rNo update was done of existing objects. "
@ -3036,7 +3036,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
return return
try: try:
success = protlib.delete_db_prototype(caller, self.args) success = protlib.delete_db_prototype(caller, self.args)
except PermissionError as err: except protlib.PermissionError as err:
caller.msg("|rError deleting:|R {}|n".format(err)) caller.msg("|rError deleting:|R {}|n".format(err))
caller.msg("Deletion {}.".format( caller.msg("Deletion {}.".format(
'successful' if success else 'failed (does the prototype exist?)')) 'successful' if success else 'failed (does the prototype exist?)'))

View file

@ -28,7 +28,7 @@ from evennia.utils import ansi, utils, gametime
from evennia.server.sessionhandler import SESSIONS from evennia.server.sessionhandler import SESSIONS
from evennia import search_object from evennia import search_object
from evennia import DefaultObject, DefaultCharacter from evennia import DefaultObject, DefaultCharacter
from evennia.prototypes import spawner, prototypes as protlib from evennia.prototypes import prototypes as protlib
# set up signal here since we are not starting the server # set up signal here since we are not starting the server
@ -46,7 +46,7 @@ class CommandTest(EvenniaTest):
Tests a command Tests a command
""" """
def call(self, cmdobj, args, msg=None, cmdset=None, noansi=True, caller=None, def call(self, cmdobj, args, msg=None, cmdset=None, noansi=True, caller=None,
receiver=None, cmdstring=None, obj=None): receiver=None, cmdstring=None, obj=None, inputs=None):
""" """
Test a command by assigning all the needed Test a command by assigning all the needed
properties to cmdobj and running properties to cmdobj and running
@ -75,14 +75,31 @@ class CommandTest(EvenniaTest):
cmdobj.obj = obj or (caller if caller else self.char1) cmdobj.obj = obj or (caller if caller else self.char1)
# test # test
old_msg = receiver.msg old_msg = receiver.msg
inputs = inputs or []
try: try:
receiver.msg = Mock() receiver.msg = Mock()
if cmdobj.at_pre_cmd(): if cmdobj.at_pre_cmd():
return return
cmdobj.parse() cmdobj.parse()
ret = cmdobj.func() ret = cmdobj.func()
# handle func's with yield in them (generators)
if isinstance(ret, types.GeneratorType): if isinstance(ret, types.GeneratorType):
ret.next() while True:
try:
inp = inputs.pop() if inputs else None
if inp:
try:
ret.send(inp)
except TypeError:
ret.next()
ret = ret.send(inp)
else:
ret.next()
except StopIteration:
break
cmdobj.at_post_cmd() cmdobj.at_post_cmd()
except StopIteration: except StopIteration:
pass pass
@ -95,7 +112,7 @@ class CommandTest(EvenniaTest):
# Get the first element of a tuple if msg received a tuple instead of a string # Get the first element of a tuple if msg received a tuple instead of a string
stored_msg = [smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg] stored_msg = [smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg]
if msg is not None: if msg is not None:
returned_msg = "||".join(_RE.sub("", mess) for mess in stored_msg) returned_msg = "||".join(_RE.sub("", str(mess)) for mess in stored_msg)
returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip()
if msg == "" and returned_msg or not returned_msg.startswith(msg.strip()): if msg == "" and returned_msg or not returned_msg.startswith(msg.strip()):
sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n" sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n"
@ -369,13 +386,13 @@ 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(),
"/save {'prototype_key': 'testprot', 'key':'Test Char', "
"'typeclass':'evennia.objects.objects.DefaultCharacter'}", "")
mock_iter.assert_called()
self.call(building.CmdSpawn(), "/list", "foo") self.call(building.CmdSpawn(),
"/save {'prototype_key': 'testprot', 'key':'Test Char', "
"'typeclass':'evennia.objects.objects.DefaultCharacter'}",
"Saved prototype: testprot", inputs=['y'])
self.call(building.CmdSpawn(), "/list", "| Key ")
self.call(building.CmdSpawn(), 'testprot', "Spawned Test Char") 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
@ -401,10 +418,14 @@ class TestBuilding(CommandTest):
goblin.delete() goblin.delete()
protlib.create_prototype(**{'key': 'Ball', 'prototype': 'GOBLIN', 'prototype_key': 'testball'}) # create prototype
protlib.create_prototype(**{'key': 'Ball',
'typeclass': 'evennia.objects.objects.DefaultCharacter',
'prototype_key': 'testball'})
# Tests "@spawn <prototype_name>" # Tests "@spawn <prototype_name>"
self.call(building.CmdSpawn(), "testball", "Spawned Ball") self.call(building.CmdSpawn(), "testball", "Spawned Ball")
ball = getObject(self, "Ball") ball = getObject(self, "Ball")
self.assertEqual(ball.location, self.char1.location) self.assertEqual(ball.location, self.char1.location)
self.assertIsInstance(ball, DefaultObject) self.assertIsInstance(ball, DefaultObject)
@ -417,10 +438,14 @@ class TestBuilding(CommandTest):
self.assertIsNone(ball.location) self.assertIsNone(ball.location)
ball.delete() ball.delete()
self.call(building.CmdSpawn(),
"/noloc {'prototype_parent':'TESTBALL', 'prototype_key': 'testball', 'location':'%s'}"
% spawnLoc.dbref, "Error: Prototype testball tries to parent itself.")
# Tests "@spawn/noloc ...", but DO specify a location. # Tests "@spawn/noloc ...", but DO specify a location.
# Location should be the specified location. # Location should be the specified location.
self.call(building.CmdSpawn(), self.call(building.CmdSpawn(),
"/noloc {'prototype':'TESTBALL', 'location':'%s'}" "/noloc {'prototype_parent':'TESTBALL', 'key': 'Ball', 'prototype_key': 'foo', 'location':'%s'}"
% spawnLoc.dbref, "Spawned Ball") % spawnLoc.dbref, "Spawned Ball")
ball = getObject(self, "Ball") ball = getObject(self, "Ball")
self.assertEqual(ball.location, spawnLoc) self.assertEqual(ball.location, spawnLoc)

View file

@ -905,19 +905,19 @@ WEAPON_PROTOTYPES = {
"magic": False, "magic": False,
"desc": "A generic blade."}, "desc": "A generic blade."},
"knife": { "knife": {
"prototype": "weapon", "prototype_parent": "weapon",
"aliases": "sword", "aliases": "sword",
"key": "Kitchen knife", "key": "Kitchen knife",
"desc": "A rusty kitchen knife. Better than nothing.", "desc": "A rusty kitchen knife. Better than nothing.",
"damage": 3}, "damage": 3},
"dagger": { "dagger": {
"prototype": "knife", "prototype_parent": "knife",
"key": "Rusty dagger", "key": "Rusty dagger",
"aliases": ["knife", "dagger"], "aliases": ["knife", "dagger"],
"desc": "A double-edged dagger with a nicked edge and a wooden handle.", "desc": "A double-edged dagger with a nicked edge and a wooden handle.",
"hit": 0.25}, "hit": 0.25},
"sword": { "sword": {
"prototype": "weapon", "prototype_parent": "weapon",
"key": "Rusty sword", "key": "Rusty sword",
"aliases": ["sword"], "aliases": ["sword"],
"desc": "A rusty shortsword. It has a leather-wrapped handle covered i food grease.", "desc": "A rusty shortsword. It has a leather-wrapped handle covered i food grease.",
@ -925,28 +925,28 @@ WEAPON_PROTOTYPES = {
"damage": 5, "damage": 5,
"parry": 0.5}, "parry": 0.5},
"club": { "club": {
"prototype": "weapon", "prototype_parent": "weapon",
"key": "Club", "key": "Club",
"desc": "A heavy wooden club, little more than a heavy branch.", "desc": "A heavy wooden club, little more than a heavy branch.",
"hit": 0.4, "hit": 0.4,
"damage": 6, "damage": 6,
"parry": 0.2}, "parry": 0.2},
"axe": { "axe": {
"prototype": "weapon", "prototype_parent": "weapon",
"key": "Axe", "key": "Axe",
"desc": "A woodcutter's axe with a keen edge.", "desc": "A woodcutter's axe with a keen edge.",
"hit": 0.4, "hit": 0.4,
"damage": 6, "damage": 6,
"parry": 0.2}, "parry": 0.2},
"ornate longsword": { "ornate longsword": {
"prototype": "sword", "prototype_parent": "sword",
"key": "Ornate longsword", "key": "Ornate longsword",
"desc": "A fine longsword with some swirling patterns on the handle.", "desc": "A fine longsword with some swirling patterns on the handle.",
"hit": 0.5, "hit": 0.5,
"magic": True, "magic": True,
"damage": 5}, "damage": 5},
"warhammer": { "warhammer": {
"prototype": "club", "prototype_parent": "club",
"key": "Silver Warhammer", "key": "Silver Warhammer",
"aliases": ["hammer", "warhammer", "war"], "aliases": ["hammer", "warhammer", "war"],
"desc": "A heavy war hammer with silver ornaments. This huge weapon causes massive damage - if you can hit.", "desc": "A heavy war hammer with silver ornaments. This huge weapon causes massive damage - if you can hit.",
@ -954,21 +954,21 @@ WEAPON_PROTOTYPES = {
"magic": True, "magic": True,
"damage": 8}, "damage": 8},
"rune axe": { "rune axe": {
"prototype": "axe", "prototype_parent": "axe",
"key": "Runeaxe", "key": "Runeaxe",
"aliases": ["axe"], "aliases": ["axe"],
"hit": 0.4, "hit": 0.4,
"magic": True, "magic": True,
"damage": 6}, "damage": 6},
"thruning": { "thruning": {
"prototype": "ornate longsword", "prototype_parent": "ornate longsword",
"key": "Broadsword named Thruning", "key": "Broadsword named Thruning",
"desc": "This heavy bladed weapon is marked with the name 'Thruning'. It is very powerful in skilled hands.", "desc": "This heavy bladed weapon is marked with the name 'Thruning'. It is very powerful in skilled hands.",
"hit": 0.6, "hit": 0.6,
"parry": 0.6, "parry": 0.6,
"damage": 7}, "damage": 7},
"slayer waraxe": { "slayer waraxe": {
"prototype": "rune axe", "prototype_parent": "rune axe",
"key": "Slayer waraxe", "key": "Slayer waraxe",
"aliases": ["waraxe", "war", "slayer"], "aliases": ["waraxe", "war", "slayer"],
"desc": "A huge double-bladed axe marked with the runes for 'Slayer'." "desc": "A huge double-bladed axe marked with the runes for 'Slayer'."
@ -976,7 +976,7 @@ WEAPON_PROTOTYPES = {
"hit": 0.7, "hit": 0.7,
"damage": 8}, "damage": 8},
"ghostblade": { "ghostblade": {
"prototype": "ornate longsword", "prototype_parent": "ornate longsword",
"key": "The Ghostblade", "key": "The Ghostblade",
"aliases": ["blade", "ghost"], "aliases": ["blade", "ghost"],
"desc": "This massive sword is large as you are tall, yet seems to weigh almost nothing." "desc": "This massive sword is large as you are tall, yet seems to weigh almost nothing."
@ -985,7 +985,7 @@ WEAPON_PROTOTYPES = {
"parry": 0.8, "parry": 0.8,
"damage": 10}, "damage": 10},
"hawkblade": { "hawkblade": {
"prototype": "ghostblade", "prototype_parent": "ghostblade",
"key": "The Hawkblade", "key": "The Hawkblade",
"aliases": ["hawk", "blade"], "aliases": ["hawk", "blade"],
"desc": "The weapon of a long-dead heroine and a more civilized age," "desc": "The weapon of a long-dead heroine and a more civilized age,"

View file

@ -13,7 +13,7 @@ from evennia.objects.models import ObjectDB
from evennia.utils.create import create_script from evennia.utils.create import create_script
from evennia.utils.utils import ( from evennia.utils.utils import (
all_from_module, make_iter, is_iter, dbid_to_obj, callables_from_module, all_from_module, make_iter, is_iter, dbid_to_obj, callables_from_module,
get_all_typeclasses, to_str) get_all_typeclasses, to_str, dbref)
from evennia.locks.lockhandler import validate_lockstring, check_lockstring from evennia.locks.lockhandler import validate_lockstring, check_lockstring
from evennia.utils import logger from evennia.utils import logger
from evennia.utils import inlinefuncs from evennia.utils import inlinefuncs
@ -91,6 +91,10 @@ def protfunc_parser(value, available_functions=None, testing=False, stacktrace=F
""" """
if not isinstance(value, basestring): if not isinstance(value, basestring):
try:
value = value.dbref
except AttributeError:
pass
value = to_str(value, force_string=True) value = to_str(value, force_string=True)
available_functions = _PROT_FUNCS if available_functions is None else available_functions available_functions = _PROT_FUNCS if available_functions is None else available_functions
@ -577,7 +581,7 @@ def validate_prototype(prototype, protkey=None, protparents=None,
for protstring in make_iter(prototype_parent): for protstring in make_iter(prototype_parent):
protstring = protstring.lower() protstring = protstring.lower()
if protkey is not None and protstring == protkey: if protkey is not None and protstring == protkey:
_flags['errors'].append("Protototype {} tries to parent itself.".format(protkey)) _flags['errors'].append("Prototype {} tries to parent itself.".format(protkey))
protparent = protparents.get(protstring) protparent = protparents.get(protstring)
if not protparent: if not protparent:
_flags['errors'].append("Prototype {}'s prototype_parent '{}' was not found.".format( _flags['errors'].append("Prototype {}'s prototype_parent '{}' was not found.".format(
@ -610,7 +614,7 @@ def validate_prototype(prototype, protkey=None, protparents=None,
# make sure prototype_locks are set to defaults # make sure prototype_locks are set to defaults
prototype_locks = [lstring.split(":", 1) prototype_locks = [lstring.split(":", 1)
for lstring in prototype.get("prototype_locks", "").split(';')] for lstring in prototype.get("prototype_locks", "").split(';') if ":" in lstring]
locktypes = [tup[0].strip() for tup in prototype_locks] locktypes = [tup[0].strip() for tup in prototype_locks]
if "spawn" not in locktypes: if "spawn" not in locktypes:
prototype_locks.append(("spawn", "all()")) prototype_locks.append(("spawn", "all()"))

View file

@ -114,24 +114,41 @@ class TestUtils(EvenniaTest):
self.assertEqual( self.assertEqual(
pdiff, pdiff,
{'aliases': 'REMOVE', ({'aliases': 'REMOVE',
'attrs': 'REPLACE', 'attrs': 'REPLACE',
'home': 'KEEP', 'home': 'KEEP',
'key': 'UPDATE', 'key': 'UPDATE',
'location': 'KEEP', 'location': 'KEEP',
'locks': 'KEEP', 'locks': 'KEEP',
'new': 'UPDATE', 'new': 'UPDATE',
'permissions': 'UPDATE', 'permissions': 'UPDATE',
'prototype_desc': 'UPDATE', 'prototype_desc': 'UPDATE',
'prototype_key': 'UPDATE', 'prototype_key': 'UPDATE',
'prototype_locks': 'KEEP', 'prototype_locks': 'KEEP',
'prototype_tags': 'KEEP', 'prototype_tags': 'KEEP',
'test': 'UPDATE', 'test': 'UPDATE',
'typeclass': 'KEEP'}) 'typeclass': 'KEEP'},
{'attrs': [('oldtest', 'to_remove', None, ['']),
('test', 'testval', None, [''])],
'prototype_locks': 'spawn:all();edit:all()',
'prototype_key': Something,
'locks': ['call:true()', 'control:perm(Developer)',
'delete:perm(Admin)', 'edit:perm(Admin)',
'examine:perm(Builder)', 'get:all()',
'puppet:pperm(Developer)', 'tell:perm(Admin)',
'view:all()'],
'prototype_tags': [],
'location': self.room1,
'key': 'NewObj',
'home': self.room1,
'typeclass': 'evennia.objects.objects.DefaultObject',
'prototype_desc': 'Built from NewObj',
'aliases': 'foo'})
)
# apply diff # apply diff
count = spawner.batch_update_objects_with_prototype( count = spawner.batch_update_objects_with_prototype(
old_prot, diff=pdiff, objects=[self.obj1]) old_prot, diff=pdiff[0], objects=[self.obj1])
self.assertEqual(count, 1) self.assertEqual(count, 1)
new_prot = spawner.prototype_from_object(self.obj1) new_prot = spawner.prototype_from_object(self.obj1)
@ -470,7 +487,7 @@ class TestOLCMenu(TestEvMenu):
menutree = "evennia.prototypes.menus" menutree = "evennia.prototypes.menus"
startnode = "node_index" startnode = "node_index"
debug_output = True # debug_output = True
expect_all_nodes = True expect_all_nodes = True
expected_node_texts = { expected_node_texts = {
@ -480,15 +497,37 @@ class TestOLCMenu(TestEvMenu):
expected_tree = \ expected_tree = \
['node_index', ['node_index',
['node_prototype_key', ['node_prototype_key',
['node_index',
'node_index',
'node_validate_prototype',
['node_index'],
'node_index'],
'node_typeclass', 'node_typeclass',
'node_aliases', ['node_key',
'node_attrs', ['node_typeclass',
'node_tags', 'node_key',
'node_locks', 'node_index',
'node_permissions', 'node_validate_prototype',
'node_location', 'node_validate_prototype'],
'node_home', 'node_index',
'node_destination', 'node_index',
'node_prototype_desc', 'node_index',
'node_prototype_tags', 'node_validate_prototype',
'node_prototype_locks']] 'node_validate_prototype'],
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype',
'node_validate_prototype']]