##// END OF EJS Templates
revlog: subclass the new `repository.iverifyproblem` Protocol class...
revlog: subclass the new `repository.iverifyproblem` Protocol class This is the same transformation as 3a90a6fd710d did for dirstate, but the CamelCase naming was already cleaned up here. We shouldn't have to explicitly subclass, but I'm doing so to test the interplay of regular attributes and the `attrs` class. Also, PyCharm has a nifty feature that puts a jump point in the gutter to navigate back and forth between the base class and subclasses (and override functions and base class functions) when there's an explicit subclassing. Additionally, PyCharm will immediately flag signature mismatches without a 40m pytype run.

File last commit:

r53310:20fe0bf9 default
r53365:4ef6dbc2 default
Show More
test-rust-ancestor.py
167 lines | 5.8 KiB | text/x-python | PythonLexer
/ tests / test-rust-ancestor.py
import sys
from mercurial.node import wdirrev
from mercurial.testing import revlog as revlogtesting
try:
from mercurial import pyo3_rustext, rustext
rustext.__name__ # trigger immediate actual import
pyo3_rustext.__name__
except ImportError:
rustext = pyo3_rustext = None
else:
# this would fail already without appropriate ancestor.__package__
from mercurial.rustext.ancestor import (
AncestorsIterator,
LazyAncestors,
MissingAncestors,
)
from mercurial.rustext import dagop
try:
from mercurial.cext import parsers as cparsers
except ImportError:
cparsers = None
class rustancestorstest(revlogtesting.RustRevlogBasedTestBase):
"""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.
"""
def testiteratorrevlist(self):
idx = self.parserustindex()
# checking test assumption about the index binary data:
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)},
)
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])
def testlazyancestors(self):
idx = self.parserustindex()
start_count = sys.getrefcount(idx.inner) # should be 2 (see Python doc)
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)},
)
lazy = LazyAncestors(idx, [3], 0, True)
# the LazyAncestors instance holds just one reference to the
# inner revlog.
self.assertEqual(sys.getrefcount(idx.inner), start_count + 1)
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.inner), start_count + 2)
del ait
self.assertEqual(sys.getrefcount(idx.inner), start_count + 1)
del lazy
self.assertEqual(sys.getrefcount(idx.inner), start_count)
# let's check bool for an empty one
self.assertFalse(LazyAncestors(idx, [0], 0, False))
def testmissingancestors(self):
idx = self.parserustindex()
missanc = MissingAncestors(idx, [1])
self.assertTrue(missanc.hasbases())
self.assertEqual(missanc.missingancestors([3]), [2, 3])
missanc.addbases({2})
self.assertEqual(missanc.bases(), {1, 2})
self.assertEqual(missanc.missingancestors([3]), [3])
self.assertEqual(missanc.basesheads(), {2})
def testmissingancestorsremove(self):
idx = self.parserustindex()
missanc = MissingAncestors(idx, [1])
revs = {0, 1, 2, 3}
missanc.removeancestorsfrom(revs)
self.assertEqual(revs, {2, 3})
def testrefcount(self):
idx = self.parserustindex()
start_count = sys.getrefcount(idx.inner)
# refcount increases upon iterator init...
ait = AncestorsIterator(idx, [3], 0, True)
self.assertEqual(sys.getrefcount(idx.inner), start_count + 1)
self.assertEqual(next(ait), 3)
# and decreases once the iterator is removed
del ait
self.assertEqual(sys.getrefcount(idx.inner), start_count)
# and removing ref to the index after iterator init is no issue
ait = AncestorsIterator(idx, [3], 0, True)
del idx
self.assertEqual(list(ait), [3, 2, 1, 0])
# 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
def testgrapherror(self):
data = (
revlogtesting.data_non_inlined[: 64 + 27]
+ b'\xf2'
+ revlogtesting.data_non_inlined[64 + 28 :]
)
idx = self.parserustindex(data=data)
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))
def testwdirunsupported(self):
# trying to access ancestors of the working directory raises
idx = self.parserustindex()
with self.assertRaises(rustext.GraphError) as arc:
list(AncestorsIterator(idx, [wdirrev], -1, False))
exc = arc.exception
self.assertIsInstance(exc, ValueError)
# rust-cpython issues appropriate str instances for Python 2 and 3
self.assertEqual(exc.args, ('InvalidRevision', wdirrev))
def testheadrevs(self):
idx = self.parserustindex()
self.assertEqual(dagop.headrevs(idx, [1, 2, 3]), {3})
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",))
if __name__ == '__main__':
import silenttestrunner
silenttestrunner.main(__name__)