Add unittests, fix bugs
This commit is contained in:
parent
e533ceacfe
commit
e52503b710
3 changed files with 168 additions and 30 deletions
|
|
@ -177,27 +177,45 @@ def prototype_from_object(obj):
|
||||||
# first, check if this object already has a prototype
|
# first, check if this object already has a prototype
|
||||||
|
|
||||||
prot = obj.tags.get(category=_PROTOTYPE_TAG_CATEGORY, return_list=True)
|
prot = obj.tags.get(category=_PROTOTYPE_TAG_CATEGORY, return_list=True)
|
||||||
prot = protlib.search_prototype(prot)
|
if prot:
|
||||||
|
prot = protlib.search_prototype(prot[0])
|
||||||
if not prot or len(prot) > 1:
|
if not prot or len(prot) > 1:
|
||||||
# no unambiguous prototype found - build new prototype
|
# no unambiguous prototype found - build new prototype
|
||||||
prot = {}
|
prot = {}
|
||||||
prot['prototype_key'] = "From-Object-{}-{}".format(
|
prot['prototype_key'] = "From-Object-{}-{}".format(
|
||||||
obj.key, hashlib.md5(str(time.time())).hexdigest()[:6])
|
obj.key, hashlib.md5(str(time.time())).hexdigest()[:7])
|
||||||
prot['prototype_desc'] = "Built from {}".format(str(obj))
|
prot['prototype_desc'] = "Built from {}".format(str(obj))
|
||||||
prot['prototype_locks'] = "spawn:all();edit:all()"
|
prot['prototype_locks'] = "spawn:all();edit:all()"
|
||||||
|
|
||||||
prot['key'] = obj.db_key or hashlib.md5(str(time.time())).hexdigest()[:6]
|
prot['key'] = obj.db_key or hashlib.md5(str(time.time())).hexdigest()[:6]
|
||||||
prot['location'] = obj.db_location
|
|
||||||
prot['home'] = obj.db_home
|
|
||||||
prot['destination'] = obj.db_destination
|
|
||||||
prot['typeclass'] = obj.db_typeclass_path
|
prot['typeclass'] = obj.db_typeclass_path
|
||||||
prot['locks'] = obj.locks.all()
|
|
||||||
prot['permissions'] = obj.permissions.get()
|
location = obj.db_location
|
||||||
prot['aliases'] = obj.aliases.get()
|
if location:
|
||||||
prot['tags'] = [(tag.key, tag.category, tag.data)
|
prot['location'] = location
|
||||||
for tag in obj.tags.get(return_tagobj=True, return_list=True)]
|
home = obj.db_home
|
||||||
prot['attrs'] = [(attr.key, attr.value, attr.category, attr.locks)
|
if home:
|
||||||
for attr in obj.attributes.get(return_obj=True, return_list=True)]
|
prot['home'] = home
|
||||||
|
destination = obj.db_destination
|
||||||
|
if destination:
|
||||||
|
prot['destination'] = destination
|
||||||
|
locks = obj.locks.all()
|
||||||
|
if locks:
|
||||||
|
prot['locks'] = locks
|
||||||
|
perms = obj.permissions.get()
|
||||||
|
if perms:
|
||||||
|
prot['permissions'] = perms
|
||||||
|
aliases = obj.aliases.get()
|
||||||
|
if aliases:
|
||||||
|
prot['aliases'] = aliases
|
||||||
|
tags = [(tag.db_key, tag.db_category, tag.db_data)
|
||||||
|
for tag in obj.tags.get(return_tagobj=True, return_list=True) if tag]
|
||||||
|
if tags:
|
||||||
|
prot['tags'] = tags
|
||||||
|
attrs = [(attr.key, attr.value, attr.category, attr.locks.all())
|
||||||
|
for attr in obj.attributes.get(return_obj=True, return_list=True) if attr]
|
||||||
|
if attrs:
|
||||||
|
prot['attrs'] = attrs
|
||||||
|
|
||||||
return prot
|
return prot
|
||||||
|
|
||||||
|
|
@ -224,8 +242,14 @@ def prototype_diff_from_object(prototype, obj):
|
||||||
diff[key] = "KEEP"
|
diff[key] = "KEEP"
|
||||||
if key in prot2:
|
if key in prot2:
|
||||||
if callable(prot2[key]) or value != prot2[key]:
|
if callable(prot2[key]) or value != prot2[key]:
|
||||||
diff[key] = "UPDATE"
|
if key in ('attrs', 'tags', 'permissions', 'locks', 'aliases'):
|
||||||
|
diff[key] = 'REPLACE'
|
||||||
|
else:
|
||||||
|
diff[key] = "UPDATE"
|
||||||
elif key not in prot2:
|
elif key not in prot2:
|
||||||
|
diff[key] = "UPDATE"
|
||||||
|
for key in prot2:
|
||||||
|
if key not in diff and key not in prot1:
|
||||||
diff[key] = "REMOVE"
|
diff[key] = "REMOVE"
|
||||||
|
|
||||||
return diff
|
return diff
|
||||||
|
|
@ -246,25 +270,42 @@ def batch_update_objects_with_prototype(prototype, diff=None, objects=None):
|
||||||
changed (int): The number of objects that had changes applied to them.
|
changed (int): The number of objects that had changes applied to them.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
prototype_key = prototype if isinstance(prototype, basestring) else prototype['prototype_key']
|
if isinstance(prototype, basestring):
|
||||||
prototype_obj = protlib.DbPrototype.objects.filter(db_key=prototype_key)
|
new_prototype = protlib.search_prototype(prototype)
|
||||||
prototype_obj = prototype_obj[0] if prototype_obj else None
|
else:
|
||||||
new_prototype = prototype_obj.db.prototype
|
new_prototype = prototype
|
||||||
objs = ObjectDB.objects.get_by_tag(prototype_key, category=_PROTOTYPE_TAG_CATEGORY)
|
|
||||||
|
|
||||||
if not objs:
|
prototype_key = new_prototype['prototype_key']
|
||||||
|
|
||||||
|
if not objects:
|
||||||
|
objects = ObjectDB.objects.get_by_tag(prototype_key, category=_PROTOTYPE_TAG_CATEGORY)
|
||||||
|
|
||||||
|
if not objects:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if not diff:
|
if not diff:
|
||||||
diff = prototype_diff_from_object(new_prototype, objs[0])
|
diff = prototype_diff_from_object(new_prototype, objects[0])
|
||||||
|
|
||||||
changed = 0
|
changed = 0
|
||||||
for obj in objs:
|
for obj in objects:
|
||||||
do_save = False
|
do_save = False
|
||||||
|
|
||||||
|
old_prot_key = obj.tags.get(category=_PROTOTYPE_TAG_CATEGORY, return_list=True)
|
||||||
|
old_prot_key = old_prot_key[0] if old_prot_key else None
|
||||||
|
if prototype_key != old_prot_key:
|
||||||
|
obj.tags.clear(category=_PROTOTYPE_TAG_CATEGORY)
|
||||||
|
obj.tags.add(prototype_key, category=_PROTOTYPE_TAG_CATEGORY)
|
||||||
|
|
||||||
for key, directive in diff.items():
|
for key, directive in diff.items():
|
||||||
val = new_prototype[key]
|
|
||||||
if directive in ('UPDATE', 'REPLACE'):
|
if directive in ('UPDATE', 'REPLACE'):
|
||||||
|
|
||||||
|
if key in _PROTOTYPE_META_NAMES:
|
||||||
|
# prototype meta keys are not stored on-object
|
||||||
|
continue
|
||||||
|
|
||||||
|
val = new_prototype[key]
|
||||||
do_save = True
|
do_save = True
|
||||||
|
|
||||||
if key == 'key':
|
if key == 'key':
|
||||||
obj.db_key = init_spawn_value(val, str)
|
obj.db_key = init_spawn_value(val, str)
|
||||||
elif key == 'typeclass':
|
elif key == 'typeclass':
|
||||||
|
|
@ -282,19 +323,19 @@ def batch_update_objects_with_prototype(prototype, diff=None, objects=None):
|
||||||
elif key == 'permissions':
|
elif key == 'permissions':
|
||||||
if directive == 'REPLACE':
|
if directive == 'REPLACE':
|
||||||
obj.permissions.clear()
|
obj.permissions.clear()
|
||||||
obj.permissions.batch_add(init_spawn_value(val, make_iter))
|
obj.permissions.batch_add(*init_spawn_value(val, make_iter))
|
||||||
elif key == 'aliases':
|
elif key == 'aliases':
|
||||||
if directive == 'REPLACE':
|
if directive == 'REPLACE':
|
||||||
obj.aliases.clear()
|
obj.aliases.clear()
|
||||||
obj.aliases.batch_add(init_spawn_value(val, make_iter))
|
obj.aliases.batch_add(*init_spawn_value(val, make_iter))
|
||||||
elif key == 'tags':
|
elif key == 'tags':
|
||||||
if directive == 'REPLACE':
|
if directive == 'REPLACE':
|
||||||
obj.tags.clear()
|
obj.tags.clear()
|
||||||
obj.tags.batch_add(init_spawn_value(val, make_iter))
|
obj.tags.batch_add(*init_spawn_value(val, make_iter))
|
||||||
elif key == 'attrs':
|
elif key == 'attrs':
|
||||||
if directive == 'REPLACE':
|
if directive == 'REPLACE':
|
||||||
obj.attributes.clear()
|
obj.attributes.clear()
|
||||||
obj.attributes.batch_add(init_spawn_value(val, make_iter))
|
obj.attributes.batch_add(*init_spawn_value(val, make_iter))
|
||||||
elif key == 'exec':
|
elif key == 'exec':
|
||||||
# we don't auto-rerun exec statements, it would be huge security risk!
|
# we don't auto-rerun exec statements, it would be huge security risk!
|
||||||
pass
|
pass
|
||||||
|
|
@ -328,9 +369,9 @@ def batch_update_objects_with_prototype(prototype, diff=None, objects=None):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
obj.attributes.remove(key)
|
obj.attributes.remove(key)
|
||||||
if do_save:
|
if do_save:
|
||||||
changed += 1
|
changed += 1
|
||||||
obj.save()
|
obj.save()
|
||||||
|
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ Unit tests for the prototypes and spawner
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from random import randint
|
from random import randint
|
||||||
|
import mock
|
||||||
|
from anything import Anything, Something
|
||||||
from evennia.utils.test_resources import EvenniaTest
|
from evennia.utils.test_resources import EvenniaTest
|
||||||
from evennia.prototypes import spawner, prototypes as protlib
|
from evennia.prototypes import spawner, prototypes as protlib
|
||||||
|
|
||||||
|
|
@ -56,6 +58,99 @@ class TestSpawner(EvenniaTest):
|
||||||
prototype_parents=_PROTPARENTS)], ['goblin grunt', 'goblin archwizard'])
|
prototype_parents=_PROTPARENTS)], ['goblin grunt', 'goblin archwizard'])
|
||||||
|
|
||||||
|
|
||||||
|
class TestUtils(EvenniaTest):
|
||||||
|
|
||||||
|
def test_prototype_from_object(self):
|
||||||
|
self.maxDiff = None
|
||||||
|
self.obj1.attributes.add("test", "testval")
|
||||||
|
self.obj1.tags.add('foo')
|
||||||
|
new_prot = spawner.prototype_from_object(self.obj1)
|
||||||
|
self.assertEqual(
|
||||||
|
{'attrs': [('test', 'testval', None, [''])],
|
||||||
|
'home': Something,
|
||||||
|
'key': 'Obj',
|
||||||
|
'location': 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_desc': 'Built from Obj',
|
||||||
|
'prototype_key': Something,
|
||||||
|
'prototype_locks': 'spawn:all();edit:all()',
|
||||||
|
'tags': [(u'foo', None, None)],
|
||||||
|
'typeclass': 'evennia.objects.objects.DefaultObject'}, new_prot)
|
||||||
|
|
||||||
|
def test_update_objects_from_prototypes(self):
|
||||||
|
|
||||||
|
self.maxDiff = None
|
||||||
|
self.obj1.attributes.add('oldtest', 'to_remove')
|
||||||
|
|
||||||
|
old_prot = spawner.prototype_from_object(self.obj1)
|
||||||
|
|
||||||
|
# modify object away from prototype
|
||||||
|
self.obj1.attributes.add('test', 'testval')
|
||||||
|
self.obj1.aliases.add('foo')
|
||||||
|
self.obj1.key = 'NewObj'
|
||||||
|
|
||||||
|
# modify prototype
|
||||||
|
old_prot['new'] = 'new_val'
|
||||||
|
old_prot['test'] = 'testval_changed'
|
||||||
|
old_prot['permissions'] = 'Builder'
|
||||||
|
# this will not update, since we don't update the prototype on-disk
|
||||||
|
old_prot['prototype_desc'] = 'New version of prototype'
|
||||||
|
|
||||||
|
# diff obj/prototype
|
||||||
|
pdiff = spawner.prototype_diff_from_object(old_prot, self.obj1)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
pdiff,
|
||||||
|
{'aliases': 'REMOVE',
|
||||||
|
'attrs': 'REPLACE',
|
||||||
|
'home': 'KEEP',
|
||||||
|
'key': 'UPDATE',
|
||||||
|
'location': 'KEEP',
|
||||||
|
'locks': 'KEEP',
|
||||||
|
'new': 'UPDATE',
|
||||||
|
'permissions': 'UPDATE',
|
||||||
|
'prototype_desc': 'UPDATE',
|
||||||
|
'prototype_key': 'UPDATE',
|
||||||
|
'prototype_locks': 'KEEP',
|
||||||
|
'test': 'UPDATE',
|
||||||
|
'typeclass': 'KEEP'})
|
||||||
|
|
||||||
|
# apply diff
|
||||||
|
count = spawner.batch_update_objects_with_prototype(
|
||||||
|
old_prot, diff=pdiff, objects=[self.obj1])
|
||||||
|
self.assertEqual(count, 1)
|
||||||
|
|
||||||
|
new_prot = spawner.prototype_from_object(self.obj1)
|
||||||
|
self.assertEqual({'attrs': [('test', 'testval_changed', None, ['']),
|
||||||
|
('new', 'new_val', None, [''])],
|
||||||
|
'home': Something,
|
||||||
|
'key': 'Obj',
|
||||||
|
'location': 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()'],
|
||||||
|
'permissions': 'builder',
|
||||||
|
'prototype_desc': 'Built from Obj',
|
||||||
|
'prototype_key': Something,
|
||||||
|
'prototype_locks': 'spawn:all();edit:all()',
|
||||||
|
'typeclass': 'evennia.objects.objects.DefaultObject'},
|
||||||
|
new_prot)
|
||||||
|
|
||||||
|
|
||||||
class TestPrototypeStorage(EvenniaTest):
|
class TestPrototypeStorage(EvenniaTest):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@
|
||||||
|
|
||||||
django > 1.10, < 2.0
|
django > 1.10, < 2.0
|
||||||
twisted == 16.0.0
|
twisted == 16.0.0
|
||||||
mock >= 1.0.1
|
|
||||||
pillow == 2.9.0
|
pillow == 2.9.0
|
||||||
pytz
|
pytz
|
||||||
future >= 0.15.2
|
future >= 0.15.2
|
||||||
django-sekizai
|
django-sekizai
|
||||||
inflect
|
inflect
|
||||||
|
|
||||||
|
mock >= 1.0.1
|
||||||
|
anything
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue