diff --git a/project/ticket-022/README.md b/project/ticket-022/README.md new file mode 100644 index 0000000..5f8ee69 --- /dev/null +++ b/project/ticket-022/README.md @@ -0,0 +1,27 @@ +# Ticket 022: Support TestTOON files in INCLUDE command + +- **ID**: ticket-022 +- **Owner**: agent:antigravity +- **Status**: IN_PROGRESS +- **Workflow state**: EDIT +- **Created**: 2026-10-02 + +## Goal and scope + +Allow the `INCLUDE` command to parse included TestTOON scenarios (`.testql.toon.yaml`) +using the interpreter's format detection (`self.parse(...)`) instead of assuming +legacy OQL syntax (`parse_oql`). + +## Acceptance criteria + +- [ ] AC-01: `INCLUDE` command parses TestTOON files through `self.parse(...)` instead of hardcoding `parse_oql`. +- [ ] AC-02: Unit test `tests/test_include_testtoon.py` passes. +- [ ] AC-03: Governance checks pass. + +## Authorization + +SESSION_EXECUTION_AUTHORIZATION: User requested sequential testing of all functionalities with testql, fixing the library directly if GUI testing fails, and merging the changes. + +## Evidence boundary + +Operational test receipts and browser execution logs remain local state. diff --git a/project/ticket-022/intent.json b/project/ticket-022/intent.json new file mode 100644 index 0000000..54610c0 --- /dev/null +++ b/project/ticket-022/intent.json @@ -0,0 +1,85 @@ +{ + "schema": "new-project.intent/v3", + "ticket": "ticket-022", + "summary": "Support TestTOON files in INCLUDE command", + "workstream": "core", + "classification": { + "kind": "BUG", + "priority": "P1", + "origin": "regression" + }, + "allowedPaths": [ + "project/ticket-022/**", + "TODO.md", + "project/TICKETS.md", + "testql/interpreter/_flow.py", + "tests/test_include_testtoon.py" + ], + "forbiddenPaths": [ + "project/ticket-*/user-*.md" + ], + "stacks": [ + "python" + ], + "dependsOn": [ + "ticket-021" + ], + "conflictsWith": [], + "integrationTicket": null, + "delivery": { + "acceptedBaseSha": "d609382cb3a2933ee5cf69b8af4e1b0552314587", + "targetBranch": "main", + "outcome": "Allow the INCLUDE command to parse included TestTOON scenarios (.testql.toon.yaml) using the interpreter's format detection instead of assuming legacy OQL syntax.", + "nonGoals": [ + "No changes to circular include detection", + "No changes to include paths resolution" + ], + "complexity": "XS", + "estimatedMinutes": 10, + "budgets": { + "maxImplementationFiles": 2, + "maxAffectedComponents": 1, + "maxPublicInterfaceChanges": 0, + "maxRuntimeDependencies": 0 + }, + "architecture": { + "status": "accepted", + "decision": "Use self.parse(source, filename=rel_path) in _cmd_include to parse both TestTOON and OQL included scripts.", + "components": [ + { + "name": "flow-include", + "paths": [ + "testql/interpreter/_flow.py", + "tests/test_include_testtoon.py" + ] + } + ], + "responsibilityChanges": false, + "interfaceChanges": [], + "dataChanges": [], + "ui": { + "impact": "none", + "states": [], + "evidence": [] + }, + "rollback": "Revert the _cmd_include parser call." + }, + "runtimeDependencies": [], + "validation": [ + { + "criterion": "AC-01", + "commands": [ + "pytest tests/test_include_testtoon.py" + ], + "evidence": "Included TestTOON files are parsed and dispatched as OQL lines." + }, + { + "criterion": "AC-02", + "commands": [ + "bash project/governance-check.sh --actor agent" + ], + "evidence": "Governance check passes." + } + ] + } +} diff --git a/testql/interpreter/_flow.py b/testql/interpreter/_flow.py index 736c85b..406d76d 100644 --- a/testql/interpreter/_flow.py +++ b/testql/interpreter/_flow.py @@ -133,7 +133,10 @@ def _cmd_include(self, args: str, line: OqlLine) -> None: self._included.add(abs_path) self.out.step("📎", f"INCLUDE {rel_path}") source = resolved.read_text(encoding="utf-8") - sub_script: OqlScript = parse_oql(source, filename=rel_path) + if hasattr(self, "parse"): + sub_script: OqlScript = self.parse(source, filename=rel_path) + else: + sub_script = parse_oql(source, filename=rel_path) for sub_line in sub_script.lines: sub_args = self.vars.interpolate(sub_line.args) try: diff --git a/tests/test_include_testtoon.py b/tests/test_include_testtoon.py new file mode 100644 index 0000000..fca2e96 --- /dev/null +++ b/tests/test_include_testtoon.py @@ -0,0 +1,36 @@ +"""Unit tests for including TestTOON scenarios via INCLUDE.""" + +from __future__ import annotations + +from pathlib import Path + +from testql.interpreter import OqlInterpreter +from testql.interpreter._parser import OqlLine + + +def test_cmd_include_parses_testtoon_scenario(tmp_path: Path) -> None: + """INCLUDE command should auto-detect and parse .testql.toon.yaml files.""" + sub_file = tmp_path / "sub.testql.toon.yaml" + sub_file.write_text( + """# SUB SCENARIO +CONFIG[1]{key, value}: + my_var, "hello_include" + +API[1]{method, endpoint, status}: + GET, /test, 200 +""", + encoding="utf-8", + ) + + interp = OqlInterpreter( + api_url="http://localhost:8100", + dry_run=True, + quiet=True, + include_paths=[str(tmp_path)], + ) + + line = OqlLine(number=1, command="INCLUDE", args=f'"{sub_file.name}"', raw=f'INCLUDE "{sub_file.name}"') + interp._cmd_include(line.args, line) + + assert interp.vars.get("my_var") == "hello_include" + assert len(interp.errors) == 0