관리-도구
편집 파일: test_heapyc.py
from guppy.heapy.test import support class TestCase(support.TestCase): def setUp(self): support.TestCase.setUp(self) self.sets = self.guppy.sets heapdefs = getattr(self.sets.setsc, '_NyHeapDefs_'), self.root = [] self.heapyc = self.guppy.heapy.heapyc self.hv = self.heapyc.HeapView(self.root, heapdefs) self.nodeset = self.sets.immnodeset self.mutnodeset = self.sets.mutnodeset self.nodegraph = self.heapyc.NodeGraph class TestHeapView(TestCase): def test_hiding_tag(self): hiding_tag = self.hv._hiding_tag_ a = [] ns = self.mutnodeset([a]) ng = self.nodegraph([(a, a)]) self.aseq(self.hv.relimg([ns]), self.nodeset([a])) self.aseq(self.hv.relimg([ng]), self.nodeset([a])) ns._hiding_tag_ = hiding_tag self.aseq(self.hv.relimg([ns]), self.nodeset([])) ng._hiding_tag_ = hiding_tag self.aseq(self.hv.relimg([ng]), self.nodeset([])) self.hv._hiding_tag_ = [] self.aseq(self.hv.relimg([ns]), self.nodeset([a, None])) self.aseq(self.hv.relimg([ng]), self.nodeset([a, None])) def test_inheritance_from_heapview(self): # I am not using inheritance from HeapView, # but it would be kinda weird if it didn't work. HeapView = self.guppy.heapy.heapyc.HeapView x = 'x' newroot = [x] class HV(HeapView): def __new__(self): return HeapView.__new__(HV, newroot, ()) hv = HV() assert hv.heap() == self.nodeset([x, newroot]) def test_inheritance_from_special_types(self): # Test that relate, size & traverse function correctly for inherited types # as discussed in Notes Apr 14 2005. # Testing with a standard type (list) with specially size and relate definitions, # and a heapdef'd type (mutnodeset) with size, relate and traverse defs. # Test includes more than 1 level of inheritance, since the generic # method needs to go over all bases and not just the (first) base. hv = self.hv hv._hiding_tag_ = [] # Different from default nodeset's hiding_tag immnodeset = self.sets.immnodeset mutnodeset = self.sets.mutnodeset for base in (list, mutnodeset): class T(base): __slots__ = 't', class U(T): __slots__ = 'u', a = base() t = T() t.t = [] u = U() u.t = [] u.u = [] data = list(range(16)) for x in data: a.append(x) t.append(x) u.append(x) # Test size za = hv.indisize_sum([a]) zt = hv.indisize_sum([t]) zu = hv.indisize_sum([u]) self.assertTrue(za < zt < zu) # Test traverse self.aseq(hv.relimg([a]), immnodeset(data)) self.aseq(hv.relimg([t]), immnodeset(data+[T, t.t])) self.aseq(hv.relimg([u]), immnodeset(data+[U, u.t, u.u])) # Test relate def rel(src, tgt): r = hv.relate(src, tgt) self.assertTrue(r != ((),)*len(r)) return r self.aseq(rel(t, data[1]), rel(a, data[1])) self.aseq(rel(u, data[1]), rel(a, data[1])) self.aseq(rel(u, u.t), rel(t, t.t)) rel(u, u.u) def test_nodeset_circularity(self): # The traversal to function correctly for types inherited from nodeset # required a fix as discussed in Notes Apr 14 2005. # This method intends to test that this fix was harmless wrt gc & circularity. # To make this method fail, it was necessary to disable nodeset gc traversal. # xxx It seems I have not yet come around to write this test... pass def test_registered_hiding(self): hv = self.hv class Set(object): __slots__ = 'some', '_hiding_tag_', 'other' class Der(Set): pass hv.register__hiding_tag__type(Set) # Der is inherited and registration follows its base type. s = Set() d = Der() t = Set() some = [] other = [] dother = [] s.some = some s.other = other d.some = some d.other = dother self.root.append([s, t, d]) self.root.append(s) self.root.append(d) self.root.append(t) x = hv.heap() assert dother in x assert some in x assert other in x assert s in x assert d in x assert t in x s._hiding_tag_ = hv._hiding_tag_ d._hiding_tag_ = hv._hiding_tag_ x = hv.heap() assert some not in x assert other not in x assert s not in x assert d not in x assert t in x he = [] hv._hiding_tag_ = he x = hv.heap() assert dother in x assert some in x assert other in x assert s in x assert d in x assert t in x def test_timing(self): # Test some timing aspects of heap traversal from time import process_time as clock hv = self.hv d = [] h = [d] self.root.extend(100000*[h]) self.root.extend(list(range(100000))) start = clock() x = hv.heap() elapsed0 = clock() - start print('elapsed0', elapsed0, 'len(x)', len(x)) class Set(object): __slots__ = 'some', '_hiding_tag_', 'other' class Der(Set): pass hv.register__hiding_tag__type(Set) s = Set() s._hiding_tag_ = hv._hiding_tag_ d = Der() d._hiding_tag_ = hv._hiding_tag_ self.root[0:50000] = 25000*[s, d] start = clock() x = hv.heap() elapsed1 = clock() - start print('elapsed1', elapsed1, 'len(x)', len(x)) # This has failed a couple of times so I remove it now, (apr 5 2008) # xxx should look into this later ... #self.assert_(elapsed1 < 3.0 * elapsed0) class TestLeak(support.TestCase): def test_1(self): import gc from sys import getrefcount as grc support.TestCase.setUp(self) sets = self.guppy.sets heapdefs = getattr(sets.setsc, '_NyHeapDefs_'), root = [] heapyc = self.guppy.heapy.heapyc nodeset = sets.mutnodeset nodegraph = heapyc.NodeGraph class T(object): __slots__ = 'a', '_hiding_tag_', 'tonly' pass class U(T): __slots__ = 'b', pass class V(object): __slots__ = 'c', gc.collect() ns = nodeset() a = [ns] a.append(a) b = [] he = [] c = [] t = T() tonly = [] t.a = a t._hiding_tag_ = he t.tonly = tonly u = U() u.a = a u._hiding_tag_ = he u.b = b v = V() v.c = c a = [x for x in [list]] li = [he, a, b, c, t, u, v, T, U, V, ns, nodeset, list] rcli0 = [grc(x) for x in li] ns |= li + list(range(10000, 10010)) root.extend(li) rcli = [grc(x) for x in li] rec = nodeset([x for x in li]) x = None rec.append(rec) ns.add(rec) rec._hiding_tag_ = rec hv = heapyc.HeapView(root, heapdefs) hv.register__hiding_tag__type(T) h = hv.heap() assert a in h assert c in h assert tonly in h hv._hiding_tag_ = he h = hv.heap() del x del h del hv ns.discard(rec) rec = None gc.collect() nrcli = [grc(x) for x in li] self.aseq(rcli, nrcli) root[:] = [] ns.clear() nrcli0 = [grc(x) for x in li] self.aseq(rcli0, nrcli0) def test_weaky(self): # Test that the extra-type information in heapview # will still allow types to come, be used, and go, and be collected # This depends on that they are weakly-referenced # so internal heapview structures can remove them when they are # to be collected. import gc from sys import getrefcount as grc support.TestCase.setUp(self) sets = self.guppy.sets heapdefs = getattr(sets.setsc, '_NyHeapDefs_'), root = [] heapyc = self.guppy.heapy.heapyc nodeset = sets.NodeSet nodegraph = heapyc.NodeGraph gc.collect() probe = [] rcprobe = grc(probe) class T(object): x = probe class U(T): pass T.U = U # Make circular dependency t = T() u = U() root.append(t) root.append(u) hv = heapyc.HeapView(root, heapdefs) x = hv.heap() assert t in x x = None T = t = U = u = None root[:] = [] gc.collect() # 2 collections needed sometimes? Note Apr 15 2005 nrcprobe = grc(probe) self.aseq(nrcprobe, rcprobe) class TestNodeGraph(TestCase): def test_constructor_and_methods(self): # Test constructor w no arg ng = self.nodegraph() # Test add_edge ng.add_edge(1, 2) # Test add_edges_n1 ng.add_edges_n1([3, 4], 5) lng = list(ng) lng.sort() assert lng == [(1, 2), (3, 5), (4, 5)] # Test as_flat_list fl = ng.as_flat_list() fl.sort() assert fl == [1, 2, 3, 4, 5, 5] # Test copy cp = ng.copy() cp.add_edge(5, 6) # Test __iter__ explicitly lng1 = list(ng.__iter__()) lng1.sort() assert lng1 == lng lcp = list(cp) lcp.sort() assert lcp == [(1, 2), (3, 5), (4, 5), (5, 6)] # Test domain_covers assert ng.domain_covers([1, 3, 4]) assert not ng.domain_covers([1, 3, 4, 5]) # Test domain_restricted rng = ng.domain_restricted([1, 3]) # Test get_domain assert rng.get_domain() == self.nodeset([1, 3]) lrng = list(rng) lrng.sort() assert lrng == [(1, 2), (3, 5)] # Test get_range assert rng.get_range() == self.nodeset([2, 5]) # Test invert rng.invert() lrng = list(rng) lrng.sort() assert lrng == [(2, 1), (5, 3)] # Test inverted ing = ng.inverted() ling = list(ing) ling.sort() assert ling == [(2, 1), (5, 3), (5, 4)] # Test relimg assert ing.relimg([2]) == self.nodeset([1]) assert ing.relimg([2, 5, 3]) == self.nodeset([1, 3, 4]) # Test update ing.update([(3, 7), (4, 8)]) assert ing.relimg([2, 5, 3]) == self.nodeset([1, 3, 4, 7]) # Test updated uing = ing.updated([(2, 9)]) assert ing.relimg([2, 5, 3]) == self.nodeset([1, 3, 4, 7]) assert uing.relimg([2, 5, 3]) == self.nodeset([1, 3, 4, 7, 9]) # Test __getitem__ tgts = list(uing[2]) tgts.sort() assert tgts == [1, 9] # Test __len__ assert len(uing) == 6 uing[2] = (2, 8) # Test __setitem__ tgts = list(uing[2]) tgts.sort() assert tgts == [2, 8] # Test clear ng.clear() assert list(ng) == [] # Test constructor with iterable ng = self.nodegraph([(1, 2)]) assert list(ng) == [(1, 2)] assert not ng.is_mapping # Test constructor with is_mapping flag ng = self.nodegraph(is_mapping=True) assert ng.is_mapping assert list(ng) == [] ng.add_edge(1, 2) assert list(ng) == [(1, 2)] assert ng[1] == 2 ng = self.nodegraph(is_mapping=False) assert not ng.is_mapping # Test constructor with iterable & is_mapping flag for ng in (self.nodegraph([(1, 2)], True), self.nodegraph(iterable=[(1, 2)], is_mapping=True), self.nodegraph([(1, 2)], is_mapping=True), self.nodegraph(is_mapping=True, iterable=[(1, 2)]) ): assert ng.is_mapping assert list(ng) == [(1, 2)] assert ng[1] == 2 ng[1] = 3 assert ng[1] == 3 # Test is_sorted flag # though this behaviour is not fixed - may change with implementation ng = self.nodegraph() ng.add_edge(1, 2) ng.add_edge(2, 1) assert not ng.is_sorted ng[1] assert ng.is_sorted def test_inheritance(self): class T(self.heapyc.NodeGraph): __slots__ = 'x' def as_sorted_list(self): a = list(self) a.sort() return a t = T() t.add_edge(1, 2) t.add_edge(2, 3) assert t.as_sorted_list() == [(1, 2), (2, 3)] t = T([(4, 5), (6, 7)]) assert t.as_sorted_list() == [(4, 5), (6, 7)] # Test that the base type functionality has been inherited # by making test_constructor_and_methods think NodeGraph is T self.nodegraph = T self.test_constructor_and_methods() # Test with a constructor with new argument # and some more attributes class R(T): __slots__ = 'stop', def __new__(self, stop): r = T.__new__(R, is_mapping=1) r.add_edges_n1(list(range(stop)), 0) r.stop = stop return r def keys(self): return list(self.get_domain()) def values(self): return [self[k] for k in list(self.keys())] r = R(10) assert r.stop == 10 assert r.is_mapping lr = list(r) lr.sort() assert lr[-2:] == [(8, 0), (9, 0)] keys = list(r.keys()) keys.sort() assert keys == list(range(10)) values = list(r.values()) assert values == [0]*10 class TestClassifiers(TestCase): # Some new standalone classifiers tests. # Some old are also tested via test_Classifiers. def test_inrel(self): def str_inrel(c): c = list(c) c.sort() return ', '.join(['(%s, %r)' % (x.kind, x.relator) for x in c]) hv = self.hv rg = self.nodegraph() x = [] y = [x] rg.add_edge(x, y) cli = hv.cli_inrel(rg, {}, {}) c = cli.classify(x) self.aseq(str_inrel(c), '(2, 0)') for i in range(5): y.append(x) c = cli.classify(x) self.aseq(str_inrel(c), '(2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5)') for i in range(5): r = {str(i): x} rg.add_edge(x, r) c = cli.classify(x) def test_nodetuple_richcompare(self): hv = self.hv cli = hv.cli_and((hv.cli_id(),), {}) a, b = cli.classify(1), cli.classify(2) self.assertTrue(a != b) self.assertFalse(a == b) self.assertTrue(a >= b or a <= b) self.assertFalse(a >= b and a <= b) self.assertTrue(a > b or a < b) self.assertFalse(a > b and a < b) a, b = cli.classify(1), cli.classify(1) self.assertFalse(a != b) self.assertTrue(a == b) self.assertTrue(a >= b or a <= b) self.assertTrue(a >= b and a <= b) self.assertFalse(a > b or a < b) self.assertFalse(a > b and a < b) def test_main(debug=False): support.run_unittest(TestClassifiers, debug) support.run_unittest(TestNodeGraph, debug) support.run_unittest(TestLeak, debug) support.run_unittest(TestHeapView, debug) if __name__ == "__main__": test_main()