1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
|
"""Wizard tests from petrounias.org
http://www.petrounias.org/articles/2014/09/16/pickling-python-collections-with-non-built-in-type-keys-and-cycles/
Includes functionality to assist with adding compatibility to jsonpickle.
"""
from __future__ import absolute_import, division, unicode_literals
import collections
import unittest
from jsonpickle import decode, encode
class World(object):
def __init__(self):
self.wizards = []
class Wizard(object):
def __init__(self, world, name):
self.name = name
self.spells = collections.OrderedDict()
world.wizards.append(self)
def __cmp__(self, other):
for (ka, va), (kb, vb) in zip(self.spells.items(), other.spells.items()):
cmp_name = cmp(ka.name, kb.name) # noqa: F821
if cmp_name != 0:
print('Wizards cmp: %s != %s' % (ka.name, kb.name))
return cmp_name
for sa, sb in zip(va, vb):
cmp_spell = cmp(sa, sb) # noqa: F821
if cmp_spell != 0:
print('Spells cmp: %s != %s' % (sa.name, sb.name))
return cmp_spell
return cmp(self.name, other.name) # noqa: F821
def __eq__(self, other):
for (ka, va), (kb, vb) in zip(self.spells.items(), other.spells.items()):
if ka.name != kb.name:
print('Wizards differ: %s != %s' % (ka.name, kb.name))
return False
for sa, sb in zip(va, vb):
if sa != sb:
print('Spells differ: %s != %s' % (sa.name, sb.name))
return False
return self.name == other.name
def __hash__(self):
return hash('Wizard %s' % self.name)
class Spell(object):
def __init__(self, caster, target, name):
self.caster = caster
self.target = target
self.name = name
try:
spells = caster.spells[target]
except KeyError:
spells = caster.spells[target] = []
spells.append(self)
def __cmp__(self, other):
return (
cmp(self.name, other.name) # noqa: F821
or cmp(self.caster.name, other.caster.name) # noqa: F821
or cmp(self.target.name, other.target.name) # noqa: F821
) # noqa: F821
def __eq__(self, other):
return (
self.name == other.name
and self.caster.name == other.caster.name
and self.target.name == other.target.name
)
def __hash__(self):
return hash(
'Spell %s by %s on %s' % (self.name, self.caster.name, self.target.name)
)
def hashsum(items):
return sum([hash(x) for x in items])
def compare_spells(a, b):
for (ka, va), (kb, vb) in zip(a.items(), b.items()):
if ka != kb:
print('Keys differ: %s != %s' % (ka, kb))
return False
return True
class MagicTestCase(unittest.TestCase):
def test_without_pickling(self):
world = World()
wizard_merlin = Wizard(world, 'Merlin')
wizard_morgana = Wizard(world, 'Morgana')
spell_a = Spell(wizard_merlin, wizard_morgana, 'magic-missile')
spell_b = Spell(wizard_merlin, wizard_merlin, 'stone-skin')
spell_c = Spell(wizard_morgana, wizard_merlin, 'geas')
self.assertEqual(wizard_merlin.spells[wizard_morgana][0], spell_a)
self.assertEqual(wizard_merlin.spells[wizard_merlin][0], spell_b)
self.assertEqual(wizard_morgana.spells[wizard_merlin][0], spell_c)
# Merlin has cast Magic Missile on Morgana, and Stone Skin on himself
self.assertEqual(wizard_merlin.spells[wizard_morgana][0].name, 'magic-missile')
self.assertEqual(wizard_merlin.spells[wizard_merlin][0].name, 'stone-skin')
# Morgana has cast Geas on Merlin
self.assertEqual(wizard_morgana.spells[wizard_merlin][0].name, 'geas')
# Merlin's first target was Morgana
merlin_spells = wizard_merlin.spells
merlin_spells_keys = list(merlin_spells.keys())
self.assertTrue(merlin_spells_keys[0] in wizard_merlin.spells)
self.assertEqual(merlin_spells_keys[0], wizard_morgana)
# Merlin's second target was himself
self.assertTrue(merlin_spells_keys[1] in wizard_merlin.spells)
self.assertEqual(merlin_spells_keys[1], wizard_merlin)
# Morgana's first target was Merlin
morgana_spells_keys = list(wizard_morgana.spells.keys())
self.assertTrue(morgana_spells_keys[0] in wizard_morgana.spells)
self.assertEqual(morgana_spells_keys[0], wizard_merlin)
# Merlin's first spell cast with himself as target is in the dictionary,
# first by looking up directly with Merlin's instance object...
self.assertEqual(wizard_merlin, wizard_merlin.spells[wizard_merlin][0].target)
# ...and then with the instance object directly from the dictionary keys
self.assertEqual(wizard_merlin, merlin_spells[merlin_spells_keys[1]][0].target)
# Ensure Merlin's object is unique...
self.assertEqual(id(wizard_merlin), id(merlin_spells_keys[1]))
# ...and consistently hashed
self.assertEqual(hash(wizard_merlin), hash(merlin_spells_keys[1]))
def test_with_pickling(self):
world = World()
wizard_merlin = Wizard(world, 'Merlin')
wizard_morgana = Wizard(world, 'Morgana')
wizard_morgana_prime = Wizard(world, 'Morgana')
self.assertEqual(wizard_morgana.__dict__, wizard_morgana_prime.__dict__)
spell_a = Spell(wizard_merlin, wizard_morgana, 'magic-missile')
spell_b = Spell(wizard_merlin, wizard_merlin, 'stone-skin')
spell_c = Spell(wizard_morgana, wizard_merlin, 'geas')
self.assertEqual(wizard_merlin.spells[wizard_morgana][0], spell_a)
self.assertEqual(wizard_merlin.spells[wizard_merlin][0], spell_b)
self.assertEqual(wizard_morgana.spells[wizard_merlin][0], spell_c)
flat_world = encode(world, keys=True)
u_world = decode(flat_world, keys=True)
u_wizard_merlin = u_world.wizards[0]
u_wizard_morgana = u_world.wizards[1]
morgana_spells_encoded = encode(wizard_morgana.spells, keys=True)
morgana_spells_decoded = decode(morgana_spells_encoded, keys=True)
self.assertEqual(wizard_morgana.spells, morgana_spells_decoded)
morgana_encoded = encode(wizard_morgana, keys=True)
morgana_decoded = decode(morgana_encoded, keys=True)
self.assertEqual(wizard_morgana, morgana_decoded)
self.assertEqual(hash(wizard_morgana), hash(morgana_decoded))
self.assertEqual(wizard_morgana.spells, morgana_decoded.spells)
# Merlin has cast Magic Missile on Morgana, and Stone Skin on himself
merlin_spells = u_wizard_merlin.spells
self.assertEqual(merlin_spells[u_wizard_morgana][0].name, 'magic-missile')
self.assertEqual(merlin_spells[u_wizard_merlin][0].name, 'stone-skin')
# Morgana has cast Geas on Merlin
self.assertEqual(u_wizard_morgana.spells[u_wizard_merlin][0].name, 'geas')
# Merlin's first target was Morgana
merlin_spells_keys = list(u_wizard_merlin.spells.keys())
self.assertTrue(merlin_spells_keys[0] in u_wizard_merlin.spells)
self.assertEqual(merlin_spells_keys[0], u_wizard_morgana)
# Merlin's second target was himself
self.assertTrue(merlin_spells_keys[1] in u_wizard_merlin.spells)
self.assertEqual(merlin_spells_keys[1], u_wizard_merlin)
# Morgana's first target was Merlin
morgana_spells_keys = list(u_wizard_morgana.spells.keys())
self.assertTrue(morgana_spells_keys[0] in u_wizard_morgana.spells)
self.assertEqual(morgana_spells_keys[0], u_wizard_merlin)
# Merlin's first spell cast with himself as target is in the dict.
# First try the lookup with Merlin's instance object
self.assertEqual(u_wizard_merlin, merlin_spells[u_wizard_merlin][0].target)
# Next try the lookup with the object from the dictionary keys.
self.assertEqual(
u_wizard_merlin, merlin_spells[merlin_spells_keys[1]][0].target
)
# Ensure Merlin's object is unique and consistently hashed.
self.assertEqual(id(u_wizard_merlin), id(merlin_spells_keys[1]))
self.assertEqual(hash(u_wizard_merlin), hash(merlin_spells_keys[1]))
if __name__ == '__main__':
unittest.main()
|