Mini Shell
from guppy.heapy.test import support
import io
import sys
import types
import unittest
class TestCase(support.TestCase):
def setUp(self):
support.TestCase.setUp(self)
self.RefPat = self.heapy.RefPat
self.iso = self.Use.iso
def makegraph(self, width, length):
# Generate a structure which will yield a high number
# of shortest paths.
# Returns a pair src, dst which are connected via a noncyclic graph
# with many edges.
# The length of each path (all shortest), number of edges will be length
# The number of nodes will be 2 + width * (length - 1)
# The number of paths will be
# width ** length, if width >= 1 and length >= 1
dst = []
ls = []
for i in range(width):
ls.append([dst])
ls = [dst] * width
for i in range(length-1):
xs = []
for j in range(width):
ys = []
xs.append(ys)
for k in range(width):
ys.append(ls[k])
ls = xs
src = ls
return src, dst
def rp(self, dst, src, **kwds):
iso = self.iso
if src is not None:
src = iso(src)
rp = iso(dst).get_rp(src=src, **kwds)
rp.mod.UniSet.summary_str.str_address = lambda a: '<address>'
return rp
class RefPatCase(TestCase):
def test_basic_methods(self):
# Test basic methods: iteration, indexing, length, tree addressing via attribute access
# Test iteration
dst = src = []
lists = [dst]
for i in range(5):
src = [src]
lists.append(src)
rp = self.rp(dst, src, depth=10)
for i, x in enumerate(rp):
if i < len(lists):
self.asis(lists[i], x.theone)
# Test indexing
# First case, when already iterated over
self.asis(rp[0].theone, lists[0])
self.asis(rp[-2].theone, lists[-1])
# Second case, when not iterated over before
rp = self.rp(dst, src, depth=10)
self.asis(rp[0].theone, lists[0])
self.asis(rp[-2].theone, lists[-1])
# Test length
self.aseq(len(rp), len(lists) + 1)
rp = self.rp(dst, src, depth=10)
self.aseq(len(rp), len(lists) + 1)
# Test attribute access
self.asis(rp._.theone, lists[0])
self.asis(rp.a.theone, lists[1])
# Test attribute access, when not iterated over before
rp = self.rp(dst, src, depth=10)
self.asis(rp.a2.theone, lists[2])
self.asis(rp.a.theone, lists[1])
# Make sure attribute access is cached:
# so it doesn't change when struct is changed
lists[2].append(lists[0])
rp.View.clear_retainers()
rp.View.update_referrers(self.iso(lists[0]))
self.asis(rp.a.theone, lists[1])
# Test with recursive structure
dst = []
dst.append(dst)
src = [dst]
rp = self.rp(dst, src)
self.asis(rp._.theone, dst)
self.aseq(rp.a, self.iso(dst, src))
self.aseq(rp.a, rp.a2)
self.aseq(rp.a, rp[1])
def test_presentation(self):
output = io.StringIO()
src = []
def write(x):
print(x, file=output)
R = self.RefPat
def test_pp(dst, src, result=None, **kwds):
rp = self.rp(dst, src, **kwds)
write(repr(rp))
return rp
dst = []
src.append(dst)
test_pp(dst, src)
for i in range(5):
x = dst
dst = []
x.append(dst)
test_pp(dst, src)
src, dst = self.makegraph(5, 7)
test_pp(dst, src, depth=10)
# Test that pp() prints limited number of lines
src, dst = self.makegraph(5, 17)
rp = test_pp(dst, src, depth=17)
write(repr(rp.more))
# Test more of more
src, dst = self.makegraph(1, 30)
rp = test_pp(dst, src, depth=35)
m = rp.more
write(repr(m))
write(repr(m.more))
m1 = m.more
write(repr(m1))
m2 = m.more
write(repr(m2.more))
write(str(m1.more)) # Test also that str() is the same as repr()
# Test that we get back to start by .top
write(m1.top)
# Test that we get back to previous by .prev
write(m1.prev)
# Test that they won't say '...more lines...' if the # of lines is what is printed
src, dst = self.makegraph(1, 30)
rp = test_pp(dst, src, depth=10)
# Test how no more lines is printed
write(rp.more)
write(rp.more.more)
# Test that one more line is printed rather than '1 more line'
src, dst = self.makegraph(1, 30)
rp = test_pp(dst, src, depth=21)
write(rp.more)
# Test that we can do more without first printing
rp = self.rp(dst, src, depth=20)
write(rp.more)
self.aseq(output.getvalue(), """\
Reference Pattern by <[dict of] class>.
0: _ --- [-] 1 list: <address>*0
1: a [-] 1 list: <address>*1
2: aa ---- [R] 1 tuple: <address>*1
Reference Pattern by <[dict of] class>.
0: _ --- [-] 1 list: <address>*0
1: a [-] 1 list: <address>*1
2: aa ---- [-] 1 list: <address>*1
3: a3 [-] 1 list: <address>*1
4: a4 ------ [-] 1 list: <address>*1
5: a5 [-] 1 list: <address>*1
6: a6 -------- [-] 1 list: <address>*1
7: a7 [R] 1 tuple: <address>*1
Reference Pattern by <[dict of] class>.
0: _ --- [-] 1 list: <address>*0
1: a [-] 5 list: <address>*5, <address>*5, <address>*5, <address>*5...
2: aa ---- [-] 5 list: <address>*5, <address>*5, <address>*5, <address>*5...
3: a3 [-] 5 list: <address>*5, <address>*5, <address>*5, <address>*5...
4: a4 ------ [-] 5 list: <address>*5, <address>*5, <address>*5, <address>*5...
5: a5 [-] 5 list: <address>*5, <address>*5, <address>*5, <address>*5...
6: a6 -------- [-] 5 list: <address>*5, <address>*5, <address>*5...
7: a7 [-] 1 list: <address>*5
8: a8 ---------- [R] 1 tuple: <address>*1
Reference Pattern by <[dict of] class>.
0: _ --- [-] 1 list: <address>*0
1: a [-] 5 list: <address>*5, <address>*5, <address>*5, <address>*5...
2: aa ---- [-] 5 list: <address>*5, <address>*5, <address>*5, <address>*5...
3: a3 [-] 5 list: <address>*5, <address>*5, <address>*5, <address>*5...
4: a4 ------ [-] 5 list: <address>*5, <address>*5, <address>*5, <address>*5...
5: a5 [-] 5 list: <address>*5, <address>*5, <address>*5, <address>*5...
6: a6 -------- [-] 5 list: <address>*5, <address>*5, <address>*5...
7: a7 [-] 5 list: <address>*5, <address>*5, <address>*5...
8: a8 ---------- [-] 5 list: <address>*5, <address>*5, <address>*5...
9: a9 [-] 5 list: <address>*5, <address>*5, <address>*5...
<Type e.g. '_.more' for more.>
10: a10 ----------- [-] 5 list: <address>*5, <address>*5, <address>*5...
11: a11 [-] 5 list: <address>*5, <address>*5, <address>*5...
12: a12 ------------- [-] 5 list: <address>*5, <address>*5, <address>*5...
13: a13 [-] 5 list: <address>*5, <address>*5, <address>*5...
14: a14 --------------- [-] 5 list: <address>*5, <address>*5, <address>*5...
15: a15 [-] 5 list: <address>*5, <address>*5, <address>*5...
16: a16 ----------------- [-] 5 list: <address>*5, <address>*5, <address>*5...
17: a17 [+] 1 list: <address>*5
Reference Pattern by <[dict of] class>.
0: _ --- [-] 1 list: <address>*0
1: a [-] 1 list: <address>*1
2: aa ---- [-] 1 list: <address>*1
3: a3 [-] 1 list: <address>*1
4: a4 ------ [-] 1 list: <address>*1
5: a5 [-] 1 list: <address>*1
6: a6 -------- [-] 1 list: <address>*1
7: a7 [-] 1 list: <address>*1
8: a8 ---------- [-] 1 list: <address>*1
9: a9 [-] 1 list: <address>*1
<Type e.g. '_.more' for more.>
10: a10 ----------- [-] 1 list: <address>*1
11: a11 [-] 1 list: <address>*1
12: a12 ------------- [-] 1 list: <address>*1
13: a13 [-] 1 list: <address>*1
14: a14 --------------- [-] 1 list: <address>*1
15: a15 [-] 1 list: <address>*1
16: a16 ----------------- [-] 1 list: <address>*1
17: a17 [-] 1 list: <address>*1
18: a18 ------------------- [-] 1 list: <address>*1
19: a19 [-] 1 list: <address>*1
<Type e.g. '_.more' for more.>
20: a20 --------------------- [-] 1 list: <address>*1
21: a21 [-] 1 list: <address>*1
22: a22 ----------------------- [-] 1 list: <address>*1
23: a23 [-] 1 list: <address>*1
24: a24 ------------------------- [-] 1 list: <address>*1
25: a25 [-] 1 list: <address>*1
26: a26 --------------------------- [-] 1 list: <address>*1
27: a27 [-] 1 list: <address>*1
28: a28 ----------------------------- [-] 1 list: <address>*1
29: a29 [-] 1 list: <address>*1
<Type e.g. '_.more' for more.>
20: a20 --------------------- [-] 1 list: <address>*1
21: a21 [-] 1 list: <address>*1
22: a22 ----------------------- [-] 1 list: <address>*1
23: a23 [-] 1 list: <address>*1
24: a24 ------------------------- [-] 1 list: <address>*1
25: a25 [-] 1 list: <address>*1
26: a26 --------------------------- [-] 1 list: <address>*1
27: a27 [-] 1 list: <address>*1
28: a28 ----------------------------- [-] 1 list: <address>*1
29: a29 [-] 1 list: <address>*1
<Type e.g. '_.more' for more.>
30: a30 ------------------------------- [-] 1 list: <address>*1
31: a31 [R] 1 tuple: <address>*1
30: a30 ------------------------------- [-] 1 list: <address>*1
31: a31 [R] 1 tuple: <address>*1
Reference Pattern by <[dict of] class>.
0: _ --- [-] 1 list: <address>*0
1: a [-] 1 list: <address>*1
2: aa ---- [-] 1 list: <address>*1
3: a3 [-] 1 list: <address>*1
4: a4 ------ [-] 1 list: <address>*1
5: a5 [-] 1 list: <address>*1
6: a6 -------- [-] 1 list: <address>*1
7: a7 [-] 1 list: <address>*1
8: a8 ---------- [-] 1 list: <address>*1
9: a9 [-] 1 list: <address>*1
<22 more lines. Type e.g. '_.more' for more.>
10: a10 ----------- [-] 1 list: <address>*1
11: a11 [-] 1 list: <address>*1
12: a12 ------------- [-] 1 list: <address>*1
13: a13 [-] 1 list: <address>*1
14: a14 --------------- [-] 1 list: <address>*1
15: a15 [-] 1 list: <address>*1
16: a16 ----------------- [-] 1 list: <address>*1
17: a17 [-] 1 list: <address>*1
18: a18 ------------------- [-] 1 list: <address>*1
19: a19 [-] 1 list: <address>*1
<12 more lines. Type e.g. '_.more' for more.>
Reference Pattern by <[dict of] class>.
0: _ --- [-] 1 list: <address>*0
1: a [-] 1 list: <address>*1
2: aa ---- [-] 1 list: <address>*1
3: a3 [-] 1 list: <address>*1
4: a4 ------ [-] 1 list: <address>*1
5: a5 [-] 1 list: <address>*1
6: a6 -------- [-] 1 list: <address>*1
7: a7 [-] 1 list: <address>*1
8: a8 ---------- [-] 1 list: <address>*1
9: a9 [-] 1 list: <address>*1
10: a10 ----------- [+] 1 list: <address>*1
Reference Pattern by <[dict of] class>.
0: _ --- [-] 1 list: <address>*0
1: a [-] 1 list: <address>*1
2: aa ---- [-] 1 list: <address>*1
3: a3 [-] 1 list: <address>*1
4: a4 ------ [-] 1 list: <address>*1
5: a5 [-] 1 list: <address>*1
6: a6 -------- [-] 1 list: <address>*1
7: a7 [-] 1 list: <address>*1
8: a8 ---------- [-] 1 list: <address>*1
9: a9 [-] 1 list: <address>*1
<Type e.g. '_.more' for more.>
10: a10 ----------- [-] 1 list: <address>*1
11: a11 [-] 1 list: <address>*1
12: a12 ------------- [-] 1 list: <address>*1
13: a13 [-] 1 list: <address>*1
14: a14 --------------- [-] 1 list: <address>*1
15: a15 [-] 1 list: <address>*1
16: a16 ----------------- [-] 1 list: <address>*1
17: a17 [-] 1 list: <address>*1
18: a18 ------------------- [-] 1 list: <address>*1
19: a19 [-] 1 list: <address>*1
<Type e.g. '_.more' for more.>
10: a10 ----------- [-] 1 list: <address>*1
11: a11 [-] 1 list: <address>*1
12: a12 ------------- [-] 1 list: <address>*1
13: a13 [-] 1 list: <address>*1
14: a14 --------------- [-] 1 list: <address>*1
15: a15 [-] 1 list: <address>*1
16: a16 ----------------- [-] 1 list: <address>*1
17: a17 [-] 1 list: <address>*1
18: a18 ------------------- [-] 1 list: <address>*1
19: a19 [-] 1 list: <address>*1
20: a20 --------------------- [+] 1 list: <address>*1
""")
def test_referrer_registration(self):
import gc
# The reference pattern should register itself as referrer target
# so that after a gc, the rp target will still be included in the referrer target
# Since the target is passed to referrers and update, it will still find the
# referrers. It is an optimization issue: it should cover the referrers.
# We test this by having two different-typed referrers
# Accessing a referrer of the first one, then gc collecting, then checking that
# the second one can be accessed without update: it was created automatically.
# The test failed when not registering, but succeeded when registering was added.
# It succeeds any case if no GC collection is made.
dst = []
a = [dst]
aa = [a]
b = (dst,)
ba = [b]
src = [aa, ba]
rp = self.rp(dst, src)
self.asis(rp._.theone, dst)
gc.collect()
self.asis(rp.aa.theone, aa)
self.asis(rp.View.rg[b][0], ba)
def test_some_more_advanced_usages(self):
import gc
# Test immediate dominators
dst = []
src = [dst]
src.append([dst])
rp = self.rp(dst, src, depth=10, imdom=1)
self.asis(rp._.theone, dst)
self.asis(rp.a.theone, src)
# Test with mixed types
# In particular, dict owned by an instance
dst = []
class A:
pass
a = A()
a.dst = dst
b = {'dst': dst}
src = (a, b)
gc.collect()
rp = self.rp(dst, src, depth=10)
rp.mod.View._is_clear_drg_enabled = 0 # Note Apr 19 2005
if sys.getsizeof(b) > sys.getsizeof(a.__dict__):
self.asis(rp.a.theone, b)
self.asis(rp.b.theone, a.__dict__)
else:
self.asis(rp.a.theone, a.__dict__)
self.asis(rp.b.theone, b)
# Test that the dict is eventually automatically removed from dictowners -
# First test that dictowners is nonzero
ln = len(rp.mod.View.dict_ownership)
self.assertTrue(ln > 0)
del src
del a
mod = rp.mod
rp.mod.View._is_clear_drg_enabled = 1
del rp
# It is cleared after GC
gc.collect()
lnnow = len(mod.View.dict_ownership)
self.assertTrue(lnnow == 0)
class NewCase(TestCase):
# Some new tests as they come up
def test_reset(self):
# Test the .reset() method
dst = []
a = [dst]
b = [dst]
src = [a, b]
rp = self.rp(dst, src)
self.aseq(rp.a, self.iso(a, b))
b.pop()
rp.reset()
self.aseq(rp.a, self.iso(a))
def test_paths(self):
# Test the .paths() method
dst = []
a = [dst]+[None]*40 # Make order well-defined. Note May 2 2005.
b = [dst]
src = [a, b]
rp = self.rp(dst, src)
expected = """\
Paths from source 'a3' to target '_'.
0: a3 [0] @ [0]
1: aa [0] @ [0]
2: a [0] @ [0]
3: _ [0] = <1 list: <address>*0>
4: aa [0] @ [1]
5: a [1] @ [0] -> #3"""
self.aseq(str(rp.paths('a3')), expected)
expected = expected[:expected.index('\n 4:')]
# Test the andsets argument, given as a dict
self.aseq(str(rp.paths('a3', andsets={'a': self.iso(a)})), expected)
# Test the andsets argument, given as a list
self.aseq(
str(rp.paths('a3', andsets=[None, None, self.iso(a)])), expected)
def test_main(debug=0):
support.run_unittest(RefPatCase, debug)
support.run_unittest(NewCase, debug)
def test_leak():
# Runs the tests in a loop and prints memory statistics,
# to see if there are underlying low-level memory problems.
# Requires Python to be compiled with debug support.
from guppy.heapy.heapyc import xmemstats
import gc
import sys
import time
i = 0
xmemstats()
while 1:
print('[%d]' % i, time.asctime())
i += 1
test_main()
gc.collect()
xmemstats()
if __name__ == "__main__":
test_main()
Zerion Mini Shell 1.0