testql 1.2.64__tar.gz → 1.2.65__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {testql-1.2.64/testql.egg-info → testql-1.2.65}/PKG-INFO +1 -1
- {testql-1.2.64 → testql-1.2.65}/pyproject.toml +1 -1
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_api_runner.py +2 -2
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_testtoon_parser.py +59 -5
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/engine.py +8 -1
- {testql-1.2.64 → testql-1.2.65/testql.egg-info}/PKG-INFO +1 -1
- {testql-1.2.64 → testql-1.2.65}/tests/test_interpreter.py +44 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_ir_runner_captures.py +20 -0
- {testql-1.2.64 → testql-1.2.65}/LICENSE +0 -0
- {testql-1.2.64 → testql-1.2.65}/README.md +0 -0
- {testql-1.2.64 → testql-1.2.65}/setup.cfg +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/__main__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/_base_fallback.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/base.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nl/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nl/entity_extractor.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nl/grammar.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nl/intent_recognizer.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nl/lexicon/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nl/llm_fallback.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nl/nl_adapter.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nlp2dsl/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nlp2dsl/client.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nlp2dsl/live_llm.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nlp2dsl/llm_provider.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nlp2dsl/mock_llm.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nlp2dsl/nlp2dsl_adapter.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nlp2env/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/nlp2env/nlp2env_adapter.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/registry.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/scenario_yaml.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/adapters/testtoon_adapter.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/artifacts/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/artifacts/base.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/artifacts/email_checker.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/artifacts/file_checker.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/artifacts/registry.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/assertion_suite.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/autoloop_runner.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/base.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/cli.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/auto_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/conversation_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/discover_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/echo/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/echo/cli.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/echo/context.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/echo/formatters/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/echo/formatters/text.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/echo/parsers/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/echo/parsers/doql.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/echo/parsers/toon.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/echo.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/echo_helpers.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/encoder_routes.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/endpoints_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/generate_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/generate_from_page_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/generate_ir_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/generate_topology_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/heal_scenario_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/inspect_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/misc_cmds.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/nlp2env_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/run_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/run_ir_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/self_test_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/suite/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/suite/cli.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/suite/collection.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/suite/execution.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/suite/listing.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/suite/reports.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/suite_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/templates/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/templates/content.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/templates/templates.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/topology_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/commands/watchdog_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/context/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/context/runtime.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/conversation/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/conversation/runner.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/data/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/data/verification-request-v1.schema.json +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/data/verification-result-v1.schema.json +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/detectors/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/detectors/base.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/detectors/config_detector.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/detectors/django_detector.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/detectors/express_detector.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/detectors/fastapi_detector.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/detectors/flask_detector.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/detectors/graphql_detector.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/detectors/models.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/detectors/openapi_detector.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/detectors/test_detector.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/detectors/unified.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/detectors/websocket_detector.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/manifest.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/probes/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/probes/base.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/probes/browser/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/probes/browser/playwright_page.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/probes/filesystem/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/probes/filesystem/api_openapi.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/probes/filesystem/container_compose.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/probes/filesystem/container_dockerfile.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/probes/filesystem/package_node.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/probes/filesystem/package_python.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/probes/network/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/probes/network/http_endpoint.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/registry.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/discovery/source.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/doql_parser.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/echo_schemas.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/endpoint_detector.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/export/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/export/scenario_builder.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/analyzers.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/api_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/base.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/convenience.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/conversation_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/generators.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/llm/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/llm/coverage_optimizer.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/llm/edge_case_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/multi.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/page_analyzer.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/pipeline.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/pytest_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/scenario_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/sources/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/sources/base.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/sources/config_source.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/sources/conversation.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/sources/nl_source.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/sources/openapi_source.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/sources/oql_models.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/sources/oql_parser.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/sources/oql_source.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/sources/page_source.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/sources/pytest_source.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/sources/ui_source.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/specialized_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/targets/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/targets/base.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/targets/nl_target.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/targets/pytest_target.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/targets/testtoon_target.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/generators/test_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/integrations/planfile_hook.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_assertions.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_context.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_converter.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_desktop.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_dom_scan.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_encoder.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_flow.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_gui.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_gui_expand.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_hardware.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_modbus.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_node_playwright.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_node_playwright_bridge.cjs +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_parser.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_shell.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_unit.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_validation.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/_websockets.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/core.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/dispatcher.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/handlers/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/handlers/api.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/handlers/assertions.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/handlers/encoder.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/handlers/flow.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/handlers/include.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/handlers/navigate.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/handlers/record.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/handlers/select.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/handlers/unknown.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/handlers/wait.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/models.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/parsers.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/converter/renderer.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/dispatcher.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/dom_scan_formatters.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/dom_scan_mixin.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/dom_scan_models.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/dom_scanner.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/interpreter.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/testtoon_models.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter/testtoon_parser.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/interpreter.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir/assertions.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir/captures.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir/fixtures.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir/metadata.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir/plan.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir/steps.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/assertion_eval.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/context.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/executors/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/executors/api.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/executors/assert_json.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/executors/base.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/executors/encoder.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/executors/graphql.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/executors/gui.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/executors/nl.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/executors/proto.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/executors/shell.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/executors/sql.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/executors/unit.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/ir_runner/interpolation.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/mcp/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/mcp/server.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/meta/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/meta/confidence_scorer.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/meta/coverage_analyzer.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/meta/mutator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/meta/self_test.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/nlp2env/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/nlp2env/llm.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/nlp2env/mcp_client.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/nlp2env/runner.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/nlp2env/scenarios.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/openapi_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/pipeline.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/proto_schema/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/proto_schema/descriptor_loader.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/proto_schema/message_validator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/report_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/reporters/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/reporters/console.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/reporters/json_reporter.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/reporters/junit.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/results/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/results/analyzer.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/results/artifacts.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/results/models.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/results/serializers.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/runner.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/runners/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/sql_schema/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/sql_schema/ddl_parser.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/sql_schema/dialect_resolver.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/sumd_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/sumd_parser.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/toon_parser.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/topology/__init__.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/topology/builder.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/topology/generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/topology/models.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/topology/serializers.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/topology/sitemap.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql/verification.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql.egg-info/SOURCES.txt +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql.egg-info/dependency_links.txt +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql.egg-info/entry_points.txt +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql.egg-info/requires.txt +0 -0
- {testql-1.2.64 → testql-1.2.65}/testql.egg-info/top_level.txt +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_adapter_capture_syntax.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_adapters_base.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_api_handler.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_assertion_suite.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_browser_discovery.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_cc_refactor_helpers.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_cli.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_cli_no_block.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_conversation_live_llm.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_conversation_nlp2dsl.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_converter.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_converter_handlers.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_desktop_assert_elements.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_desktop_execution.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_detectors.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_discovery.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_dispatcher.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_doql_parser_sumd_gen.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_echo.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_echo_doql_parser.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_echo_schemas_helpers.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_encoder_routes.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_environment_regressions.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_generate_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_generate_from_page_cli.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_generate_ir_cli.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_generators.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_gui_execution.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_ir.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_ir_captures.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_ir_runner_assertion_eval.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_ir_runner_engine.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_ir_runner_executors.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_ir_runner_interpolation.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_mcp_autoloop.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_meta_confidence.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_meta_coverage.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_meta_mutator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_meta_self_test.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_misc_cmds.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_modbus_commands.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_navigate_json_path.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_network_discovery.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_nl_adapter.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_nl_entity_extractor.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_nl_grammar.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_nl_intent_recognizer.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_nl_scenarios_e2e.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_nlp2env_adapter.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_node_playwright_fallback.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_openapi_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_page_analyzer.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_pipeline.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_plugin_registry.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_proto_descriptor_loader.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_proto_graphql_scenarios_e2e.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_proto_message_validator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_report_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_reporters.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_results.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_run_cmd.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_run_ir_cli.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_runner.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_runtime_context.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_scenario_yaml_adapter.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_shell_execution.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_smoke_decisions.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_sources.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_sql_ddl_parser.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_sql_dialect_resolver.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_suite_cmd_helpers.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_suite_execution.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_suite_listing.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_sumd_parser.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_targets.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_test_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_testtoon_adapter.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_toon_parser.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_topology.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_topology_generator.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_unit_execution.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_validation.py +0 -0
- {testql-1.2.64 → testql-1.2.65}/tests/test_verification_api.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: testql
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.65
|
|
4
4
|
Summary: TestQL — Multi-DSL Test Platform: TestTOON / NL / SQL / Proto / GraphQL adapters with Unified IR, generator engine, and meta-testing
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: <3.14,>=3.11
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "testql"
|
|
7
|
-
version = "1.2.
|
|
7
|
+
version = "1.2.65"
|
|
8
8
|
description = "TestQL — Multi-DSL Test Platform: TestTOON / NL / SQL / Proto / GraphQL adapters with Unified IR, generator engine, and meta-testing"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11,<3.14"
|
|
@@ -72,7 +72,7 @@ class ApiRunnerMixin:
|
|
|
72
72
|
continue
|
|
73
73
|
# Re-raise non-retryable errors
|
|
74
74
|
raise
|
|
75
|
-
except Exception
|
|
75
|
+
except Exception:
|
|
76
76
|
# Non-retryable errors
|
|
77
77
|
raise
|
|
78
78
|
|
|
@@ -128,7 +128,7 @@ class ApiRunnerMixin:
|
|
|
128
128
|
return
|
|
129
129
|
|
|
130
130
|
method = parts[0].upper()
|
|
131
|
-
url = parts[1].strip("\"'")
|
|
131
|
+
url = self.vars.interpolate(parts[1].strip("\"'"))
|
|
132
132
|
body_str = parts[2] if len(parts) > 2 else ""
|
|
133
133
|
|
|
134
134
|
if url.startswith("/"):
|
|
@@ -19,9 +19,6 @@ import json
|
|
|
19
19
|
|
|
20
20
|
from ._gui_expand import expand_gui_row
|
|
21
21
|
from ._parser import OqlLine, OqlScript
|
|
22
|
-
from .testtoon_models import ToonSection, ToonScript
|
|
23
|
-
from .testtoon_parser import parse_testtoon
|
|
24
|
-
|
|
25
22
|
# Backward compatibility: re-export classes that were moved
|
|
26
23
|
from .testtoon_models import ToonSection, ToonScript # noqa: F401
|
|
27
24
|
from .testtoon_parser import parse_testtoon # noqa: F401
|
|
@@ -110,9 +107,38 @@ def _append_api_asserts(row: dict, lines: list[OqlLine], line_num: int) -> int:
|
|
|
110
107
|
return line_num
|
|
111
108
|
|
|
112
109
|
|
|
113
|
-
def
|
|
110
|
+
def _append_api_captures(
|
|
111
|
+
row: dict,
|
|
112
|
+
api_step: int,
|
|
113
|
+
capture_rows: list[dict],
|
|
114
|
+
lines: list[OqlLine],
|
|
115
|
+
line_num: int,
|
|
116
|
+
) -> int:
|
|
117
|
+
"""Append captures assigned to an API row by its 1-based index or name."""
|
|
118
|
+
step_name = str(row.get('name', '')).strip()
|
|
119
|
+
for capture in capture_rows:
|
|
120
|
+
target = str(capture.get('step', '')).strip()
|
|
121
|
+
if target != str(api_step) and (not step_name or target != step_name):
|
|
122
|
+
continue
|
|
123
|
+
var_name = str(capture.get('var', '')).strip()
|
|
124
|
+
from_path = str(capture.get('from', '')).strip()
|
|
125
|
+
if not var_name or not from_path:
|
|
126
|
+
continue
|
|
127
|
+
args = f'{var_name} FROM "{from_path}"'
|
|
128
|
+
line_num = _append_raw_command(lines, line_num, 'CAPTURE', args)
|
|
129
|
+
return line_num
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _expand_api(
|
|
133
|
+
section: ToonSection,
|
|
134
|
+
lines: list[OqlLine],
|
|
135
|
+
line_num: int,
|
|
136
|
+
*,
|
|
137
|
+
capture_rows: list[dict] | None = None,
|
|
138
|
+
step_offset: int = 0,
|
|
139
|
+
) -> int:
|
|
114
140
|
"""Expand API section → API + ASSERT_STATUS commands."""
|
|
115
|
-
for row in section.rows:
|
|
141
|
+
for row_index, row in enumerate(section.rows, 1):
|
|
116
142
|
method = row.get('method', 'GET')
|
|
117
143
|
endpoint = row.get('endpoint', '/')
|
|
118
144
|
body = row.get('body')
|
|
@@ -127,6 +153,13 @@ def _expand_api(section: ToonSection, lines: list[OqlLine], line_num: int) -> in
|
|
|
127
153
|
raw = f'API {method} "{endpoint}"{body_str}'
|
|
128
154
|
lines.append(OqlLine(number=line_num, command='API', args=f'{method} "{endpoint}"{body_str}', raw=raw))
|
|
129
155
|
line_num = _append_api_asserts(row, lines, line_num + 1)
|
|
156
|
+
line_num = _append_api_captures(
|
|
157
|
+
row,
|
|
158
|
+
step_offset + row_index,
|
|
159
|
+
capture_rows or [],
|
|
160
|
+
lines,
|
|
161
|
+
line_num,
|
|
162
|
+
)
|
|
130
163
|
return line_num
|
|
131
164
|
|
|
132
165
|
|
|
@@ -649,8 +682,29 @@ def testtoon_to_oql(text: str, filename: str = "<string>") -> OqlScript:
|
|
|
649
682
|
toon = parse_testtoon(text, filename)
|
|
650
683
|
lines: list[OqlLine] = []
|
|
651
684
|
line_num = 1
|
|
685
|
+
api_step_count = 0
|
|
686
|
+
capture_rows = [
|
|
687
|
+
row
|
|
688
|
+
for section in toon.sections
|
|
689
|
+
if section.type == 'CAPTURE'
|
|
690
|
+
for row in section.rows
|
|
691
|
+
]
|
|
652
692
|
|
|
653
693
|
for section in toon.sections:
|
|
694
|
+
if section.type == 'CAPTURE':
|
|
695
|
+
# Captures must run while the referenced API response is still the
|
|
696
|
+
# current response, so API expansion interleaves them above.
|
|
697
|
+
continue
|
|
698
|
+
if section.type == 'API':
|
|
699
|
+
line_num = _expand_api(
|
|
700
|
+
section,
|
|
701
|
+
lines,
|
|
702
|
+
line_num,
|
|
703
|
+
capture_rows=capture_rows,
|
|
704
|
+
step_offset=api_step_count,
|
|
705
|
+
)
|
|
706
|
+
api_step_count += len(section.rows)
|
|
707
|
+
continue
|
|
654
708
|
expander = _SECTION_EXPANDERS.get(section.type, _expand_generic)
|
|
655
709
|
line_num = expander(section, lines, line_num)
|
|
656
710
|
|
|
@@ -49,7 +49,14 @@ def _apply_captures(step, result: StepResult, ctx: ExecutionContext) -> None:
|
|
|
49
49
|
return
|
|
50
50
|
payload = (result.details or {}).get("payload", {})
|
|
51
51
|
for capture in captures:
|
|
52
|
-
|
|
52
|
+
# API capture paths are relative to the response body (`response.data.id`
|
|
53
|
+
# is normalized to `data.id`). Other executors expose their result fields
|
|
54
|
+
# directly. Fall back to the full envelope so API status/header captures
|
|
55
|
+
# remain possible.
|
|
56
|
+
capture_root = payload.get("data", {}) if getattr(step, "kind", "") == "api" else payload
|
|
57
|
+
value = navigate(capture_root, capture.from_path)
|
|
58
|
+
if value is None and capture_root is not payload:
|
|
59
|
+
value = navigate(payload, capture.from_path)
|
|
53
60
|
if value is None:
|
|
54
61
|
ctx.warnings.append(
|
|
55
62
|
f"capture {capture.var_name!r} from {capture.from_path!r}: path not found"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: testql
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.65
|
|
4
4
|
Summary: TestQL — Multi-DSL Test Platform: TestTOON / NL / SQL / Proto / GraphQL adapters with Unified IR, generator engine, and meta-testing
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: <3.14,>=3.11
|
|
@@ -103,6 +103,34 @@ class TestTestTOONExpansion:
|
|
|
103
103
|
assert script.lines[3].command == "ASSERT_STATUS"
|
|
104
104
|
assert "201" in script.lines[3].args
|
|
105
105
|
|
|
106
|
+
def test_capture_is_interleaved_after_referenced_api_step(self):
|
|
107
|
+
source = (
|
|
108
|
+
"API[2]{method, endpoint, status}:\n"
|
|
109
|
+
" POST, /devices, 201\n"
|
|
110
|
+
" GET, /devices/${device_id}, 200\n"
|
|
111
|
+
"CAPTURE[1]{step, var, from}:\n"
|
|
112
|
+
" 1, device_id, data.id\n"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
script = _testtoon_to_oql(source, "test.testql.toon.yaml")
|
|
116
|
+
|
|
117
|
+
assert [line.command for line in script.lines] == [
|
|
118
|
+
"API", "ASSERT_STATUS", "CAPTURE", "API", "ASSERT_STATUS",
|
|
119
|
+
]
|
|
120
|
+
assert script.lines[2].args == 'device_id FROM "data.id"'
|
|
121
|
+
|
|
122
|
+
def test_capture_can_reference_named_api_step(self):
|
|
123
|
+
source = (
|
|
124
|
+
"API[1]{method, endpoint, status, name}:\n"
|
|
125
|
+
" POST, /devices, 201, createDevice\n"
|
|
126
|
+
"CAPTURE[1]{step, var, from}:\n"
|
|
127
|
+
" createDevice, device_id, data.id\n"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
script = _testtoon_to_oql(source, "test.testql.toon.yaml")
|
|
131
|
+
|
|
132
|
+
assert script.lines[-1].command == "CAPTURE"
|
|
133
|
+
|
|
106
134
|
def test_encoder_expansion(self):
|
|
107
135
|
source = (
|
|
108
136
|
"ENCODER[2]{action, target, value, wait_ms}:\n"
|
|
@@ -227,6 +255,22 @@ class TestOqlInterpreter:
|
|
|
227
255
|
assert result.ok
|
|
228
256
|
assert result.passed >= 1
|
|
229
257
|
|
|
258
|
+
def test_api_interpolates_captured_variable_in_url(self, monkeypatch):
|
|
259
|
+
requested_urls = []
|
|
260
|
+
|
|
261
|
+
def fake_request(_self, _method, url, _body):
|
|
262
|
+
requested_urls.append(url)
|
|
263
|
+
return 200, {"ok": True}, {}
|
|
264
|
+
|
|
265
|
+
monkeypatch.setattr(OqlInterpreter, "_do_http_request_with_retry", fake_request)
|
|
266
|
+
interp = OqlInterpreter(quiet=True, api_url="http://localhost:8101")
|
|
267
|
+
interp.vars.set("device_id", "dev-7")
|
|
268
|
+
|
|
269
|
+
result = interp.run('API GET "/devices/${device_id}"', "test.tql")
|
|
270
|
+
|
|
271
|
+
assert result.ok
|
|
272
|
+
assert requested_urls == ["http://localhost:8101/devices/dev-7"]
|
|
273
|
+
|
|
230
274
|
def test_set_get(self):
|
|
231
275
|
source = 'SET foo "bar"\nGET foo'
|
|
232
276
|
interp = OqlInterpreter(dry_run=True, quiet=True)
|
|
@@ -77,6 +77,26 @@ class TestShellCaptures:
|
|
|
77
77
|
assert "hello" in runner.ctx.vars.get("out")
|
|
78
78
|
|
|
79
79
|
|
|
80
|
+
class TestApiCaptures:
|
|
81
|
+
def test_capture_is_relative_to_response_body(self, monkeypatch):
|
|
82
|
+
from testql.ir_runner.executors import api
|
|
83
|
+
|
|
84
|
+
monkeypatch.setattr(api, "_do_request", lambda *args: (201, {"data": {"id": "sc-1"}}))
|
|
85
|
+
plan = _plan(
|
|
86
|
+
ApiStep(
|
|
87
|
+
method="POST",
|
|
88
|
+
path="/api/v3/scenarios",
|
|
89
|
+
captures=[Capture(var_name="scenario_id", from_path="data.id")],
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
runner = IRRunner()
|
|
93
|
+
|
|
94
|
+
result = runner.run(plan)
|
|
95
|
+
|
|
96
|
+
assert result.ok
|
|
97
|
+
assert runner.ctx.vars.get("scenario_id") == "sc-1"
|
|
98
|
+
|
|
99
|
+
|
|
80
100
|
# ── Missing path → warning, not failure ─────────────────────────────────────
|
|
81
101
|
|
|
82
102
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|