#!/usr/bin/env python3 """ Fixes misplaced 'using StellaOps.TestKit;' statements in test files. The validate-test-traits.py --fix script has a bug that inserts 'using StellaOps.TestKit;' after 'using var' statements inside methods, causing CS1001 compilation errors. This script: 1. Finds all affected .cs files 2. Removes the misplaced 'using StellaOps.TestKit;' lines (inside methods) 3. Ensures 'using StellaOps.TestKit;' exists at the top of the file """ import os import re import sys from pathlib import Path def fix_file(file_path: Path, dry_run: bool = False) -> bool: """Fix a single file by removing misplaced using statements.""" try: content = file_path.read_text(encoding='utf-8-sig') # Handle BOM except Exception as e: print(f" Error reading {file_path}: {e}", file=sys.stderr) return False original = content # Pattern to find 'using var' followed by 'using StellaOps.TestKit;' (bug) # This matches the broken pattern inside method bodies broken_pattern = re.compile( r'(using var [^;]+;\s*\n)(using StellaOps\.TestKit;\s*\n)', re.MULTILINE ) # Check if file has the broken pattern if not broken_pattern.search(content): return False # Remove all misplaced 'using StellaOps.TestKit;' lines after 'using var' fixed = broken_pattern.sub(r'\1', content) # Check if 'using StellaOps.TestKit;' exists at top of file (before namespace) namespace_match = re.search(r'^namespace\s+\w+', fixed, re.MULTILINE) if namespace_match: top_section = fixed[:namespace_match.start()] has_top_using = 'using StellaOps.TestKit;' in top_section if not has_top_using: # Find the last 'using' statement before namespace and add after it last_using = None for match in re.finditer(r'^using [^;]+;\s*$', top_section, re.MULTILINE): last_using = match if last_using: insert_pos = last_using.end() fixed = fixed[:insert_pos] + '\nusing StellaOps.TestKit;' + fixed[insert_pos:] if fixed != original: if not dry_run: # Preserve UTF-8 BOM if present encoding = 'utf-8-sig' if content.startswith('\ufeff') else 'utf-8' file_path.write_text(fixed, encoding=encoding) return True return False def main(): import argparse parser = argparse.ArgumentParser(description='Fix misplaced using statements') parser.add_argument('--path', default='src', help='Path to scan') parser.add_argument('--dry-run', action='store_true', help='Show what would be fixed') args = parser.parse_args() root = Path(args.path) if not root.exists(): print(f"Path not found: {root}", file=sys.stderr) sys.exit(1) fixed_count = 0 checked_count = 0 # Find all test .cs files for file_path in root.rglob('*.cs'): # Skip non-test files if '/obj/' in str(file_path) or '/bin/' in str(file_path): continue if 'node_modules' in str(file_path): continue if 'Test' not in str(file_path): continue checked_count += 1 if fix_file(file_path, dry_run=args.dry_run): print(f"{'Would fix' if args.dry_run else 'Fixed'}: {file_path}") fixed_count += 1 print(f"\nChecked: {checked_count} files") print(f"Fixed: {fixed_count} files") if args.dry_run: print("\n(Dry run - no files were modified)") if __name__ == '__main__': main()