1f5049fc8c65ca45a3d42de400be57353b42f1d61Thomas Hellerimport unittest, sys
2babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
3babddfca758abe34ff12023f63b18d745fae7ca9Thomas Hellerfrom ctypes import *
4babddfca758abe34ff12023f63b18d745fae7ca9Thomas Hellerimport _ctypes_test
5babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
6babddfca758abe34ff12023f63b18d745fae7ca9Thomas Hellerctype_types = [c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint,
7babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller                 c_long, c_ulong, c_longlong, c_ulonglong, c_double, c_float]
8e2a383d062434c05b73031f0da57fe82b9da8942Guido van Rossumpython_types = [int, int, int, int, int, int,
9e2a383d062434c05b73031f0da57fe82b9da8942Guido van Rossum                int, int, int, int, float, float]
10babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
11babddfca758abe34ff12023f63b18d745fae7ca9Thomas Hellerclass PointersTestCase(unittest.TestCase):
12babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
13babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller    def test_pointer_crash(self):
14e8d09e581816aa7fdb812801c79e8f6bc55dc134Tim Peters
15babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        class A(POINTER(c_ulong)):
16babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller            pass
17babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
18babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        POINTER(c_ulong)(c_ulong(22))
19babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        # Pointer can't set contents: has no _type_
20c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertRaises(TypeError, A, c_ulong(33))
21babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
22babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller    def test_pass_pointers(self):
23477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        dll = CDLL(_ctypes_test.__file__)
24babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        func = dll._testfunc_p_p
2553683965aaf2895fbdb851e07436c6f86b48d0dcSteve Dower        if sizeof(c_longlong) == sizeof(c_void_p):
2653683965aaf2895fbdb851e07436c6f86b48d0dcSteve Dower            func.restype = c_longlong
2753683965aaf2895fbdb851e07436c6f86b48d0dcSteve Dower        else:
2853683965aaf2895fbdb851e07436c6f86b48d0dcSteve Dower            func.restype = c_long
29babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
30babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        i = c_int(12345678)
31babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller##        func.argtypes = (POINTER(c_int),)
32babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        address = func(byref(i))
33c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(c_int.from_address(address).value, 12345678)
34babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
35babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        func.restype = POINTER(c_int)
36babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        res = func(pointer(i))
37c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(res.contents.value, 12345678)
38c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(res[0], 12345678)
39babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
40babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller    def test_change_pointers(self):
41477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        dll = CDLL(_ctypes_test.__file__)
42babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        func = dll._testfunc_p_p
43babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
44babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        i = c_int(87654)
45babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        func.restype = POINTER(c_int)
46babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        func.argtypes = (POINTER(c_int),)
47babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
48babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        res = func(pointer(i))
49c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(res[0], 87654)
50c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(res.contents.value, 87654)
51babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
52babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        # C code: *res = 54345
53babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        res[0] = 54345
54c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(i.value, 54345)
55babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
56babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        # C code:
57babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        #   int x = 12321;
58babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        #   res = &x
5934360c8e09f51075fec0c673b2674d20bed33bf5Martin Panter        x = c_int(12321)
6034360c8e09f51075fec0c673b2674d20bed33bf5Martin Panter        res.contents = x
61c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(i.value, 54345)
62babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
6334360c8e09f51075fec0c673b2674d20bed33bf5Martin Panter        x.value = -99
6434360c8e09f51075fec0c673b2674d20bed33bf5Martin Panter        self.assertEqual(res.contents.value, -99)
6534360c8e09f51075fec0c673b2674d20bed33bf5Martin Panter
66babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller    def test_callbacks_with_pointers(self):
67babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        # a function type receiving a pointer
68babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        PROTOTYPE = CFUNCTYPE(c_int, POINTER(c_int))
69babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
70babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        self.result = []
71babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
72babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        def func(arg):
73babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller            for i in range(10):
74babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller##                print arg[i],
75babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller                self.result.append(arg[i])
76babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller##            print
77babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller            return 0
78babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        callback = PROTOTYPE(func)
79babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
80477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        dll = CDLL(_ctypes_test.__file__)
81babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        # This function expects a function pointer,
82babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        # and calls this with an integer pointer as parameter.
83babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        # The int pointer points to a table containing the numbers 1..10
84babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        doit = dll._testfunc_callback_with_pointer
85babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
86babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller##        i = c_int(42)
87babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller##        callback(byref(i))
887c5e24f948e6ce33e21b09833f8fe3a8eb1530acSerhiy Storchaka##        self.assertEqual(i.value, 84)
89babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
90babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        doit(callback)
91babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller##        print self.result
92babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        doit(callback)
93babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller##        print self.result
94e8d09e581816aa7fdb812801c79e8f6bc55dc134Tim Peters
95babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller    def test_basics(self):
96babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        from operator import delitem
97babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        for ct, pt in zip(ctype_types, python_types):
98babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller            i = ct(42)
99babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller            p = pointer(i)
100babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller##            print type(p.contents), ct
1017c5e24f948e6ce33e21b09833f8fe3a8eb1530acSerhiy Storchaka            self.assertIs(type(p.contents), ct)
102babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller            # p.contents is the same as p[0]
103babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller##            print p.contents
1047c5e24f948e6ce33e21b09833f8fe3a8eb1530acSerhiy Storchaka##            self.assertEqual(p.contents, 42)
1057c5e24f948e6ce33e21b09833f8fe3a8eb1530acSerhiy Storchaka##            self.assertEqual(p[0], 42)
106babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
107babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller            self.assertRaises(TypeError, delitem, p, 0)
108babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
109babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller    def test_from_address(self):
110babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        from array import array
111babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        a = array('i', [100, 200, 300, 400, 500])
112babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        addr = a.buffer_info()[0]
113babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
114babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        p = POINTER(POINTER(c_int))
115babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller##        print dir(p)
116babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller##        print p.from_address
117babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller##        print p.from_address(addr)[0][0]
118babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
119babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller    def test_other(self):
120babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        class Table(Structure):
121babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller            _fields_ = [("a", c_int),
122babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller                        ("b", c_int),
123babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller                        ("c", c_int)]
124babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
125babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        pt = pointer(Table(1, 2, 3))
126babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
127c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(pt.contents.a, 1)
128c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(pt.contents.b, 2)
129c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(pt.contents.c, 3)
130babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
131babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        pt.contents.c = 33
132babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
133babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        from ctypes import _pointer_type_cache
134babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        del _pointer_type_cache[Table]
135babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
136babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller    def test_basic(self):
137babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        p = pointer(c_int(42))
13834360c8e09f51075fec0c673b2674d20bed33bf5Martin Panter        # Although a pointer can be indexed, it has no length
139babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        self.assertRaises(TypeError, len, p)
140c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(p[0], 42)
14134360c8e09f51075fec0c673b2674d20bed33bf5Martin Panter        self.assertEqual(p[0:1], [42])
142c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(p.contents.value, 42)
143e8d09e581816aa7fdb812801c79e8f6bc55dc134Tim Peters
14473e5a5b65d66f4fba9c4f626bcd6400f4a7215e6Thomas Wouters    def test_charpp(self):
145babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        """Test that a character pointer-to-pointer is correctly passed"""
146477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        dll = CDLL(_ctypes_test.__file__)
147babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        func = dll._testfunc_c_p_p
148babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        func.restype = c_char_p
149babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        argv = (c_char_p * 2)()
150babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        argc = c_int( 2 )
1518b939526215754a0317353f9e8d9ed85636101a0Thomas Heller        argv[0] = b'hello'
1528b939526215754a0317353f9e8d9ed85636101a0Thomas Heller        argv[1] = b'world'
153babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller        result = func( byref(argc), argv )
1548b939526215754a0317353f9e8d9ed85636101a0Thomas Heller        self.assertEqual(result, b'world')
155babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller
15649fd7fa4431da299196d74087df4a04f99f9c46fThomas Wouters    def test_bug_1467852(self):
15749fd7fa4431da299196d74087df4a04f99f9c46fThomas Wouters        # http://sourceforge.net/tracker/?func=detail&atid=532154&aid=1467852&group_id=71702
15849fd7fa4431da299196d74087df4a04f99f9c46fThomas Wouters        x = c_int(5)
15949fd7fa4431da299196d74087df4a04f99f9c46fThomas Wouters        dummy = []
16049fd7fa4431da299196d74087df4a04f99f9c46fThomas Wouters        for i in range(32000):
16149fd7fa4431da299196d74087df4a04f99f9c46fThomas Wouters            dummy.append(c_int(i))
16249fd7fa4431da299196d74087df4a04f99f9c46fThomas Wouters        y = c_int(6)
16349fd7fa4431da299196d74087df4a04f99f9c46fThomas Wouters        p = pointer(x)
16449fd7fa4431da299196d74087df4a04f99f9c46fThomas Wouters        pp = pointer(p)
16549fd7fa4431da299196d74087df4a04f99f9c46fThomas Wouters        q = pointer(y)
16649fd7fa4431da299196d74087df4a04f99f9c46fThomas Wouters        pp[0] = q         # <==
167c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(p[0], 6)
1680e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters    def test_c_void_p(self):
1690e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters        # http://sourceforge.net/tracker/?func=detail&aid=1518190&group_id=5470&atid=105470
1700e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters        if sizeof(c_void_p) == 4:
171c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson            self.assertEqual(c_void_p(0xFFFFFFFF).value,
1720e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters                                 c_void_p(-1).value)
173c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson            self.assertEqual(c_void_p(0xFFFFFFFFFFFFFFFF).value,
1740e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters                                 c_void_p(-1).value)
1750e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters        elif sizeof(c_void_p) == 8:
176c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson            self.assertEqual(c_void_p(0xFFFFFFFF).value,
177e2a383d062434c05b73031f0da57fe82b9da8942Guido van Rossum                                 0xFFFFFFFF)
178c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson            self.assertEqual(c_void_p(0xFFFFFFFFFFFFFFFF).value,
1790e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters                                 c_void_p(-1).value)
180c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson            self.assertEqual(c_void_p(0xFFFFFFFFFFFFFFFFFFFFFFFF).value,
1810e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters                                 c_void_p(-1).value)
1820e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters
1830e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters        self.assertRaises(TypeError, c_void_p, 3.14) # make sure floats are NOT accepted
1840e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters        self.assertRaises(TypeError, c_void_p, object()) # nor other objects
185e8d09e581816aa7fdb812801c79e8f6bc55dc134Tim Peters
1867dca3ebc97661da9fe2945b9c65d58c234d10629Thomas Heller    def test_pointers_bool(self):
1877dca3ebc97661da9fe2945b9c65d58c234d10629Thomas Heller        # NULL pointers have a boolean False value, non-NULL pointers True.
188c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(bool(POINTER(c_int)()), False)
189c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(bool(pointer(c_int())), True)
1907dca3ebc97661da9fe2945b9c65d58c234d10629Thomas Heller
191c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(bool(CFUNCTYPE(None)(0)), False)
192c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson        self.assertEqual(bool(CFUNCTYPE(None)(42)), True)
1937dca3ebc97661da9fe2945b9c65d58c234d10629Thomas Heller
194f5049fc8c65ca45a3d42de400be57353b42f1d61Thomas Heller        # COM methods are boolean True:
195f5049fc8c65ca45a3d42de400be57353b42f1d61Thomas Heller        if sys.platform == "win32":
196f5049fc8c65ca45a3d42de400be57353b42f1d61Thomas Heller            mth = WINFUNCTYPE(None)(42, "name", (), None)
197c9c0f201fed21efcf669dbbf5f923eaf0eeb1db9Benjamin Peterson            self.assertEqual(bool(mth), True)
198f5049fc8c65ca45a3d42de400be57353b42f1d61Thomas Heller
199817905b2393b03e035d2bbfc8d92b7bbeaddb118R David Murray    def test_pointer_type_name(self):
2009db55004a1bc0c0b3efca69dcd577ff58a86ea16Serhiy Storchaka        LargeNamedType = type('T' * 2 ** 25, (Structure,), {})
201817905b2393b03e035d2bbfc8d92b7bbeaddb118R David Murray        self.assertTrue(POINTER(LargeNamedType))
202817905b2393b03e035d2bbfc8d92b7bbeaddb118R David Murray
203b63902a74834e3e7d15356ff60e017ee6efba2a7Serhiy Storchaka        # to not leak references, we must clean _pointer_type_cache
204b63902a74834e3e7d15356ff60e017ee6efba2a7Serhiy Storchaka        from ctypes import _pointer_type_cache
205b63902a74834e3e7d15356ff60e017ee6efba2a7Serhiy Storchaka        del _pointer_type_cache[LargeNamedType]
206b63902a74834e3e7d15356ff60e017ee6efba2a7Serhiy Storchaka
207817905b2393b03e035d2bbfc8d92b7bbeaddb118R David Murray    def test_pointer_type_str_name(self):
2089db55004a1bc0c0b3efca69dcd577ff58a86ea16Serhiy Storchaka        large_string = 'T' * 2 ** 25
209b63902a74834e3e7d15356ff60e017ee6efba2a7Serhiy Storchaka        P = POINTER(large_string)
210b63902a74834e3e7d15356ff60e017ee6efba2a7Serhiy Storchaka        self.assertTrue(P)
211b63902a74834e3e7d15356ff60e017ee6efba2a7Serhiy Storchaka
212b63902a74834e3e7d15356ff60e017ee6efba2a7Serhiy Storchaka        # to not leak references, we must clean _pointer_type_cache
213b63902a74834e3e7d15356ff60e017ee6efba2a7Serhiy Storchaka        from ctypes import _pointer_type_cache
214b63902a74834e3e7d15356ff60e017ee6efba2a7Serhiy Storchaka        del _pointer_type_cache[id(P)]
215b63902a74834e3e7d15356ff60e017ee6efba2a7Serhiy Storchaka
216817905b2393b03e035d2bbfc8d92b7bbeaddb118R David Murray
217babddfca758abe34ff12023f63b18d745fae7ca9Thomas Hellerif __name__ == '__main__':
218babddfca758abe34ff12023f63b18d745fae7ca9Thomas Heller    unittest.main()
219