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
|
"""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.
"""
import collections
from jsonpickle import decode, encode
class World:
def __init__(self):
self.wizards = []
class Wizard:
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(f'Wizards cmp: {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(f'Spells cmp: {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(f'Wizards differ: {ka.name} != {kb.name}')
return False
for sa, sb in zip(va, vb):
if sa != sb:
print(f'Spells differ: {sa.name} != {sb.name}')
return False
return self.name == other.name
def __hash__(self):
return hash('Wizard %s' % self.name)
class Spell:
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(f'Spell {self.name} by {self.caster.name} on {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(f'Keys differ: {ka} != {kb}')
return False
return True
def test_without_pickling():
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')
assert wizard_merlin.spells[wizard_morgana][0] == spell_a
assert wizard_merlin.spells[wizard_merlin][0] == spell_b
assert wizard_morgana.spells[wizard_merlin][0] == spell_c
# Merlin has cast Magic Missile on Morgana, and Stone Skin on himself
assert wizard_merlin.spells[wizard_morgana][0].name == 'magic-missile'
assert wizard_merlin.spells[wizard_merlin][0].name == 'stone-skin'
# Morgana has cast Geas on Merlin
assert 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())
assert merlin_spells_keys[0] in wizard_merlin.spells
assert merlin_spells_keys[0] == wizard_morgana
# Merlin's second target was himself
assert merlin_spells_keys[1] in wizard_merlin.spells
assert merlin_spells_keys[1] == wizard_merlin
# Morgana's first target was Merlin
morgana_spells_keys = list(wizard_morgana.spells.keys())
assert morgana_spells_keys[0] in wizard_morgana.spells
assert 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...
assert wizard_merlin == wizard_merlin.spells[wizard_merlin][0].target
# ...and then with the instance object directly from the dictionary keys
assert wizard_merlin == merlin_spells[merlin_spells_keys[1]][0].target
# Ensure Merlin's object is unique...
assert id(wizard_merlin) == id(merlin_spells_keys[1])
# ...and consistently hashed
assert hash(wizard_merlin) == hash(merlin_spells_keys[1])
def test_with_pickling():
world = World()
wizard_merlin = Wizard(world, 'Merlin')
wizard_morgana = Wizard(world, 'Morgana')
wizard_morgana_prime = Wizard(world, 'Morgana')
assert 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')
assert wizard_merlin.spells[wizard_morgana][0] == spell_a
assert wizard_merlin.spells[wizard_merlin][0] == spell_b
assert 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)
assert wizard_morgana.spells == morgana_spells_decoded
morgana_encoded = encode(wizard_morgana, keys=True)
morgana_decoded = decode(morgana_encoded, keys=True)
assert wizard_morgana == morgana_decoded
assert hash(wizard_morgana) == hash(morgana_decoded)
assert wizard_morgana.spells == morgana_decoded.spells
# Merlin has cast Magic Missile on Morgana, and Stone Skin on himself
merlin_spells = u_wizard_merlin.spells
assert merlin_spells[u_wizard_morgana][0].name == 'magic-missile'
assert merlin_spells[u_wizard_merlin][0].name == 'stone-skin'
# Morgana has cast Geas on Merlin
assert 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())
assert merlin_spells_keys[0] in u_wizard_merlin.spells
assert merlin_spells_keys[0] == u_wizard_morgana
# Merlin's second target was himself
assert merlin_spells_keys[1] in u_wizard_merlin.spells
assert merlin_spells_keys[1] == u_wizard_merlin
# Morgana's first target was Merlin
morgana_spells_keys = list(u_wizard_morgana.spells.keys())
assert morgana_spells_keys[0] in u_wizard_morgana.spells
assert 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
assert u_wizard_merlin == merlin_spells[u_wizard_merlin][0].target
# Next try the lookup with the object from the dictionary keys.
assert u_wizard_merlin == merlin_spells[merlin_spells_keys[1]][0].target
# Ensure Merlin's object is unique and consistently hashed.
assert id(u_wizard_merlin) == id(merlin_spells_keys[1])
assert hash(u_wizard_merlin) == hash(merlin_spells_keys[1])
|