test-rust-ancestor.py
167 lines
| 5.8 KiB
| text/x-python
|
PythonLexer
/ tests / test-rust-ancestor.py
Georges Racinet
|
r41083 | import sys | ||
Georges Racinet
|
r41004 | |||
Joerg Sonnenberger
|
r46729 | from mercurial.node import wdirrev | ||
Georges Racinet
|
r41386 | |||
r44397 | from mercurial.testing import revlog as revlogtesting | |||
Georges Racinet
|
r41004 | try: | ||
Georges Racinet
|
r53310 | from mercurial import pyo3_rustext, rustext | ||
Augie Fackler
|
r43346 | |||
Georges Racinet
|
r41083 | rustext.__name__ # trigger immediate actual import | ||
Georges Racinet
|
r53310 | pyo3_rustext.__name__ | ||
Georges Racinet
|
r41004 | except ImportError: | ||
Georges Racinet
|
r53310 | rustext = pyo3_rustext = None | ||
Georges Racinet
|
r41083 | else: | ||
# this would fail already without appropriate ancestor.__package__ | ||||
Georges Racinet
|
r41149 | from mercurial.rustext.ancestor import ( | ||
AncestorsIterator, | ||||
Georges Racinet
|
r41224 | LazyAncestors, | ||
MissingAncestors, | ||||
Georges Racinet
|
r41149 | ) | ||
Georges Racinet
|
r41843 | from mercurial.rustext import dagop | ||
Georges Racinet
|
r41004 | |||
try: | ||||
from mercurial.cext import parsers as cparsers | ||||
except ImportError: | ||||
cparsers = None | ||||
Georges Racinet
|
r41083 | |||
Georges Racinet on incendie.racinet.fr
|
r52137 | class rustancestorstest(revlogtesting.RustRevlogBasedTestBase): | ||
Georges Racinet
|
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. | ||||
""" | ||||
Georges Racinet
|
r41083 | def testiteratorrevlist(self): | ||
Georges Racinet
|
r52132 | idx = self.parserustindex() | ||
Georges Racinet
|
r41083 | # checking test assumption about the index binary data: | ||
Augie Fackler
|
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)}, | ||||
) | ||||
Georges Racinet
|
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]) | ||||
Georges Racinet
|
r41149 | def testlazyancestors(self): | ||
Georges Racinet
|
r52132 | idx = self.parserustindex() | ||
Georges Racinet
|
r53302 | start_count = sys.getrefcount(idx.inner) # should be 2 (see Python doc) | ||
Augie Fackler
|
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)}, | ||||
) | ||||
Georges Racinet
|
r41149 | lazy = LazyAncestors(idx, [3], 0, True) | ||
Georges Racinet
|
r53302 | # the LazyAncestors instance holds just one reference to the | ||
# inner revlog. | ||||
self.assertEqual(sys.getrefcount(idx.inner), start_count + 1) | ||||
Georges Racinet
|
r41149 | |||
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) | ||||
Georges Racinet
|
r53302 | self.assertEqual(sys.getrefcount(idx.inner), start_count + 2) | ||
Georges Racinet
|
r41149 | del ait | ||
Georges Racinet
|
r53302 | self.assertEqual(sys.getrefcount(idx.inner), start_count + 1) | ||
Georges Racinet
|
r41149 | del lazy | ||
Georges Racinet
|
r53302 | self.assertEqual(sys.getrefcount(idx.inner), start_count) | ||
Georges Racinet
|
r41149 | |||
# let's check bool for an empty one | ||||
self.assertFalse(LazyAncestors(idx, [0], 0, False)) | ||||
Georges Racinet
|
r41224 | def testmissingancestors(self): | ||
Georges Racinet on incendie.racinet.fr
|
r52133 | idx = self.parserustindex() | ||
Georges Racinet
|
r41224 | missanc = MissingAncestors(idx, [1]) | ||
self.assertTrue(missanc.hasbases()) | ||||
self.assertEqual(missanc.missingancestors([3]), [2, 3]) | ||||
missanc.addbases({2}) | ||||
Georges Racinet
|
r41279 | self.assertEqual(missanc.bases(), {1, 2}) | ||
Georges Racinet
|
r41224 | self.assertEqual(missanc.missingancestors([3]), [3]) | ||
Georges Racinet
|
r41282 | self.assertEqual(missanc.basesheads(), {2}) | ||
Georges Racinet
|
r41224 | |||
def testmissingancestorsremove(self): | ||||
Georges Racinet on incendie.racinet.fr
|
r52133 | idx = self.parserustindex() | ||
Georges Racinet
|
r41224 | missanc = MissingAncestors(idx, [1]) | ||
revs = {0, 1, 2, 3} | ||||
missanc.removeancestorsfrom(revs) | ||||
self.assertEqual(revs, {2, 3}) | ||||
Georges Racinet
|
r41083 | def testrefcount(self): | ||
Georges Racinet
|
r52132 | idx = self.parserustindex() | ||
Georges Racinet
|
r53302 | start_count = sys.getrefcount(idx.inner) | ||
Georges Racinet
|
r41083 | |||
# refcount increases upon iterator init... | ||||
ait = AncestorsIterator(idx, [3], 0, True) | ||||
Georges Racinet
|
r53302 | self.assertEqual(sys.getrefcount(idx.inner), start_count + 1) | ||
Georges Racinet
|
r41083 | self.assertEqual(next(ait), 3) | ||
# and decreases once the iterator is removed | ||||
del ait | ||||
Georges Racinet
|
r53302 | self.assertEqual(sys.getrefcount(idx.inner), start_count) | ||
Georges Racinet
|
r41083 | |||
# and removing ref to the index after iterator init is no issue | ||||
ait = AncestorsIterator(idx, [3], 0, True) | ||||
del idx | ||||
Georges Racinet
|
r41149 | self.assertEqual(list(ait), [3, 2, 1, 0]) | ||
Georges Racinet
|
r41004 | |||
Georges Racinet
|
r52132 | # the index is not tracked by the GC, hence there is nothing more | ||
# we can assert to check that it is properly deleted once its refcount | ||||
# drops to 0 | ||||
Georges Racinet
|
r41004 | def testgrapherror(self): | ||
Augie Fackler
|
r43346 | data = ( | ||
r44397 | revlogtesting.data_non_inlined[: 64 + 27] | |||
+ b'\xf2' | ||||
+ revlogtesting.data_non_inlined[64 + 28 :] | ||||
Augie Fackler
|
r43346 | ) | ||
Georges Racinet
|
r52132 | idx = self.parserustindex(data=data) | ||
Georges Racinet
|
r41083 | 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)) | ||||
Georges Racinet
|
r41004 | |||
Georges Racinet
|
r41386 | def testwdirunsupported(self): | ||
# trying to access ancestors of the working directory raises | ||||
Georges Racinet
|
r52132 | idx = self.parserustindex() | ||
Raphaël Gomès
|
r51872 | with self.assertRaises(rustext.GraphError) as arc: | ||
Joerg Sonnenberger
|
r46729 | list(AncestorsIterator(idx, [wdirrev], -1, False)) | ||
Georges Racinet
|
r41004 | |||
Raphaël Gomès
|
r51872 | exc = arc.exception | ||
self.assertIsInstance(exc, ValueError) | ||||
# rust-cpython issues appropriate str instances for Python 2 and 3 | ||||
self.assertEqual(exc.args, ('InvalidRevision', wdirrev)) | ||||
Georges Racinet
|
r41843 | def testheadrevs(self): | ||
Georges Racinet
|
r52134 | idx = self.parserustindex() | ||
Georges Racinet
|
r41843 | self.assertEqual(dagop.headrevs(idx, [1, 2, 3]), {3}) | ||
Georges Racinet
|
r53310 | def testpyo3_headrevs(self): | ||
idx = self.parserustindex() | ||||
self.assertEqual(pyo3_rustext.dagop.headrevs(idx, [1, 2, 3]), {3}) | ||||
def testpyo3_rank(self): | ||||
idx = self.parserustindex() | ||||
try: | ||||
pyo3_rustext.dagop.rank(idx, 1, 2) | ||||
except pyo3_rustext.GraphError as exc: | ||||
self.assertEqual(exc.args, ("InconsistentGraphData",)) | ||||
Augie Fackler
|
r43346 | |||
Georges Racinet
|
r41004 | if __name__ == '__main__': | ||
import silenttestrunner | ||||
Augie Fackler
|
r43346 | |||
Georges Racinet
|
r41004 | silenttestrunner.main(__name__) | ||