run-tests: make it possible to nest conditionals stable
authorPierre-Yves David <pierre-yves.david@octobus.net>
Tue, 31 Jan 2023 13:16:39 +0100
branchstable
changeset 50210 6515d9a6592d
parent 50180 be019ac8c1e4
child 50211 f5e4248e5bce
run-tests: make it possible to nest conditionals This is not that hard to implement and makes our life easier on a regular basis.
tests/run-tests.py
--- a/tests/run-tests.py	Mon Nov 28 12:33:20 2022 +0100
+++ b/tests/run-tests.py	Tue Jan 31 13:16:39 2023 +0100
@@ -1834,8 +1834,44 @@
 
         pos = prepos = -1
 
-        # True or False when in a true or false conditional section
-        skipping = None
+        # The current stack of conditionnal section.
+        # Each relevant conditionnal section can have the following value:
+        #  - True:  we should run this block
+        #  - False: we should skip this block
+        #  - None:  The parent block is skipped,
+        #           (no branch of this one will ever run)
+        condition_stack = []
+
+        def run_line():
+            """return True if the current line should be run"""
+            if not condition_stack:
+                return True
+            return bool(condition_stack[-1])
+
+        def push_conditional_block(should_run):
+            """Push a new conditional context, with its initial state
+
+            i.e. entry a #if block"""
+            if not run_line():
+                condition_stack.append(None)
+            else:
+                condition_stack.append(should_run)
+
+        def flip_conditional():
+            """reverse the current condition state
+
+            i.e. enter a #else
+            """
+            assert condition_stack
+            if condition_stack[-1] is not None:
+                condition_stack[-1] = not condition_stack[-1]
+
+        def pop_conditional():
+            """exit the current skipping context
+
+            i.e. reach the #endif"""
+            assert condition_stack
+            condition_stack.pop()
 
         # We keep track of whether or not we're in a Python block so we
         # can generate the surrounding doctest magic.
@@ -1891,7 +1927,7 @@
                     after.setdefault(pos, []).append(
                         b'  !!! invalid #require\n'
                     )
-                if not skipping:
+                if run_line():
                     haveresult, message = self._hghave(lsplit[1:])
                     if not haveresult:
                         script = [b'echo "%s"\nexit 80\n' % message]
@@ -1901,21 +1937,19 @@
                 lsplit = l.split()
                 if len(lsplit) < 2 or lsplit[0] != b'#if':
                     after.setdefault(pos, []).append(b'  !!! invalid #if\n')
-                if skipping is not None:
-                    after.setdefault(pos, []).append(b'  !!! nested #if\n')
-                skipping = not self._iftest(lsplit[1:])
+                push_conditional_block(self._iftest(lsplit[1:]))
                 after.setdefault(pos, []).append(l)
             elif l.startswith(b'#else'):
-                if skipping is None:
+                if not condition_stack:
                     after.setdefault(pos, []).append(b'  !!! missing #if\n')
-                skipping = not skipping
+                flip_conditional()
                 after.setdefault(pos, []).append(l)
             elif l.startswith(b'#endif'):
-                if skipping is None:
+                if not condition_stack:
                     after.setdefault(pos, []).append(b'  !!! missing #if\n')
-                skipping = None
+                pop_conditional()
                 after.setdefault(pos, []).append(l)
-            elif skipping:
+            elif not run_line():
                 after.setdefault(pos, []).append(l)
             elif l.startswith(b'  >>> '):  # python inlines
                 after.setdefault(pos, []).append(l)
@@ -1960,7 +1994,7 @@
 
         if inpython:
             script.append(b'EOF\n')
-        if skipping is not None:
+        if condition_stack:
             after.setdefault(pos, []).append(b'  !!! missing #endif\n')
         addsalt(n + 1, False)
         # Need to end any current per-command trace