test-rust-ancestor.py
163 lines
| 5.4 KiB
| text/x-python
|
PythonLexer
/ tests / test-rust-ancestor.py
|
r41004 | from __future__ import absolute_import | ||
|
r41083 | import sys | ||
|
r41004 | import unittest | ||
|
r41386 | from mercurial import ( | ||
error, | ||||
node, | ||||
) | ||||
r44397 | from mercurial.testing import revlog as revlogtesting | |||
|
r41004 | try: | ||
from mercurial import rustext | ||||
|
r43346 | |||
|
r41083 | rustext.__name__ # trigger immediate actual import | ||
|
r41004 | except ImportError: | ||
rustext = None | ||||
|
r41083 | else: | ||
# this would fail already without appropriate ancestor.__package__ | ||||
|
r41149 | from mercurial.rustext.ancestor import ( | ||
AncestorsIterator, | ||||
|
r41224 | LazyAncestors, | ||
MissingAncestors, | ||||
|
r41149 | ) | ||
|
r41843 | from mercurial.rustext import dagop | ||
|
r41004 | |||
try: | ||||
from mercurial.cext import parsers as cparsers | ||||
except ImportError: | ||||
cparsers = None | ||||
|
r41083 | |||
|
r43346 | @unittest.skipIf( | ||
r44397 | rustext is None, | |||
'The Rust version of the "ancestor" module is not available. It is needed' | ||||
' for this test.', | ||||
|
r43346 | ) | ||
r44397 | @unittest.skipIf( | |||
rustext is None, | ||||
'The Rust or C version of the "parsers" module, which the "ancestor" module' | ||||
' relies on, is not available.', | ||||
) | ||||
class rustancestorstest(revlogtesting.RevlogBasedTestBase): | ||||
|
r41004 | """Test the correctness of binding to Rust code. | ||
This test is merely for the binding to Rust itself: extraction of | ||||
Python variable, giving back the results etc. | ||||
It is not meant to test the algorithmic correctness of the operations | ||||
on ancestors it provides. Hence the very simple embedded index data is | ||||
good enough. | ||||
Algorithmic correctness is asserted by the Rust unit tests. | ||||
""" | ||||
|
r41083 | def testiteratorrevlist(self): | ||
idx = self.parseindex() | ||||
# checking test assumption about the index binary data: | ||||
|
r43346 | self.assertEqual( | ||
{i: (r[5], r[6]) for i, r in enumerate(idx)}, | ||||
{0: (-1, -1), 1: (0, -1), 2: (1, -1), 3: (2, -1)}, | ||||
) | ||||
|
r41083 | ait = AncestorsIterator(idx, [3], 0, True) | ||
self.assertEqual([r for r in ait], [3, 2, 1, 0]) | ||||
ait = AncestorsIterator(idx, [3], 0, False) | ||||
self.assertEqual([r for r in ait], [2, 1, 0]) | ||||
|
r41149 | def testlazyancestors(self): | ||
idx = self.parseindex() | ||||
start_count = sys.getrefcount(idx) # should be 2 (see Python doc) | ||||
|
r43346 | self.assertEqual( | ||
{i: (r[5], r[6]) for i, r in enumerate(idx)}, | ||||
{0: (-1, -1), 1: (0, -1), 2: (1, -1), 3: (2, -1)}, | ||||
) | ||||
|
r41149 | lazy = LazyAncestors(idx, [3], 0, True) | ||
# we have two more references to the index: | ||||
# - in its inner iterator for __contains__ and __bool__ | ||||
# - in the LazyAncestors instance itself (to spawn new iterators) | ||||
self.assertEqual(sys.getrefcount(idx), start_count + 2) | ||||
self.assertTrue(2 in lazy) | ||||
self.assertTrue(bool(lazy)) | ||||
self.assertEqual(list(lazy), [3, 2, 1, 0]) | ||||
# a second time to validate that we spawn new iterators | ||||
self.assertEqual(list(lazy), [3, 2, 1, 0]) | ||||
# now let's watch the refcounts closer | ||||
ait = iter(lazy) | ||||
self.assertEqual(sys.getrefcount(idx), start_count + 3) | ||||
del ait | ||||
self.assertEqual(sys.getrefcount(idx), start_count + 2) | ||||
del lazy | ||||
self.assertEqual(sys.getrefcount(idx), start_count) | ||||
# let's check bool for an empty one | ||||
self.assertFalse(LazyAncestors(idx, [0], 0, False)) | ||||
|
r41224 | def testmissingancestors(self): | ||
idx = self.parseindex() | ||||
missanc = MissingAncestors(idx, [1]) | ||||
self.assertTrue(missanc.hasbases()) | ||||
self.assertEqual(missanc.missingancestors([3]), [2, 3]) | ||||
missanc.addbases({2}) | ||||
|
r41279 | self.assertEqual(missanc.bases(), {1, 2}) | ||
|
r41224 | self.assertEqual(missanc.missingancestors([3]), [3]) | ||
|
r41282 | self.assertEqual(missanc.basesheads(), {2}) | ||
|
r41224 | |||
def testmissingancestorsremove(self): | ||||
idx = self.parseindex() | ||||
missanc = MissingAncestors(idx, [1]) | ||||
revs = {0, 1, 2, 3} | ||||
missanc.removeancestorsfrom(revs) | ||||
self.assertEqual(revs, {2, 3}) | ||||
|
r41083 | def testrefcount(self): | ||
idx = self.parseindex() | ||||
start_count = sys.getrefcount(idx) | ||||
# refcount increases upon iterator init... | ||||
ait = AncestorsIterator(idx, [3], 0, True) | ||||
self.assertEqual(sys.getrefcount(idx), start_count + 1) | ||||
self.assertEqual(next(ait), 3) | ||||
# and decreases once the iterator is removed | ||||
del ait | ||||
self.assertEqual(sys.getrefcount(idx), start_count) | ||||
# and removing ref to the index after iterator init is no issue | ||||
ait = AncestorsIterator(idx, [3], 0, True) | ||||
del idx | ||||
|
r41149 | self.assertEqual(list(ait), [3, 2, 1, 0]) | ||
|
r41004 | |||
def testgrapherror(self): | ||||
|
r43346 | data = ( | ||
r44397 | revlogtesting.data_non_inlined[: 64 + 27] | |||
+ b'\xf2' | ||||
+ revlogtesting.data_non_inlined[64 + 28 :] | ||||
|
r43346 | ) | ||
|
r41083 | idx = cparsers.parse_index2(data, False)[0] | ||
with self.assertRaises(rustext.GraphError) as arc: | ||||
AncestorsIterator(idx, [1], -1, False) | ||||
exc = arc.exception | ||||
self.assertIsInstance(exc, ValueError) | ||||
# rust-cpython issues appropriate str instances for Python 2 and 3 | ||||
self.assertEqual(exc.args, ('ParentOutOfRange', 1)) | ||||
|
r41004 | |||
|
r41386 | def testwdirunsupported(self): | ||
# trying to access ancestors of the working directory raises | ||||
# WdirUnsupported directly | ||||
idx = self.parseindex() | ||||
with self.assertRaises(error.WdirUnsupported): | ||||
list(AncestorsIterator(idx, [node.wdirrev], -1, False)) | ||||
|
r41004 | |||
|
r41843 | def testheadrevs(self): | ||
idx = self.parseindex() | ||||
self.assertEqual(dagop.headrevs(idx, [1, 2, 3]), {3}) | ||||
|
r43346 | |||
|
r41004 | if __name__ == '__main__': | ||
import silenttestrunner | ||||
|
r43346 | |||
|
r41004 | silenttestrunner.main(__name__) | ||