Mercurial > public > mercurial-scm > hg-stable
diff tests/test-rust-revlog.py @ 53031:e705fec4a03f stable
branching: merging with 7.0 changes
Since 6.9.3 was made after 7.0rc0 we need to deal with more branching than
usual.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Wed, 05 Mar 2025 23:02:19 +0100 |
parents | 3fcd86374074 |
children |
line wrap: on
line diff
--- a/tests/test-rust-revlog.py Wed Mar 05 22:33:11 2025 +0100 +++ b/tests/test-rust-revlog.py Wed Mar 05 23:02:19 2025 +0100 @@ -1,7 +1,10 @@ import struct -import unittest -from mercurial.node import hex +from mercurial.node import ( + bin as node_bin, + hex, +) +from mercurial import error try: from mercurial import rustext @@ -10,8 +13,6 @@ except ImportError: rustext = None else: - from mercurial.rustext import revlog - # this would fail already without appropriate ancestor.__package__ from mercurial.rustext.ancestor import LazyAncestors @@ -20,48 +21,124 @@ header = struct.unpack(">I", revlogtesting.data_non_inlined[:4])[0] -@unittest.skipIf( - rustext is None, - "rustext module revlog relies on is not available", -) -class RustRevlogIndexTest(revlogtesting.RevlogBasedTestBase): - def test_heads(self): - idx = self.parseindex() - rustidx = revlog.Index(revlogtesting.data_non_inlined, header) - self.assertEqual(rustidx.headrevs(), idx.headrevs()) +class RustInnerRevlogTestMixin: + """Common tests for both Rust Python bindings.""" + + node_hex0 = b'd1f4bbb0befc13bd8cd39d0fcdd93b8c078c4a2f' + node0 = node_bin(node_hex0) + bogus_node_hex = b'cafe' * 10 + bogus_node = node_bin(bogus_node_hex) + node_hex2 = b"020a0ec626a192ae360b0269fe2de5ba6f05d1e7" + node2 = node_bin(node_hex2) + + def test_index_nodemap(self): + idx = self.parserustindex() + self.assertTrue(idx.has_node(self.node0)) + self.assertFalse(idx.has_node(self.bogus_node)) + + self.assertEqual(idx.get_rev(self.node0), 0) + self.assertEqual(idx.get_rev(self.node0), 0) + + self.assertEqual(idx.rev(self.node0), 0) + with self.assertRaises(error.RevlogError) as exc_info: + idx.rev(self.bogus_node) + self.assertEqual(exc_info.exception.args, (None,)) + + self.assertEqual(idx.partialmatch(self.node_hex0[:3]), self.node0) + self.assertIsNone(idx.partialmatch(self.bogus_node_hex[:3])) + self.assertEqual(idx.shortest(self.node0), 1) def test_len(self): - idx = self.parseindex() - rustidx = revlog.Index(revlogtesting.data_non_inlined, header) - self.assertEqual(len(rustidx), len(idx)) + idx = self.parserustindex() + self.assertEqual(len(idx), 4) + + def test_getitem(self): + idx = self.parserustindex() + as_tuple = (0, 82969, 484626, 0, 0, -1, -1, self.node0, 0, 0, 2, 2, -1) + self.assertEqual(idx[0], as_tuple) + self.assertEqual(idx[self.node0], 0) + + def test_heads(self): + idx = self.parserustindex() + self.assertEqual(idx.headrevs(), [3]) + + def test_index_append(self): + idx = self.parserustindex(data=b'') + self.assertEqual(len(idx), 0) + self.assertIsNone(idx.get_rev(self.node0)) + + non_empty_index = self.parserustindex() + idx.append(non_empty_index[0]) + self.assertEqual(len(idx), 1) + self.assertEqual(idx.get_rev(self.node0), 0) + + def test_index_delitem_single(self): + idx = self.parserustindex() + del idx[2] + self.assertEqual(len(idx), 2) + + # the nodetree is consistent + self.assertEqual(idx.get_rev(self.node0), 0) + self.assertIsNone(idx.get_rev(self.node2)) + + # not an error and does nothing + del idx[-1] + self.assertEqual(len(idx), 2) - def test_ancestors(self): - rustidx = revlog.Index(revlogtesting.data_non_inlined, header) - 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]) + for bogus in (-2, 17): + try: + del idx[bogus] + except ValueError as exc: + # this underlines that we should do better with this message + assert exc.args[0] == ( + f"Inconsistency: Revision {bogus} found in nodemap " + "is not in revlog index" + ) + else: + raise AssertionError( + f"an exception was expected for `del idx[{bogus}]`" + ) + + def test_index_delitem_slice(self): + idx = self.parserustindex() + del idx[2:3] + self.assertEqual(len(idx), 2) - # let's check bool for an empty one - self.assertFalse(LazyAncestors(rustidx, [0], 0, False)) - + # not an error and not equivalent to `del idx[0::]` but to + # `del idx[-1]` instead and thus does nothing. + del idx[-1::] + self.assertEqual(len(idx), 2) -@unittest.skipIf( - rustext is None, - "rustext module revlog relies on is not available", -) -class RustRevlogNodeTreeClassTest(revlogtesting.RustRevlogBasedTestBase): + for start, stop in ( + (-2, None), + (17, None), + ): + try: + del idx[start:stop] + except ValueError as exc: + # this underlines that we should do better with this message + assert exc.args[0] == ( + f"Inconsistency: Revision {start} found in nodemap " + "is not in revlog index" + ) + else: + raise AssertionError( + f"an exception was expected for `del idx[{start}:{stop}]`" + ) + + # although the upper bound is way too big, this is not an error: + del idx[0::17] + self.assertEqual(len(idx), 0) + def test_standalone_nodetree(self): idx = self.parserustindex() - nt = revlog.NodeTree(idx) + nt = self.nodetree(idx) for i in range(4): nt.insert(i) + # invalidation is upon mutation *of the index* + self.assertFalse(nt.is_invalidated()) + bin_nodes = [entry[7] for entry in idx] hex_nodes = [hex(n) for n in bin_nodes] @@ -83,6 +160,49 @@ del idx[3] self.assertTrue(nt.is_invalidated()) + def test_reading_context_manager(self): + irl = self.make_inner_revlog() + try: + with irl.reading(): + # not much to do yet + pass + except error.RevlogError as exc: + # well our data file does not even exist + self.assertTrue(b"when reading Just a path/test.d" in exc.args[0]) + + +# Conditional skipping done by the base class +class RustInnerRevlogTest( + revlogtesting.RustRevlogBasedTestBase, RustInnerRevlogTestMixin +): + """For reference""" + + 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_canonical_index_file(self): + irl = self.make_inner_revlog() + self.assertEqual(irl.canonical_index_file, b'test.i') + + +# 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