#!/usr/bin/env python3 """ tests/support/toml_smoke_check.py — Validate TOML files generated by Phase 1 adapters. Usage: python tests/support/toml_smoke_check.py path/to/file.toml Exit 0 if the file parses under the subset of TOML features used in Phase 1: - Standard [table] headers - Quoted table names: [mcp_servers."Google Calendar"] - key = "string" - key = true / false - key = ["a", "b"] (array of strings) - env = { KEY = "VALUE" } (inline table) - Comments (# ...) - Blank lines - key = '''...''' (multiline literal string, any content) - key = \"\"\"...\"\"\" (multiline basic string, any content) Exit 1 with a clear error message if parsing fails. """ import re import sys # --------------------------------------------------------------------------- # Token patterns for Phase 1 TOML subset # --------------------------------------------------------------------------- # Blank line or comment RE_BLANK = re.compile(r'^\s*(#.*)?$') # Standard table header: [agents] or [mcp_servers.Gmail] RE_TABLE = re.compile(r'^\[([A-Za-z0-9_.-]+)\]\s*(#.*)?$') # TOML basic string content used inside quoted table keys for this test suite. # The generated keys only need literal characters plus escaped quote/backslash. # Keeping the subset narrow helps catch accidental raw backslashes such as # [mcp_servers."foo\bar"], which would change the key meaning. _TOML_ESCAPE = r'\\(?:["\\])' _TOML_SAFE_CHAR = r'[^"\\]' _TOML_QSTR = rf'(?:{_TOML_SAFE_CHAR}|{_TOML_ESCAPE})*' # Quoted table header: [mcp_servers."Google Calendar"] RE_TABLE_QUOTED = re.compile( rf'^\[([A-Za-z0-9_.-]+"{_TOML_QSTR}")\]\s*(#.*)?$' ) # key = "string" RE_KEY_STRING = re.compile(r'^[A-Za-z0-9_.-]+\s*=\s*"([^"\\]|\\.)*"\s*(#.*)?$') # key = true or key = false RE_KEY_BOOL = re.compile(r'^[A-Za-z0-9_.-]+\s*=\s*(true|false)\s*(#.*)?$') # key = integer RE_KEY_INT = re.compile(r'^[A-Za-z0-9_.-]+\s*=\s*-?\d+\s*(#.*)?$') # key = ["a", "b", ...] (array of strings — may span a single line only) RE_KEY_ARRAY = re.compile(r'^[A-Za-z0-9_.-]+\s*=\s*\[.*\]\s*(#.*)?$') # key = { KEY = "VALUE", ... } (inline table — single line) RE_KEY_INLINE_TABLE = re.compile(r'^[A-Za-z0-9_.-]+\s*=\s*\{.*\}\s*(#.*)?$') # key = ''' (start of multiline literal string) RE_MULTILINE_LIT_START = re.compile(r"^[A-Za-z0-9_.-]+\s*=\s*'''") # key = """ (start of multiline basic string) RE_MULTILINE_BASIC_START = re.compile(r'^[A-Za-z0-9_.-]+\s*=\s*"""') # Closing delimiter for multiline literal: line that is exactly ''' or ends with ''' RE_MULTILINE_LIT_END = re.compile(r"'''$") # Closing delimiter for multiline basic: line that is exactly """ or ends with """ RE_MULTILINE_BASIC_END = re.compile(r'"""$') # Collect all line-level patterns (order matters — most specific first) LINE_PATTERNS = [ RE_BLANK, RE_TABLE_QUOTED, RE_TABLE, RE_KEY_STRING, RE_KEY_BOOL, RE_KEY_INT, RE_KEY_ARRAY, RE_KEY_INLINE_TABLE, RE_MULTILINE_LIT_START, RE_MULTILINE_BASIC_START, ] def check_file(path: str) -> None: try: with open(path, encoding='utf-8') as fh: lines = fh.readlines() except FileNotFoundError: print(f"ERROR: File not found: {path}", file=sys.stderr) sys.exit(1) except OSError as exc: print(f"ERROR: Cannot read {path}: {exc}", file=sys.stderr) sys.exit(1) errors = [] in_multiline_lit = False # inside ''' ... ''' in_multiline_basic = False # inside """ ... """ for lineno, raw in enumerate(lines, start=1): line = raw.rstrip('\n') # Inside a multiline literal string: any content is valid until ''' if in_multiline_lit: if RE_MULTILINE_LIT_END.search(line): in_multiline_lit = False # All lines inside a multiline literal are valid — no error continue # Inside a multiline basic string: any content is valid until """ if in_multiline_basic: if RE_MULTILINE_BASIC_END.search(line): in_multiline_basic = False # All lines inside a multiline basic string are valid — no error continue # Check if this line opens a multiline string if RE_MULTILINE_LIT_START.match(line): # Check if it's also closed on the same line (inline) rest = re.sub(r"^[A-Za-z0-9_.-]+\s*=\s*'''", "", line) if rest.endswith("'''"): pass # Single-line multiline literal (unusual but valid) else: in_multiline_lit = True continue if RE_MULTILINE_BASIC_START.match(line): rest = re.sub(r'^[A-Za-z0-9_.-]+\s*=\s*"""', "", line) if rest.endswith('"""'): pass # Single-line multiline basic (unusual but valid) else: in_multiline_basic = True continue matched = any(pat.match(line) for pat in LINE_PATTERNS) if not matched: errors.append(f" line {lineno}: unexpected syntax: {line!r}") if in_multiline_lit: errors.append(" Unterminated multiline literal string (''' not closed)") if in_multiline_basic: errors.append(' Unterminated multiline basic string (""" not closed)') if errors: print(f"TOML parse error in {path}:", file=sys.stderr) for err in errors: print(err, file=sys.stderr) sys.exit(1) print(f"OK: {path}") if __name__ == '__main__': if len(sys.argv) != 2: print(f"Usage: {sys.argv[0]} ", file=sys.stderr) sys.exit(2) check_file(sys.argv[1])