Skip to content
Snippets Groups Projects
Commit 674e1e7be85a authored by Georges Racinet's avatar Georges Racinet :squid:
Browse files

rust-pyo3: reviving test-rust-revlog.py

This test file was removed in 7346f93be7a4. Adaptation to the
new `InnerRevlog` / `RustIndexProxy` structure was as easy as
redefining the `parserustindex()` method to use `RustIndexProxy`.

As we did before with `test-rust-ancestors.py`, we are preparing
a mixin class that will contain tests for both bindings.
Existing tests will migrate from `RustInnerRevlogTest`
(the one for `hg-cpython`) to the mixin.
parent d55f2f7d2785
No related merge requests found
......@@ -44,5 +44,15 @@
rust_revlog = None
try:
from ..pyo3_rustext import ( # pytype: disable=import-error
revlog as pyo3_revlog,
)
pyo3_revlog.__name__ # force actual import
except ImportError:
pyo3_revlog = None
@unittest.skipIf(
cparsers is None,
......@@ -47,6 +57,9 @@
@unittest.skipIf(
cparsers is None,
'The C version of the "parsers" module is not available. It is needed for this test.',
(
'The C version of the "parsers" module is not available. '
'It is needed for this test.'
),
)
class RevlogBasedTestBase(unittest.TestCase):
def parseindex(self, data=None):
......@@ -65,9 +78,17 @@
revlog_delta_config = revlog.DeltaConfig()
revlog_feature_config = revlog.FeatureConfig()
@classmethod
def irl_class(cls):
return rust_revlog.InnerRevlog
@classmethod
def nodetree(cls, idx):
return rust_revlog.NodeTree(idx)
def make_inner_revlog(
self, data=None, vfs_is_readonly=True, kind=KIND_CHANGELOG
):
if data is None:
data = data_non_inlined
......@@ -68,10 +89,10 @@
def make_inner_revlog(
self, data=None, vfs_is_readonly=True, kind=KIND_CHANGELOG
):
if data is None:
data = data_non_inlined
return rust_revlog.InnerRevlog(
return self.irl_class()(
vfs_base=b"Just a path",
fncache=None, # might be enough for now
vfs_is_readonly=vfs_is_readonly,
......@@ -91,3 +112,17 @@
def parserustindex(self, data=None):
return revlog.RustIndexProxy(self.make_inner_revlog(data=data))
@unittest.skipIf(
pyo3_revlog is None,
'The Rust PyO3 revlog module is not available. It is needed for this test.',
)
class PyO3RevlogBasedTestBase(RustRevlogBasedTestBase):
@classmethod
def irl_class(cls):
return pyo3_revlog.InnerRevlog
@classmethod
def nodetree(cls, idx):
return pyo3_revlog.NodeTree(idx)
import struct
from mercurial.node import (
bin as node_bin,
hex,
)
try:
from mercurial import rustext
rustext.__name__ # trigger immediate actual import
except ImportError:
rustext = None
else:
# this would fail already without appropriate ancestor.__package__
from mercurial.rustext.ancestor import LazyAncestors
from mercurial.testing import revlog as revlogtesting
header = struct.unpack(">I", revlogtesting.data_non_inlined[:4])[0]
class RustInnerRevlogTestMixin:
"""Common tests for both Rust Python bindings."""
node_hex0 = b'd1f4bbb0befc13bd8cd39d0fcdd93b8c078c4a2f'
node0 = node_bin(node_hex0)
# Conditional skipping done by the base class
class RustInnerRevlogTest(
revlogtesting.RustRevlogBasedTestBase, RustInnerRevlogTestMixin
):
"""For reference"""
def test_heads(self):
idx = self.parserustindex()
self.assertEqual(idx.headrevs(), [3])
def test_len(self):
idx = self.parserustindex()
self.assertEqual(len(idx), 4)
def test_ancestors(self):
rustidx = self.parserustindex()
lazy = LazyAncestors(rustidx, [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.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])
# let's check bool for an empty one
self.assertFalse(LazyAncestors(rustidx, [0], 0, False))
def test_standalone_nodetree(self):
idx = self.parserustindex()
nt = self.nodetree(idx)
for i in range(4):
nt.insert(i)
bin_nodes = [entry[7] for entry in idx]
hex_nodes = [hex(n) for n in bin_nodes]
for i, node in enumerate(hex_nodes):
self.assertEqual(nt.prefix_rev_lookup(node), i)
self.assertEqual(nt.prefix_rev_lookup(node[:5]), i)
# all 4 revisions in idx (standard data set) have different
# first nybbles in their Node IDs,
# hence `nt.shortest()` should return 1 for them, except when
# the leading nybble is 0 (ambiguity with NULL_NODE)
for i, (bin_node, hex_node) in enumerate(zip(bin_nodes, hex_nodes)):
shortest = nt.shortest(bin_node)
expected = 2 if hex_node[0] == ord('0') else 1
self.assertEqual(shortest, expected)
self.assertEqual(nt.prefix_rev_lookup(hex_node[:shortest]), i)
# test invalidation (generation poisoning) detection
del idx[3]
self.assertTrue(nt.is_invalidated())
# Conditional skipping done by the base class
class PyO3InnerRevlogTest(
revlogtesting.PyO3RevlogBasedTestBase, RustInnerRevlogTestMixin
):
"""Testing new PyO3 bindings, by comparison with rust-cpython bindings."""
if __name__ == '__main__':
import silenttestrunner
silenttestrunner.main(__name__)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment