from guppy.heapy.test import support import textwrap PORTABLE_TEST = 1 # Relax tests to be more portable class TestCase(support.TestCase): def setUp(self): support.TestCase.setUp(self) self.View.is_rg_update_all = False self.US = US = self.heapy.UniSet self.Use = Use = self.heapy.Use Use.reprefix = 'hp.' self.do = lambda x: x.dictof self.un = Use.Anything.fam self.ty = Use.Type self.rc = Use.Rcs self.iso = Use.iso self.Anything = US.Anything self.Nothing = US.Nothing class C1: def x(self): return 0 class C2: pass c1 = C1() self.C1 = C1 self.C2 = C2 self.c1 = c1 def lt(self, a, b): self.assertTrue(a < b) def eq(self, a, b): self.assertTrue(a == b) def dj(self, a, b): # disjoint; not related by <= or >=, and not overlapping self.assertTrue(not a <= b) self.assertTrue(not b <= a) self.assertTrue(not a & b) self.assertTrue(a.disjoint(b)) def nr(self, a, b): # not related by <= or >=, and overlapping self.assertTrue(not a <= b) self.assertTrue(not b <= a) self.assertTrue(a & b) self.assertTrue(not a.disjoint(b)) class SpecialCases(TestCase): # Special tests that catch cases that came up during development & debugging def test_1(self): un = self.un ty = self.ty do = self.do rc = self.rc iso = self.iso All = self.Anything Nothing = self.Nothing C1 = self.C1 C2 = self.C2 c1 = self.c1 def eq(a, b): self.assertTrue(a == b) self.assertTrue(str(a) == str(b)) e1 = [] e2 = {} e3 = [] e4 = () a = ty(int) b = ty(dict) self.assertTrue(~a & ~b != Nothing) eq(ty(list) & iso(e1, e2, e3), iso(e1, e3)) eq((ty(list) | ty(dict)) & iso(e1, e2, e3, e4), iso(e1, e2, e3)) eq(iso(e1, e3) | ty(list), ty(list)) eq(ty(list) | iso(e1, e3), ty(list)) eq(iso(e1, e3) - iso(e3), iso(e1)) eq(~iso(e3) & iso(e1, e3), iso(e1)) eq(iso(e1, e2, e3) - ty(dict), iso(e1, e3)) eq(~ty(dict) & iso(e1, e2, e3), iso(e1, e3)) eq(ty(dict) | iso(e1, e2), ty(dict) | iso(e1)) eq(iso(e1, e2) | ty(dict), ty(dict) | iso(e1)) eq((ty(dict) | ty(tuple)) | iso(e1, e2), (ty(dict) | ty(tuple)) | iso(e1)) eq(iso(e1, e2) | (ty(dict) | ty(tuple)), (ty(dict) | ty(tuple)) | iso(e1)) eq(~ty(dict) | iso(e1, e2), ~ty(dict) | iso(e2)) eq(iso(e1, e2) | ~ty(dict), ~ty(dict) | iso(e2)) eq(ty(dict) - iso(e1, e2), ty(dict) - iso(e2)) eq(~iso(e1, e2) & ty(dict), ty(dict) - iso(e2)) eq(iso(e1, e3) ^ iso(e2), iso(e1, e2, e3)) eq(iso(e1, e3) ^ iso(e2, e3), iso(e1, e2)) eq(iso(e1, e3) ^ iso(e1, e3), Nothing) eq(iso(e1, e3) <= ty(list), True) eq(iso(e1, e2) <= ty(list) | ty(dict), True) eq(ty(list) >= iso(e1, e3), True) eq(ty(list) | ty(dict) >= iso(e1, e2), True) def test_2(self): un = self.un ty = self.ty do = self.do rc = self.rc iso = self.iso All = self.Anything Nothing = self.Nothing C1 = self.C1 C2 = self.C2 c1 = self.c1 class C3(object): def x(self): return 1 def asrt(x): self.assertTrue(x) def no(x): self.assertTrue(not x) eq = self.aseq # Tests to do with Nothing being finite - having length and iteration no(dict in (ty(dict) | ty(int))) no([] in (ty(dict) | ty(int))) asrt({} in (ty(dict) | ty(int))) asrt(dict in (ty(dict) | ty(int) | ty(type(dict)))) asrt(list(ty(list) & iso({})) == []) # When creating ISO classes, we don't want to memoize them # which would leak the elements. from sys import getrefcount as grc import sys import types c = C1() rc = grc(c) x = iso(c) x = None eq(grc(c), rc) def test_dictowner(self): # Special test for dict ownership # motivated by: dicts that are not found in traversal, should not # cause repeated (unsuccessfull) updates of dict ownership # This is a performance question, requires special kind of testing # # Also tests that dict & dict owners are not leaked import gc from sys import getrefcount as grc Use = self.Use C1 = self.C1 c1 = self.c1 iso = self.iso o = self.python.io.StringIO() # Create a dict hidden from view d1 = self.View.immnodeset([{}]) d3 = {} # Remember the initial ref counts for target objects gc.collect() rcd1 = grc(list(d1)[0]) rcd3 = grc(d3) rcC1 = grc(C1) rcc1 = grc(c1) rcdc1 = grc(c1.__dict__) clock = self.python.time.process_time N = 5 M = 50 # This was the fast case, when only reachable dicts are classified for i in range(N): print(iso(d3).kind, file=o) print(iso(c1.__dict__).kind, file=o) # Now measure it while 1: gc.collect() t = clock() for i in range(M): iso(d3).kind iso(c1.__dict__).kind fast = clock()-t if fast >= 0.5: # Enough resolution? break else: M *= 2 # No, try more loops # This was a slow case; involving repeated classification of a unreachable dict # It was originally 4.97 times slower when N was 5 # The problem occurs for successive classifications of different dicts, # when at least one of them is unreachable. gc.collect() for i in range(N): print(iso(*d1).kind, file=o) print(iso(c1.__dict__).kind, file=o) gc.collect() # Now measure it t = clock() for i in range(M): iso(*d1).kind iso(c1.__dict__).kind slow = clock()-t self.assertTrue(slow <= 1.5*fast) # This is another slow case according to notes Nov 18 2004. # A succession of different unreachable dicts. gc.collect() dn = self.View.immnodeset([{} for i in range(N)]) for i in range(N): print(iso(list(dn)[i]).kind, file=o) # Now measure it gc.collect() dn = self.View.immnodeset([{} for i in range(M)]) t = clock() for i in range(M): iso(list(dn)[i]).kind slow = clock()-t # Sometimes M might be huge, and the vast majority of time it is not # doing the classification. # self.assertTrue(slow <= 1.5*fast) # Partition was likewise slow for unreachable dicts dn = self.View.immnodeset([{} for i in range(N)]) gc.collect() print([x[0] for x in Use.Clodo.classifier.partition(dn)], file=o) # Now measure it dn = self.View.immnodeset([{} for i in range(M)]) gc.collect() t = clock() [x[0] for x in Use.Clodo.classifier.partition(dn)] slow = clock()-t self.assertTrue(slow <= 1.5*fast) # Check that ref counts for target objects are the same as initially gc.collect() gc.collect() # Note May 17 2005 self.aseq(grc(list(d1)[0]), rcd1) self.aseq(grc(d3), rcd3) self.aseq(grc(c1), rcc1) self.aseq(grc(C1), rcC1) self.aseq(grc(c1.__dict__), rcdc1) self.aseq(o.getvalue(), """\ dict (no owner) dict of .C1 dict (no owner) dict of .C1 dict (no owner) dict of .C1 dict (no owner) dict of .C1 dict (no owner) dict of .C1 dict (no owner) dict of .C1 dict (no owner) dict of .C1 dict (no owner) dict of .C1 dict (no owner) dict of .C1 dict (no owner) dict of .C1 dict (no owner) dict (no owner) dict (no owner) dict (no owner) dict (no owner) [hp.Nothing.dictof] """.replace('', self.__module__)) def test_retclaset(self): # Test (A) that referrer classifications don't leak their classes # and (B) that selection is not disturbed by list arguments # (This is removed since it doesnt always work) # and (C) that selection does update referrer graph correctly self.__module__ = '' # Make the rendering independent on our name from sys import getrefcount as grc import gc C1 = self.C1 c1 = self.c1 iso = self.iso rcC1 = grc(C1) o = self.python.io.StringIO() print(iso(C1).byrcs.kind, file=o) s = iso(c1).byrcs.kind print(s, file=o) self.aseq(s & iso(c1), iso(c1)) x = C1() self.aseq(s & iso(c1, x), iso(c1)) s = iso(x).byrcs.kind self.aseq(s & iso(c1, x), iso(x)) x = C1() # (C) make sure referrer graph is updated by select self.aseq(s & iso(c1, x), iso(x)) s = None x = None gc.collect() gc.collect() # Note May 17 2005 self.aseq(grc(C1), rcC1) # (A) def test_alt_retclaset(self): # Test the alternative referrer memo update # On low level, and the speed of selection import gc iso = self.iso a = [] b = self.View.immnodeset([[]]) x = [a, b] hv = self.View.hv rg = self.View.nodegraph() gc.collect() hv.update_referrers_completely(rg) self.assertTrue(x in rg[a]) self.assertTrue(rg[list(b)[0]] == (None,)) rg.clear() rg = None # Test View functionality self.View.is_rg_update_all = True gc.collect() iso(a).referrers self.assertTrue(a in self.View.rg.get_domain()) self.assertTrue(list(b)[0] in self.View.rg.get_domain()) clock = self.python.time.process_time s = iso(a) N = 1000 while 1: t = clock() for i in range(N): s.referrers fast = clock()-t if fast >= 0.5: break N *= 2 # CPU is too fast to get good resolution, try more loops t = clock() for i in range(N): self.View.rg.domain_covers([a]) self.View.rg[a] faster = clock()-t s = iso(*b) t = clock() for i in range(N): s.referrers slow = clock() - t self.assertTrue(not slow > fast * 4) def test_via(self, vlist=['v', ]): # vlist is just to make v unoptimizable # Special tests for the via classifier from sys import getrefcount as grc import gc iso = self.iso hp = self.Use d = {} k = ('k',) v = tuple(vlist) # Make sure v is not optimized to a constant d[k] = v d[v] = v rck = grc(k) rcv = grc(v) s = iso(v) self.assertTrue(s.byvia.kind == hp.Via("_.f_locals['v']", "_[('k',)]", "_[('v',)]", '_.keys()[1]') or s.byvia.kind == hp.Via("_.f_locals['v']", "_[('k',)]", "_[('v',)]", '_.keys()[0]')) del s gc.collect() gc.collect() self.aseq(grc(k), rck) self.aseq(grc(v), rcv) class RenderCase(TestCase): def test_rendering(self): import sys import types iso = self.iso C1 = self.C1 c1 = self.c1 class C3(object): def x(self): return 1 e1 = [] e2 = {} e3 = [] o = self.python.io.StringIO() # str'ing of homogenous & inhoumogenous values self.US.summary_str.str_address = lambda x: '
' def ps(x): print(x.brief, file=o) ps(iso(1, 2)) ps(iso(1, 2.0, 3.0)) ps(iso(e1)) ps(iso(e1, e2)) ps(iso(e1, e3)) ps(iso(self.python.builtins.TypeError())) # ps(iso(type('MetaType', (type,), {})('MetaTypeIns', (), {}))) ps(iso(None)) ps(iso(sys, support, types)) ps(iso(int, type, C3)) ps(iso(C1())) ps(iso(C3())) ps(iso(C1)) ps(iso(C3)) ps(iso(len)) ps(iso(self.setUp)) ps(iso(C1.x)) ps(iso(C1().x)) ps(iso(C3.x)) ps(iso(C3().x)) ps(iso({})) ps(iso(c1.__dict__)) ps(iso(types.__dict__)) try: 1/0 except ZeroDivisionError: typ, value, traceback = sys.exc_info() ps(iso(traceback)) ps(iso(traceback.tb_frame)) expected = textwrap.dedent("""\ <2 int: 1, 2> <3 (float | int): <2 float: 2.0, 3.0> | <1 int: 1>> <1 list:
*0> <2 (dict (no owner) | list): <1 dict (no owner):
*0> | <1 list: <2 list:
*0,
*0> <1 TypeError:
> <1 builtins.NoneType: None> <3 module: guppy.heapy.test.support, sys, types> <3 type: .C3, int, type> <1 .C1:
> <1 .C3:
> <1 type: .C1> <1 type: .C3> <1 types.BuiltinMethodType: len> <1 types.MethodType: <.RenderCase at <1 function: .x> <1 types.MethodType: <.C1 at
>.x> <1 function: .x> <1 types.MethodType: <.C3 at
>.x> <1 dict (no owner):
*0> <1 dict of .C1:
> <1 dict of module: types> <1 types.TracebackType: > at
>> <1 types.FrameType: >> """) expected = expected.replace('', self.__module__) if self.version_info >= (3, 10): expected = expected.replace('builtins.NoneType', 'types.NoneType') self.aseq(o.getvalue(), expected) if PORTABLE_TEST: return o = self.python.io.StringIO() # The following is nonportable, sizes may change # In particular, the list size changed from 2.3 to 2.4 # The following test is only for 2.3 in 32-bit python # pp'ing prints in a nice form # This tests all types currently defined in Classifiers.Summary_str # and then some # Except: frametype; its size varies from time to time! x = iso(len, C1, 1.0+3j, {1: 2, 3: 4}, 1.25, C1.x.__func__, 1, ['list'], 100000000000, None, C1.x, C1().x, C3.x, C3().x, sys, support, 'string', ('tuple',), C3, int, type(None), # and some types not defined C1(), C3(), c1.__dict__ ) print(x, file=o) print(x.more, file=o) # Test instancetype; we need to replace the classifier with bytype x = iso(C1()).bytype print(x, file=o) expected = """\ Partition of a set of 24 objects. Total size = 2128 bytes. Index Count % Size % Cumulative % Kind (class / dict of class) 0 3 12 1272 60 1272 60 type 1 4 17 144 7 1416 67 types.MethodType 2 1 4 136 6 1552 73 dict (no owner) 3 1 4 136 6 1688 79 dict of .C1 4 1 4 60 3 1748 82 list 5 1 4 56 3 1804 85 function 6 2 8 48 2 1852 87 module 7 1 4 44 2 1896 89 class 8 1 4 32 2 1928 91 .C1 9 1 4 32 2 1960 92 str <8 more rows. Type e.g. '_.more' to view.> Index Count % Size % Cumulative % Kind (class / dict of class) 10 1 4 32 2 1992 94 types.BuiltinMethodType 11 1 4 28 1 2020 95 .C3 12 1 4 28 1 2048 96 tuple 13 1 4 24 1 2072 97 complex 14 1 4 20 1 2092 98 long 15 1 4 16 1 2108 99 float 16 1 4 12 1 2120 100 int 17 1 4 8 0 2128 100 types.NoneType Partition of a set of 1 object. Total size = 32 bytes. Index Count % Size % Cumulative % Type 0 1 100 32 100 32 100 types.InstanceType """.replace('', self.__module__) self.aseq(o.getvalue(), expected) class BaseCase(TestCase): def test_minmax(self): s = self.guppy.sets.immbitset min = self.US.minimals max = self.US.maximals self.aseq(min([]), []) self.aseq(min([1]), [1]) self.aseq(min([1, 1]), [1]) self.aseq(min([1, 2]), [1]) self.aseq(min([[], []]), [[]]) self.aseq(min([s([1]), s([1, 2])]), [s([1])]) self.aseq(min([s([1]), s([1, 2]), s([3])]), [s([1]), s([3])]) self.aseq(max([]), []) self.aseq(max([1]), [1]) self.aseq(max([1, 1]), [1]) self.aseq(max([1, 2]), [2]) self.aseq(max([[], []]), [[]]) self.aseq(max([s([1]), s([1, 2])]), [s([1, 2])]) self.aseq(max([s([1]), s([1, 2]), s([3])]), [s([1, 2]), s([3])]) def test_base_classes(self): un = self.un ty = self.ty do = self.do rc = self.rc iso = self.iso All = self.Anything Nothing = self.Nothing C1 = self.C1 C2 = self.C2 c1 = self.c1 lt = self.lt eq = self.eq dj = self.dj nr = self.nr data = [ (All, eq, All), (ty(int), eq, ty(int)), (ty(int), dj, ty(dict)), (ty(int), lt, All), (rc(ty(dict)), eq, rc(ty(dict))), (rc(ty(dict)), lt, All), (rc(ty(dict)), dj, rc(ty(list))), (iso(1), eq, iso(1)), (iso(1), lt, All), (iso(1), dj, iso(2)), (iso(1), lt, ty(int)), (iso(1), dj, ty(dict)), (Nothing, eq, Nothing), (Nothing, lt, ty(int)), (Nothing, lt, iso(1)), ] # Test relation of base classifications for a, cmp, b in data: cmp(a, b) # Test the four set-operations: & | - ^ # depending on the asserted argument relation if cmp is eq: eq(b, a) elif cmp is lt: self.assertTrue(b > a) eq(b ^ a, b - a) # Simple transformation eq(a ^ b, b - a) # -=-, indep. of type lt(a, b) elif cmp is dj: dj(b, a) # check that the dj relation is symmetric eq(a & b, Nothing) eq(b & a, Nothing) eq(a | b, b | a) eq(a - b, a) eq((a | b) - b, a) eq(a ^ b, a | b) eq(b ^ a, a | b) lt(a, a | b) lt(b, a | b) elif cmp is nr: nr(b, a) # symmetric as well eq(a & b, b & a) eq(a & b & b, a & b) eq((a & b) - b, Nothing) eq((a | b) - b, a - b) eq(a | b, b | a) lt(Nothing, a & b) lt(Nothing, b & a) lt(a & b, a) lt(a & b, b) lt(a - b, a) dj(a - b, b) lt(a ^ b, a | b) lt(a, a | b) lt(b, a | b) def test_invalid_operations(self): US = self.US US.auto_convert_iter = False US.auto_convert_type = False ty = self.ty c1 = self.c1 self.assertRaises(TypeError, lambda: ty(c1)) self.assertRaises(TypeError, lambda: ty(int) <= None) self.assertRaises(TypeError, lambda: None >= ty(int)) self.assertRaises(TypeError, lambda: None <= ty(int)) self.assertRaises(TypeError, lambda: list(ty(int))) self.assertRaises(TypeError, lambda: len(ty(int))) self.assertRaises(TypeError, lambda: ty(int) & None) self.assertRaises(TypeError, lambda: None & ty(int)) self.assertRaises(TypeError, lambda: ty(int) | None) self.assertRaises(TypeError, lambda: None | ty(int)) self.assertRaises(TypeError, lambda: ty(int) - None) self.assertRaises(TypeError, lambda: None - ty(int)) self.assertRaises(TypeError, lambda: ty(int) ^ None) self.assertRaises(TypeError, lambda: None ^ ty(int)) self.assertRaises(TypeError, lambda: ty(int) | [14]) self.assertRaises(TypeError, lambda: ty(int) | dict) self.assertRaises(TypeError, lambda: ty(int) | self.C1) def test_fancy_list_args(self): # Test the, normally disabled, possibility to use iterables as # right and left arguments in set expressions. # This option can cause problems as noted 22/11 2004. self.US.auto_convert_iter = True eq = self.eq iso = self.iso ty = self.ty e1 = [] e2 = {} e3 = [] e4 = () eq(ty(list) & [e1, e2, e3], iso(e1, e3)) eq([e1, e2, e3] & ty(list), iso(e1, e3)) # Requires __rand__ eq([e1, e2, e4] & (ty(dict) | ty(list)) == [e1, e2], True) eq([e1, e2] & (ty(dict) | ty(list)) == [e1, e2], True) eq(iso(e1, e2) & (ty(dict) | ty(list)) == [e1, e2], True) eq(iso(e1, e2) & [e1, e3], iso(e1)) eq(iso(e1, e2) | [e1, e3], iso(e1, e2, e3)) # Requires __ror__ eq([e1, e3] | iso(e1, e2), iso(e1, e2, e3)) eq(iso(e1, e3) - [e3], iso(e1)) eq([e1, e3] - iso(e3), iso(e1)) # Requires __rsub__ eq([e1, e2, e3] - ty(dict), iso(e1, e3)) eq(~ty(dict) & [e1, e2, e3], iso(e1, e3)) eq(iso(e1, e3) ^ [e2], iso(e1, e2, e3)) eq([e2] ^ iso(e1, e3), iso(e1, e2, e3)) # Requires __rxor__ eq([e1, e2] <= iso(e1, e2, e3), True) eq([e1, e2] <= ty(list) | ty(dict), True) eq((ty(list) | ty(dict)) >= [e1, e2], True) eq([e1, e2] <= ty(list), False) eq([e1, e2] <= iso(e1), False) eq([e1, e2] >= iso(e1, e2, e3), False) eq([e1, e2] >= iso(e1, e2), True) eq(iso(e1, e2, e3) <= [e1, e2], False) eq(iso(e1, e2) <= [e1, e2], True) eq(iso(e1, e2, e3) >= [e1, e2], True) eq(iso(e1, e2) >= [e1, e2, e3], False) def test_fancy_type_conversions(self): # Test the, perhaps optional, possibility to use types and classes # in classification set expressions. self.US.auto_convert_type = True un = self.un ty = self.ty do = self.do rc = self.rc iso = self.iso All = self.Anything Nothing = self.Nothing C1 = self.C1 C2 = self.C2 c1 = self.c1 def eq(a, b): self.assertTrue(a == b) e1 = [] e2 = {} e3 = [] e4 = () eq(ty(dict), dict) eq(iso(e1, e2) & dict, iso(e2)) eq(dict & iso(e1, e2), iso(e2)) eq(iso(e1, e2) | dict, iso(e1) | ty(dict)) eq(dict | iso(e1, e2), iso(e1) | ty(dict)) eq(iso(e1, e2) - dict, iso(e1)) eq(dict - iso(e1, e2), ty(dict) - iso(e2)) eq(iso(e1, e2, e3) ^ dict, (ty(dict)-iso(e2)) | iso(e1, e3)) class LawsCase(TestCase): def test_laws(self): un = self.un ty = self.ty do = self.do rc = self.rc iso = self.iso All = self.Anything Nothing = self.Nothing C1 = self.C1 C2 = self.C2 c1 = self.c1 lt = self.lt eq = self.eq t = self.guppy.sets.test absorption = t.absorption associative = t.associative commutative = t.commutative deMorgan = t.deMorgan distributive = t.distributive idempotence = t.idempotence inclusion = t.inclusion def ltr(a, b, level=3): lt(a, b) eq(a & b, a) eq(b & a, a) eq(a | b, b) eq(b | a, b) eq(a - b, Nothing) eqr(b - a, b - a) eq((b - a) | a, b) eq(a | (b - a), b) eq(a & (b - a), Nothing) eq((b - a) & a, Nothing) eq((b - a) - a, (b - a)) eq(a - (b - a), a) # note Nov 3 2004 if level > 0: if a is Nothing: eq(b - a, b) else: ltr(b - a, b, level-1) def eqr(a, b, level=1): eq(a, b) eq(a & b, a) eq(a | b, a) eq(a - b, Nothing) eq(a ^ b, Nothing) if level: eqr(b, a, level - 1) classes = [All, ty(int), ty(type(c1)), rc(ty(dict)), iso(c1), Nothing] for a in classes: idempotence(a) for b in classes: if a <= b: if b <= a: eqr(a, b) else: ltr(a, b) elif b <= a: ltr(b, a) absorption(a, b) commutative(a, b) inclusion(a, b) deMorgan(a, b) for c in classes: associative(a, b, c) deMorgan(a, b, c) distributive(a, b, c) class ClassificationCase(TestCase): def test_classification(self): # Test classification by the standard classifiers self.View.is_rg_update_all = True # Tricky details Note Apr 22 2005 Use = self.Use iso = self.iso nodeset = self.heapy.UniSet.immnodeset class A: pass class B(object): pass a = A() b = B() li = [1, [], {}, a, b, a.__dict__, b.__dict__] for o in li: self.asis(iso(o).bytype.kind.arg, type(o)) for o in li: if o is a.__dict__: kind = iso(a).kind elif o is b.__dict__: kind = iso(b).kind elif type(o) is dict: kind = Use.Nothing elif o is a: kind = a.__class__ else: kind = type(o) self.aseq(iso(o).kind.arg, kind) cla = iso(()).byunity.kind self.asis(cla.arg, None) for o in li: self.aseq(iso(o).byunity.kind, cla) for o in li: self.aseq(iso(o).byid.kind, Use.Id(id(o))) # self.View.update_referrers(nodeset(li)) for i, o in enumerate(li): cl = iso(o).byrcs.kind if 1 <= i <= 2: self.aseq(cl, Use.Clodo.sokind(list).refdby) if i == 5: self.aseq(cl, Use.Clodo.sokind(A)(list).refdby) if i == 6: self.aseq(cl, Use.Clodo.sokind(B)(list).refdby) def test_selection(self): # Test classifications operations via selection invariant Use = self.Use class A: pass class B(object): pass a = A() b = B() li = Use.iso(135, [], {}, a, b, a.__dict__, b.__dict__) allers = (Use.Unity, Use.Type, Use.Clodo, Use.Rcs, Use.Via) # , Use.Id ps = {} for er in allers: # p = er.classifier.partition(li.nodes) p = [(av.kind, av) for av in li.by(er).partition] for ak, av in p: if ak in ps: self.aseq(ps[ak], av) else: ps[ak] = av for ak, av in list(ps.items()): self.aseq(ak & li, av) for bk, bv in list(ps.items()): # Test set operations by selection definition self.aseq((ak & bk) & li, av & bv) self.aseq((ak | bk) & li, av | bv) self.aseq((ak - bk) & li, av - bv) self.aseq((bk - ak) & li, bv - av) self.aseq((ak ^ bk) & li, av ^ bv) def test_main(testrender=1, debug=0): support.run_unittest(BaseCase, debug) support.run_unittest(ClassificationCase, debug) support.run_unittest(LawsCase, debug) support.run_unittest(RenderCase, debug) support.run_unittest(SpecialCases, debug)