comparison tests/test-rust-ancestor.py @ 41053:d9f439fcdb4c

rust-cpython: binding for AncestorsIterator It's now reachable from Python as rustext.ancestor.AncestorsIterator Tests are provided in the previously introduced Python testcase: this is much more convenient that writing lengthy Rust code to call into Python. Differential Revision: https://phab.mercurial-scm.org/D5439
author Georges Racinet <gracinet@anybox.fr>
date Thu, 06 Dec 2018 20:01:21 +0100
parents 74f41329bf55
children b31a41f24864
comparison
equal deleted inserted replaced
41052:4c25038c112c 41053:d9f439fcdb4c
1 from __future__ import absolute_import 1 from __future__ import absolute_import
2 import sys
2 import unittest 3 import unittest
3 4
4 try: 5 try:
5 from mercurial import rustext 6 from mercurial import rustext
7 rustext.__name__ # trigger immediate actual import
6 except ImportError: 8 except ImportError:
7 rustext = None 9 rustext = None
10 else:
11 # this would fail already without appropriate ancestor.__package__
12 from mercurial.rustext.ancestor import AncestorsIterator
8 13
9 try: 14 try:
10 from mercurial.cext import parsers as cparsers 15 from mercurial.cext import parsers as cparsers
11 except ImportError: 16 except ImportError:
12 cparsers = None 17 cparsers = None
13 18
19 # picked from test-parse-index2, copied rather than imported
20 # so that it stays stable even if test-parse-index2 changes or disappears.
21 data_non_inlined = (
22 b'\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01D\x19'
23 b'\x00\x07e\x12\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff'
24 b'\xff\xff\xff\xff\xd1\xf4\xbb\xb0\xbe\xfc\x13\xbd\x8c\xd3\x9d'
25 b'\x0f\xcd\xd9;\x8c\x07\x8cJ/\x00\x00\x00\x00\x00\x00\x00\x00\x00'
26 b'\x00\x00\x00\x00\x00\x00\x01D\x19\x00\x00\x00\x00\x00\xdf\x00'
27 b'\x00\x01q\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\xff'
28 b'\xff\xff\xff\xc1\x12\xb9\x04\x96\xa4Z1t\x91\xdfsJ\x90\xf0\x9bh'
29 b'\x07l&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
30 b'\x00\x01D\xf8\x00\x00\x00\x00\x01\x1b\x00\x00\x01\xb8\x00\x00'
31 b'\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\x02\n'
32 b'\x0e\xc6&\xa1\x92\xae6\x0b\x02i\xfe-\xe5\xbao\x05\xd1\xe7\x00'
33 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01F'
34 b'\x13\x00\x00\x00\x00\x01\xec\x00\x00\x03\x06\x00\x00\x00\x01'
35 b'\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x12\xcb\xeby1'
36 b'\xb6\r\x98B\xcb\x07\xbd`\x8f\x92\xd9\xc4\x84\xbdK\x00\x00\x00'
37 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00'
38 )
39
40
14 @unittest.skipIf(rustext is None or cparsers is None, 41 @unittest.skipIf(rustext is None or cparsers is None,
15 "rustext.ancestor or the C Extension parsers module " 42 "rustext or the C Extension parsers module "
16 "it relies on is not available") 43 "ancestor relies on is not available")
17 class rustancestorstest(unittest.TestCase): 44 class rustancestorstest(unittest.TestCase):
18 """Test the correctness of binding to Rust code. 45 """Test the correctness of binding to Rust code.
19 46
20 This test is merely for the binding to Rust itself: extraction of 47 This test is merely for the binding to Rust itself: extraction of
21 Python variable, giving back the results etc. 48 Python variable, giving back the results etc.
25 good enough. 52 good enough.
26 53
27 Algorithmic correctness is asserted by the Rust unit tests. 54 Algorithmic correctness is asserted by the Rust unit tests.
28 """ 55 """
29 56
30 def testmodule(self): 57 def parseindex(self):
31 self.assertTrue('DAG' in rustext.ancestor.__doc__) 58 return cparsers.parse_index2(data_non_inlined, False)[0]
59
60 def testiteratorrevlist(self):
61 idx = self.parseindex()
62 # checking test assumption about the index binary data:
63 self.assertEqual({i: (r[5], r[6]) for i, r in enumerate(idx)},
64 {0: (-1, -1),
65 1: (0, -1),
66 2: (1, -1),
67 3: (2, -1)})
68 ait = AncestorsIterator(idx, [3], 0, True)
69 self.assertEqual([r for r in ait], [3, 2, 1, 0])
70
71 ait = AncestorsIterator(idx, [3], 0, False)
72 self.assertEqual([r for r in ait], [2, 1, 0])
73
74 def testrefcount(self):
75 idx = self.parseindex()
76 start_count = sys.getrefcount(idx)
77
78 # refcount increases upon iterator init...
79 ait = AncestorsIterator(idx, [3], 0, True)
80 self.assertEqual(sys.getrefcount(idx), start_count + 1)
81 self.assertEqual(next(ait), 3)
82
83 # and decreases once the iterator is removed
84 del ait
85 self.assertEqual(sys.getrefcount(idx), start_count)
86
87 # and removing ref to the index after iterator init is no issue
88 ait = AncestorsIterator(idx, [3], 0, True)
89 del idx
90 self.assertEqual([r for r in ait], [3, 2, 1, 0])
32 91
33 def testgrapherror(self): 92 def testgrapherror(self):
34 self.assertTrue('GraphError' in dir(rustext)) 93 data = (data_non_inlined[:64 + 27] +
94 b'\xf2' +
95 data_non_inlined[64 + 28:])
96 idx = cparsers.parse_index2(data, False)[0]
97 with self.assertRaises(rustext.GraphError) as arc:
98 AncestorsIterator(idx, [1], -1, False)
99 exc = arc.exception
100 self.assertIsInstance(exc, ValueError)
101 # rust-cpython issues appropriate str instances for Python 2 and 3
102 self.assertEqual(exc.args, ('ParentOutOfRange', 1))
35 103
36 104
37 if __name__ == '__main__': 105 if __name__ == '__main__':
38 import silenttestrunner 106 import silenttestrunner
39 silenttestrunner.main(__name__) 107 silenttestrunner.main(__name__)