Mercurial > hg
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__) |