zig0

my attempts at zig bootstrapping in C
Log | Files | Refs | README | LICENSE

check_test_order.py (4284B) - Raw


      1 #!/usr/bin/env python3
      2 """Check and optionally fix test order in parser_test.zig to match upstream."""
      3 
      4 import re
      5 import sys
      6 
      7 OURS = "parser_test.zig"
      8 UPSTREAM = "../zig/lib/std/zig/parser_test.zig"
      9 
     10 
     11 def extract_test_names(path):
     12     with open(path) as f:
     13         return re.findall(r'^test "(.+?)" \{', f.read(), re.M)
     14 
     15 
     16 def extract_test_blocks(path):
     17     """Split file into: header, list of (name, content) test blocks, footer."""
     18     with open(path) as f:
     19         lines = f.readlines()
     20 
     21     header = []
     22     footer = []
     23     blocks = []
     24     current_name = None
     25     current_lines = []
     26     brace_depth = 0
     27     in_test = False
     28     found_first_test = False
     29 
     30     for line in lines:
     31         m = re.match(r'^test "(.+?)" \{', line)
     32         if m and not in_test:
     33             found_first_test = True
     34             if current_name is not None:
     35                 blocks.append((current_name, "".join(current_lines)))
     36             current_name = m.group(1)
     37             current_lines = [line]
     38             brace_depth = 1
     39             in_test = True
     40             continue
     41 
     42         if in_test:
     43             current_lines.append(line)
     44             brace_depth += line.count("{") - line.count("}")
     45             if brace_depth == 0:
     46                 in_test = False
     47         elif not found_first_test:
     48             header.append(line)
     49         else:
     50             # Non-test content after tests started — could be blank lines
     51             # between tests or footer content
     52             if current_name is not None:
     53                 # Append to previous test block as trailing content
     54                 current_lines.append(line)
     55             else:
     56                 footer.append(line)
     57 
     58     if current_name is not None:
     59         blocks.append((current_name, "".join(current_lines)))
     60 
     61     # Anything after the last test block is footer
     62     # Split last block's trailing non-test content into footer
     63     if blocks:
     64         last_name, last_content = blocks[-1]
     65         last_lines = last_content.split('\n')
     66         # Find where the test block ends (} at column 0)
     67         test_end = len(last_lines)
     68         for i, line in enumerate(last_lines):
     69             if line == '}' and i > 0:
     70                 test_end = i + 1
     71         if test_end < len(last_lines):
     72             blocks[-1] = (last_name, '\n'.join(last_lines[:test_end]) + '\n')
     73             footer = ['\n'.join(last_lines[test_end:]) + '\n'] + footer
     74 
     75     return "".join(header), blocks, "".join(footer)
     76 
     77 
     78 def main():
     79     fix = "--fix" in sys.argv
     80 
     81     upstream_order = extract_test_names(UPSTREAM)
     82     our_names = extract_test_names(OURS)
     83 
     84     # Build position map for upstream
     85     upstream_pos = {name: i for i, name in enumerate(upstream_order)}
     86 
     87     # Check order
     88     our_in_upstream = [n for n in our_names if n in upstream_pos]
     89     positions = [upstream_pos[n] for n in our_in_upstream]
     90     is_sorted = positions == sorted(positions)
     91 
     92     if is_sorted:
     93         print(f"OK: {len(our_names)} tests in correct order")
     94         return 0
     95 
     96     # Find out-of-order tests
     97     out_of_order = []
     98     prev_pos = -1
     99     for name in our_in_upstream:
    100         pos = upstream_pos[name]
    101         if pos < prev_pos:
    102             out_of_order.append(name)
    103         prev_pos = max(prev_pos, pos)
    104 
    105     print(f"WARN: {len(out_of_order)} tests out of order:")
    106     for name in out_of_order[:10]:
    107         print(f"  - {name}")
    108     if len(out_of_order) > 10:
    109         print(f"  ... and {len(out_of_order) - 10} more")
    110 
    111     if not fix:
    112         print("\nRun with --fix to reorder")
    113         return 1
    114 
    115     # Fix: reorder
    116     header, blocks, footer = extract_test_blocks(OURS)
    117     block_map = {name: content for name, content in blocks}
    118 
    119     # Reorder: upstream-ordered first, then extras
    120     ordered = []
    121     seen = set()
    122     for name in upstream_order:
    123         if name in block_map and name not in seen:
    124             ordered.append((name, block_map[name]))
    125             seen.add(name)
    126     for name, content in blocks:
    127         if name not in seen:
    128             ordered.append((name, content))
    129             seen.add(name)
    130 
    131     with open(OURS, "w") as f:
    132         f.write(header)
    133         for _, content in ordered:
    134             f.write("\n")
    135             f.write(content)
    136         f.write(footer)
    137 
    138     print(f"Fixed: {len(ordered)} tests reordered")
    139     return 0
    140 
    141 
    142 if __name__ == "__main__":
    143     sys.exit(main())