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