# HG changeset patch # User Pierre-Yves David # Date 1675167399 -3600 # Node ID 6515d9a6592dc07ba59fbefbdf69324a9730dcb0 # Parent be019ac8c1e4b76e56cfec2f89a63fe0103ce72c run-tests: make it possible to nest conditionals This is not that hard to implement and makes our life easier on a regular basis. diff -r be019ac8c1e4 -r 6515d9a6592d 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