cli-test-framework 0.9.0__tar.gz → 0.9.1__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.
- {cli_test_framework-0.9.0/src/cli_test_framework.egg-info → cli_test_framework-0.9.1}/PKG-INFO +1 -1
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/docs/user_manual.md +94 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/setup.py +1 -1
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/cli.py +23 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/config_loader.py +35 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/runners/config_runner.py +5 -1
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/runners/parallel_config_runner.py +5 -1
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1/src/cli_test_framework.egg-info}/PKG-INFO +1 -1
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework.egg-info/SOURCES.txt +3 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/__pycache__/test_cli.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-0.9.1/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-0.9.1/tests/unit/core/test_config_loader.py +136 -0
- cli_test_framework-0.9.1/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-0.9.1/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/runners/test_json_yaml_runner.py +50 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/test_cli.py +46 -0
- cli_test_framework-0.9.0/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/MANIFEST.in +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/README.md +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/docs/design.md +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/docs/design_en.md +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/docs/user_manual_en.md +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/pyproject.toml +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/setup.cfg +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/__init__.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/commands/__init__.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/commands/compare.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/__init__.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/assertions.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/base_runner.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/execution.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/history_store.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/parallel_runner.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/process_worker.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/setup.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/test_case.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/types.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/file_comparator/__init__.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/file_comparator/base_comparator.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/file_comparator/binary_comparator.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/file_comparator/csv_comparator.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/file_comparator/factory.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/file_comparator/h5_comparator.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/file_comparator/json_comparator.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/file_comparator/result.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/file_comparator/text_comparator.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/file_comparator/xml_comparator.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/logging_config.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/runners/__init__.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/runners/json_runner.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/runners/parallel_json_runner.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/runners/parallel_yaml_runner.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/runners/yaml_runner.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/utils/__init__.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/utils/junit_xml_writer.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/utils/path_resolver.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/utils/report_generator.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework.egg-info/dependency_links.txt +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework.egg-info/entry_points.txt +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework.egg-info/requires.txt +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework.egg-info/top_level.txt +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/README.md +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/__init__.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/__pycache__/__init__.cpython-312.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/__pycache__/__init__.cpython-39.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/__pycache__/conftest.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/__pycache__/run_all.cpython-312.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/__pycache__/run_all.cpython-39.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/__pycache__/test_setup_module.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/conftest.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/demos/h5_filter_demo.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/demos/manual_report_example.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/demos/perf_parallel.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/e2e/__init__.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/e2e/__pycache__/__init__.cpython-312.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/e2e/__pycache__/__init__.cpython-39.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/e2e/__pycache__/test_user_flows.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/e2e/test_user_flows.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/fixtures/test_cases.json +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/fixtures/test_cases.yaml +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/fixtures/test_cases1.json +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/fixtures/test_with_setup.json +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/fixtures/test_with_setup.yaml +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/test_binary_compare.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/test_csv_compare.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/test_h5_compare.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/test_json_compare.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/test_text_compare.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/file_compare/test_xml_compare.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/parallel/test_parallel_runner.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/path_handling/test_spaces_in_paths.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/test_history_feature.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/test_real_command_execution.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/integration/test_sequence.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/run_all.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/test_report.txt +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/__pycache__/test_cli.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/commands/test_compare_command.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/__pycache__/test_setup.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/test_assertions.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/test_execution.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/test_history_store.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/test_process_worker.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/core/test_setup.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/runners/test_test_case_filter.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/runners/test_test_case_tag_filter.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/test_h5_comparator.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/test_run_all.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/utils/test_junit_xml_writer.py +0 -0
- {cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/utils/test_report_generator.py +0 -0
{cli_test_framework-0.9.0/src/cli_test_framework.egg-info → cli_test_framework-0.9.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cli-test-framework
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.1
|
|
4
4
|
Summary: A powerful command line testing framework in Python with setup modules, parallel execution, and file comparison capabilities.
|
|
5
5
|
Home-page: https://github.com/ozil111/cli-test-framework
|
|
6
6
|
Author: Xiaotong Wang
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
- [安装](#安装)
|
|
6
6
|
- [测试用例定义](#测试用例定义)
|
|
7
7
|
- [运行测试](#运行测试)
|
|
8
|
+
- [占位符(变量替换)](#占位符变量替换)
|
|
8
9
|
- [标签过滤](#标签过滤)
|
|
9
10
|
- [Setup 模块](#setup-模块)
|
|
10
11
|
- [并行测试](#并行测试)
|
|
@@ -245,6 +246,99 @@ for detail in runner.results["details"]:
|
|
|
245
246
|
print(detail["name"], detail["status"], detail.get("message", ""))
|
|
246
247
|
```
|
|
247
248
|
|
|
249
|
+
## 占位符(变量替换)
|
|
250
|
+
|
|
251
|
+
当同一个配置文件需要在不同环境下使用不同参数(如求解器路径、模型文件路径等)时,可以用 `{变量名}` 占位符编写配置,运行时通过 `--var` 或 `variables` 参数传入实际值。
|
|
252
|
+
|
|
253
|
+
### 编写含占位符的配置
|
|
254
|
+
|
|
255
|
+
JSON:
|
|
256
|
+
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"test_cases": [
|
|
260
|
+
{
|
|
261
|
+
"name": "求解器测试",
|
|
262
|
+
"command": "{solver}",
|
|
263
|
+
"args": ["--input", "{model}", "--output", "{output}"],
|
|
264
|
+
"expected": { "return_code": 0 }
|
|
265
|
+
}
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
YAML:
|
|
271
|
+
|
|
272
|
+
```yaml
|
|
273
|
+
test_cases:
|
|
274
|
+
- name: 求解器测试
|
|
275
|
+
command: "{solver}"
|
|
276
|
+
args: ["--input", "{model}", "--output", "{output}"]
|
|
277
|
+
expected:
|
|
278
|
+
return_code: 0
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
占位符 `{变量名}` 可出现在配置文件的任意字符串值中,包括 `command`、`args`、`name`、`expected.output_contains` 等。支持同一个字符串中使用多个占位符,如 `"{solver} --input {model}"`。
|
|
282
|
+
|
|
283
|
+
> **安全设计**:只有 `variables` 字典中存在的 key 才会被替换。`{xxx}` 若无匹配不会报错,而是原样保留。因此 `expected.output_matches` 中的正则模式(如 `{2,}`、`\d{4}`)不受影响。
|
|
284
|
+
|
|
285
|
+
### 用法
|
|
286
|
+
|
|
287
|
+
#### CLI
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
# 单个变量
|
|
291
|
+
cli-test run test_cases.json --var solver=/opt/solver/bin/solver.exe
|
|
292
|
+
|
|
293
|
+
# 多个变量
|
|
294
|
+
cli-test run test_cases.json --var solver=/opt/solver/bin/solver.exe --var model=./data/model.dat
|
|
295
|
+
|
|
296
|
+
# 与并行模式、标签过滤等组合使用
|
|
297
|
+
cli-test run test_cases.json --var solver=solver.exe --parallel --workers 4 --tag smoke
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
`--var` 格式为 `KEY=VALUE`,可多次使用。等号分隔,key 和 value 两侧的空格会被自动去除。
|
|
301
|
+
|
|
302
|
+
#### Python API
|
|
303
|
+
|
|
304
|
+
```python
|
|
305
|
+
from cli_test_framework.runners import JSONRunner, YAMLRunner, ParallelJSONRunner, ParallelYAMLRunner
|
|
306
|
+
|
|
307
|
+
# 顺序运行
|
|
308
|
+
runner = JSONRunner(
|
|
309
|
+
config_file="test_cases.json",
|
|
310
|
+
variables={
|
|
311
|
+
"solver": "/opt/solver/bin/solver.exe",
|
|
312
|
+
"model": "./data/model.dat",
|
|
313
|
+
"output": "./results/output.dat",
|
|
314
|
+
},
|
|
315
|
+
)
|
|
316
|
+
success = runner.run_tests()
|
|
317
|
+
|
|
318
|
+
# 并行运行
|
|
319
|
+
runner = ParallelJSONRunner(
|
|
320
|
+
config_file="test_cases.json",
|
|
321
|
+
variables={"solver": "/opt/solver/bin/solver.exe"},
|
|
322
|
+
)
|
|
323
|
+
success = runner.run_tests()
|
|
324
|
+
|
|
325
|
+
# YAML 同样支持
|
|
326
|
+
runner = YAMLRunner(
|
|
327
|
+
config_file="test_cases.yaml",
|
|
328
|
+
variables={"solver": "/opt/solver/bin/solver.exe"},
|
|
329
|
+
)
|
|
330
|
+
success = runner.run_tests()
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### 适用场景
|
|
334
|
+
|
|
335
|
+
| 场景 | 示例 |
|
|
336
|
+
|---|---|
|
|
337
|
+
| 不同求解器版本测试 | `--var solver=v1.0/solver.exe` ↔ `--var solver=v2.0/solver.exe` |
|
|
338
|
+
| 不同输入数据 | `--var model=case_1.dat` ↔ `--var model=case_2.dat` |
|
|
339
|
+
| CI/CD 环境适配 | 本地 `/opt/solver.exe`,CI `/runner/solver.exe` |
|
|
340
|
+
| 多平台路径 | Windows `--var solver=C:\solver.exe`,Linux `--var solver=/opt/solver.exe` |
|
|
341
|
+
|
|
248
342
|
## 标签过滤
|
|
249
343
|
|
|
250
344
|
通过标签(tags)可以对测试用例进行分类,并在运行时按标签批量过滤。标签过滤与名称过滤可同时使用,满足 AND 关系(两个条件都必须满足)。
|
|
@@ -8,7 +8,7 @@ with open(os.path.join(this_directory, 'README.md'), encoding='utf-8') as f:
|
|
|
8
8
|
|
|
9
9
|
setup(
|
|
10
10
|
name="cli-test-framework",
|
|
11
|
-
version="0.9.
|
|
11
|
+
version="0.9.1",
|
|
12
12
|
author="Xiaotong Wang",
|
|
13
13
|
author_email="xiaotongwang98@gmail.com",
|
|
14
14
|
description="A powerful command line testing framework in Python with setup modules, parallel execution, and file comparison capabilities.",
|
|
@@ -22,6 +22,18 @@ from .utils.junit_xml_writer import write_junit_xml
|
|
|
22
22
|
logger = logging.getLogger("cli_test_framework.cli")
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
def _parse_vars(var_list):
|
|
26
|
+
"""Parse ``['solver=/path', 'model=./m.dat']`` → ``{'solver': '/path', ...}``."""
|
|
27
|
+
variables = {}
|
|
28
|
+
for item in var_list or []:
|
|
29
|
+
if '=' not in item:
|
|
30
|
+
logger.warning("Ignoring invalid --var '%s' (expected KEY=VALUE)", item)
|
|
31
|
+
continue
|
|
32
|
+
key, _, value = item.partition('=')
|
|
33
|
+
variables[key.strip()] = value.strip()
|
|
34
|
+
return variables
|
|
35
|
+
|
|
36
|
+
|
|
25
37
|
def create_parser():
|
|
26
38
|
"""Create and configure the argument parser"""
|
|
27
39
|
parser = argparse.ArgumentParser(
|
|
@@ -61,6 +73,11 @@ Examples:
|
|
|
61
73
|
run_parser.add_argument('--debug', action='store_true', help='Enable debug mode')
|
|
62
74
|
run_parser.add_argument('--junit-xml', dest='junit_xml',
|
|
63
75
|
help='Write JUnit XML report to the specified file path')
|
|
76
|
+
run_parser.add_argument('--var', action='append', default=[],
|
|
77
|
+
metavar='KEY=VALUE',
|
|
78
|
+
help='Set a variable for config placeholder substitution, '
|
|
79
|
+
'e.g. --var solver=/path/to/solver '
|
|
80
|
+
'(can be used multiple times)')
|
|
64
81
|
|
|
65
82
|
# ---- Compare command ----
|
|
66
83
|
compare_parser = subparsers.add_parser('compare', help='Compare two files')
|
|
@@ -136,6 +153,8 @@ def run_tests(args):
|
|
|
136
153
|
# construct Namespace objects without the newer arguments.
|
|
137
154
|
history_dir = getattr(args, 'history_dir', None)
|
|
138
155
|
regression_threshold = getattr(args, 'regression_threshold', 1.5)
|
|
156
|
+
var_list = getattr(args, 'var', [])
|
|
157
|
+
variables = _parse_vars(var_list)
|
|
139
158
|
|
|
140
159
|
try:
|
|
141
160
|
if args.parallel:
|
|
@@ -150,6 +169,7 @@ def run_tests(args):
|
|
|
150
169
|
test_case_tag_filter=args.tag,
|
|
151
170
|
history_dir=history_dir,
|
|
152
171
|
regression_threshold=regression_threshold,
|
|
172
|
+
variables=variables,
|
|
153
173
|
)
|
|
154
174
|
elif file_ext in ['.yaml', '.yml']:
|
|
155
175
|
runner = ParallelYAMLRunner(
|
|
@@ -161,6 +181,7 @@ def run_tests(args):
|
|
|
161
181
|
test_case_tag_filter=args.tag,
|
|
162
182
|
history_dir=history_dir,
|
|
163
183
|
regression_threshold=regression_threshold,
|
|
184
|
+
variables=variables,
|
|
164
185
|
)
|
|
165
186
|
else:
|
|
166
187
|
logger.error("Unsupported configuration file format for parallel mode: %s", file_ext)
|
|
@@ -175,6 +196,7 @@ def run_tests(args):
|
|
|
175
196
|
test_case_tag_filter=args.tag,
|
|
176
197
|
history_dir=history_dir,
|
|
177
198
|
regression_threshold=regression_threshold,
|
|
199
|
+
variables=variables,
|
|
178
200
|
)
|
|
179
201
|
elif file_ext in ['.yaml', '.yml']:
|
|
180
202
|
runner = YAMLRunner(
|
|
@@ -184,6 +206,7 @@ def run_tests(args):
|
|
|
184
206
|
test_case_tag_filter=args.tag,
|
|
185
207
|
history_dir=history_dir,
|
|
186
208
|
regression_threshold=regression_threshold,
|
|
209
|
+
variables=variables,
|
|
187
210
|
)
|
|
188
211
|
else:
|
|
189
212
|
logger.error("Unsupported configuration file format: %s", file_ext)
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/config_loader.py
RENAMED
|
@@ -11,6 +11,7 @@ Backward-compatible: the runner classes still expose ``load_test_cases()`` and
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
13
|
import logging
|
|
14
|
+
import re
|
|
14
15
|
from pathlib import Path
|
|
15
16
|
from typing import Any, Dict, List, Optional, Tuple
|
|
16
17
|
|
|
@@ -20,6 +21,40 @@ from ..utils.path_resolver import resolve_paths
|
|
|
20
21
|
|
|
21
22
|
logger = logging.getLogger("cli_test_framework.core.config_loader")
|
|
22
23
|
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
# Placeholder substitution
|
|
26
|
+
# ---------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
_PLACEHOLDER_RE = re.compile(r'\{(\w+)\}')
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def substitute_placeholders(
|
|
32
|
+
config: Dict[str, Any],
|
|
33
|
+
variables: Optional[Dict[str, Any]] = None,
|
|
34
|
+
) -> Dict[str, Any]:
|
|
35
|
+
"""递归替换 config 中字符串值的 ``{placeholder}`` 占位符。
|
|
36
|
+
|
|
37
|
+
只替换 ``variables`` 中存在的 key,未匹配的 ``{xxx}`` 原样保留,
|
|
38
|
+
不会影响 ``expected.matches`` 等字段中的正则模式(如 ``{2}``)。
|
|
39
|
+
"""
|
|
40
|
+
if not variables:
|
|
41
|
+
return config
|
|
42
|
+
|
|
43
|
+
def _sub(value: Any) -> Any:
|
|
44
|
+
if isinstance(value, str):
|
|
45
|
+
return _PLACEHOLDER_RE.sub(
|
|
46
|
+
lambda m: str(variables[m.group(1)])
|
|
47
|
+
if m.group(1) in variables else m.group(0),
|
|
48
|
+
value,
|
|
49
|
+
)
|
|
50
|
+
if isinstance(value, list):
|
|
51
|
+
return [_sub(item) for item in value]
|
|
52
|
+
if isinstance(value, dict):
|
|
53
|
+
return {k: _sub(v) for k, v in value.items()}
|
|
54
|
+
return value
|
|
55
|
+
|
|
56
|
+
return _sub(config)
|
|
57
|
+
|
|
23
58
|
|
|
24
59
|
# ---------------------------------------------------------------------------
|
|
25
60
|
# Test-case parsing (loaded dict → list[TestCase])
|
|
@@ -10,7 +10,7 @@ import logging
|
|
|
10
10
|
from typing import Optional, Dict, Any, Callable, BinaryIO
|
|
11
11
|
|
|
12
12
|
from ..core.base_runner import BaseRunner
|
|
13
|
-
from ..core.config_loader import parse_test_cases
|
|
13
|
+
from ..core.config_loader import parse_test_cases, substitute_placeholders
|
|
14
14
|
from ..core.test_case import TestCase
|
|
15
15
|
from ..core.execution import execute_single_test_case
|
|
16
16
|
from ..core.types import TestCaseData
|
|
@@ -30,9 +30,11 @@ class ConfigRunner(BaseRunner):
|
|
|
30
30
|
def __init__(self, config_file: str = "test_cases.json",
|
|
31
31
|
workspace: Optional[str] = None,
|
|
32
32
|
config_loader: Optional[Callable[[BinaryIO], Dict[str, Any]]] = None,
|
|
33
|
+
variables: Optional[Dict[str, Any]] = None,
|
|
33
34
|
**kwargs):
|
|
34
35
|
super().__init__(config_file, workspace, **kwargs)
|
|
35
36
|
self._config_loader = config_loader
|
|
37
|
+
self._variables = variables or {}
|
|
36
38
|
# Backward-compatible attribute for tests that patch path_resolver
|
|
37
39
|
self.path_resolver = PathResolver(self.workspace)
|
|
38
40
|
|
|
@@ -46,6 +48,8 @@ class ConfigRunner(BaseRunner):
|
|
|
46
48
|
with open(self.config_path, 'r', encoding='utf-8') as f:
|
|
47
49
|
config = self._config_loader(f)
|
|
48
50
|
|
|
51
|
+
config = substitute_placeholders(config, self._variables)
|
|
52
|
+
|
|
49
53
|
self.load_setup_from_config(config)
|
|
50
54
|
self.test_cases = parse_test_cases(
|
|
51
55
|
config, self.workspace, self.path_resolver,
|
|
@@ -10,7 +10,7 @@ import logging
|
|
|
10
10
|
from typing import Optional, Dict, Any, Callable, BinaryIO
|
|
11
11
|
|
|
12
12
|
from ..core.parallel_runner import ParallelRunner, AtomicSemaphore
|
|
13
|
-
from ..core.config_loader import parse_test_cases, execute_sequence
|
|
13
|
+
from ..core.config_loader import parse_test_cases, execute_sequence, substitute_placeholders
|
|
14
14
|
from ..core.test_case import TestCase
|
|
15
15
|
from ..core.execution import execute_single_test_case
|
|
16
16
|
from ..core.types import TestCaseData
|
|
@@ -32,6 +32,7 @@ class ParallelConfigRunner(ParallelRunner):
|
|
|
32
32
|
max_workers: Optional[int] = None,
|
|
33
33
|
execution_mode: str = "thread",
|
|
34
34
|
config_loader: Optional[Callable[[BinaryIO], Dict[str, Any]]] = None,
|
|
35
|
+
variables: Optional[Dict[str, Any]] = None,
|
|
35
36
|
**kwargs):
|
|
36
37
|
# Auto-detect physical CPU cores (reserve 2 for OS)
|
|
37
38
|
self.total_physical = os.cpu_count() or 4
|
|
@@ -43,6 +44,7 @@ class ParallelConfigRunner(ParallelRunner):
|
|
|
43
44
|
super().__init__(config_file, workspace, max_workers,
|
|
44
45
|
execution_mode, **kwargs)
|
|
45
46
|
self._config_loader = config_loader
|
|
47
|
+
self._variables = variables or {}
|
|
46
48
|
# Backward-compatible attribute for tests that patch path_resolver
|
|
47
49
|
self.path_resolver = PathResolver(self.workspace)
|
|
48
50
|
|
|
@@ -121,6 +123,8 @@ class ParallelConfigRunner(ParallelRunner):
|
|
|
121
123
|
with open(self.config_path, 'r', encoding='utf-8') as f:
|
|
122
124
|
config = self._config_loader(f)
|
|
123
125
|
|
|
126
|
+
config = substitute_placeholders(config, self._variables)
|
|
127
|
+
|
|
124
128
|
self.load_setup_from_config(config)
|
|
125
129
|
self.test_cases = parse_test_cases(
|
|
126
130
|
config, self.workspace, self.path_resolver,
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1/src/cli_test_framework.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cli-test-framework
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.1
|
|
4
4
|
Summary: A powerful command line testing framework in Python with setup modules, parallel execution, and file comparison capabilities.
|
|
5
5
|
Home-page: https://github.com/ozil111/cli-test-framework
|
|
6
6
|
Author: Xiaotong Wang
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework.egg-info/SOURCES.txt
RENAMED
|
@@ -130,12 +130,14 @@ tests/unit/commands/test_compare_command.py
|
|
|
130
130
|
tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-7.4.4.pyc
|
|
131
131
|
tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-9.0.3.pyc
|
|
132
132
|
tests/unit/core/test_assertions.py
|
|
133
|
+
tests/unit/core/test_config_loader.py
|
|
133
134
|
tests/unit/core/test_execution.py
|
|
134
135
|
tests/unit/core/test_history_store.py
|
|
135
136
|
tests/unit/core/test_process_worker.py
|
|
136
137
|
tests/unit/core/test_setup.py
|
|
137
138
|
tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-7.4.4.pyc
|
|
138
139
|
tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-9.0.3.pyc
|
|
140
|
+
tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc
|
|
139
141
|
tests/unit/core/__pycache__/test_execution.cpython-312-pytest-9.0.3.pyc
|
|
140
142
|
tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-7.4.4.pyc
|
|
141
143
|
tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-9.0.3.pyc
|
|
@@ -149,6 +151,7 @@ tests/unit/runners/test_test_case_filter.py
|
|
|
149
151
|
tests/unit/runners/test_test_case_tag_filter.py
|
|
150
152
|
tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-7.4.4.pyc
|
|
151
153
|
tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-9.0.3.pyc
|
|
154
|
+
tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312.pyc
|
|
152
155
|
tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-39-pytest-8.3.4.pyc
|
|
153
156
|
tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-7.4.4.pyc
|
|
154
157
|
tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-9.0.3.pyc
|
|
Binary file
|
cli_test_framework-0.9.1/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc
ADDED
|
Binary file
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Unit tests for cli_test_framework.core.config_loader — substitute_placeholders."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from cli_test_framework.core.config_loader import substitute_placeholders
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# ---------------------------------------------------------------------------
|
|
9
|
+
# Basic substitution
|
|
10
|
+
# ---------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
class TestSubstitutePlaceholders:
|
|
13
|
+
"""Tests for the substitute_placeholders utility."""
|
|
14
|
+
|
|
15
|
+
def test_no_variables_returns_unchanged(self):
|
|
16
|
+
config = {"command": "{solver}", "args": ["--input", "{model}"]}
|
|
17
|
+
result = substitute_placeholders(config, None)
|
|
18
|
+
assert result == config
|
|
19
|
+
|
|
20
|
+
def test_empty_variables_returns_unchanged(self):
|
|
21
|
+
config = {"command": "{solver}", "args": ["--input", "{model}"]}
|
|
22
|
+
result = substitute_placeholders(config, {})
|
|
23
|
+
assert result == config
|
|
24
|
+
|
|
25
|
+
def test_simple_string_substitution(self):
|
|
26
|
+
config = {"command": "{solver}"}
|
|
27
|
+
result = substitute_placeholders(config, {"solver": "/usr/bin/solver"})
|
|
28
|
+
assert result["command"] == "/usr/bin/solver"
|
|
29
|
+
|
|
30
|
+
def test_multiple_placeholders_in_one_string(self):
|
|
31
|
+
config = {"command": "{solver} --input {model}"}
|
|
32
|
+
result = substitute_placeholders(
|
|
33
|
+
config, {"solver": "/usr/bin/solver", "model": "./data.dat"},
|
|
34
|
+
)
|
|
35
|
+
assert result["command"] == "/usr/bin/solver --input ./data.dat"
|
|
36
|
+
|
|
37
|
+
def test_placeholder_in_list(self):
|
|
38
|
+
config = {"args": ["--solver", "{solver}", "--input", "{model}"]}
|
|
39
|
+
result = substitute_placeholders(
|
|
40
|
+
config, {"solver": "/usr/bin/solver", "model": "./data.dat"},
|
|
41
|
+
)
|
|
42
|
+
assert result["args"] == ["--solver", "/usr/bin/solver", "--input", "./data.dat"]
|
|
43
|
+
|
|
44
|
+
def test_placeholder_in_nested_dict(self):
|
|
45
|
+
config = {
|
|
46
|
+
"test_cases": [
|
|
47
|
+
{
|
|
48
|
+
"name": "test-{tag}",
|
|
49
|
+
"command": "{solver}",
|
|
50
|
+
"args": ["{model}"],
|
|
51
|
+
"expected": {"return_code": 0},
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
result = substitute_placeholders(
|
|
56
|
+
config, {"solver": "/usr/bin/solver", "model": "./data.dat", "tag": "alpha"},
|
|
57
|
+
)
|
|
58
|
+
case = result["test_cases"][0]
|
|
59
|
+
assert case["name"] == "test-alpha"
|
|
60
|
+
assert case["command"] == "/usr/bin/solver"
|
|
61
|
+
assert case["args"] == ["./data.dat"]
|
|
62
|
+
|
|
63
|
+
def test_unmatched_placeholder_preserved(self):
|
|
64
|
+
"""Unmatched {xxx} should be kept as-is (safe for regex patterns like {2})."""
|
|
65
|
+
config = {"expected": {"output_matches": r"\d{2,4}"}}
|
|
66
|
+
result = substitute_placeholders(config, {"solver": "/bin/solver"})
|
|
67
|
+
assert result["expected"]["output_matches"] == r"\d{2,4}"
|
|
68
|
+
|
|
69
|
+
def test_partial_match_preserved(self):
|
|
70
|
+
"""Only entirely matching keys are substituted; partial matches stay."""
|
|
71
|
+
config = {"command": "{solver_extra}"}
|
|
72
|
+
result = substitute_placeholders(config, {"solver": "/bin/solver"})
|
|
73
|
+
assert result["command"] == "{solver_extra}"
|
|
74
|
+
|
|
75
|
+
def test_non_string_values_unchanged(self):
|
|
76
|
+
config = {"timeout": 60, "priority": 3.5, "enabled": True, "data": None}
|
|
77
|
+
result = substitute_placeholders(config, {"timeout": "999"})
|
|
78
|
+
assert result["timeout"] == 60
|
|
79
|
+
assert result["priority"] == 3.5
|
|
80
|
+
assert result["enabled"] is True
|
|
81
|
+
assert result["data"] is None
|
|
82
|
+
|
|
83
|
+
def test_original_config_not_mutated(self):
|
|
84
|
+
original = {"command": "{solver}", "args": ["{model}"]}
|
|
85
|
+
result = substitute_placeholders(
|
|
86
|
+
original, {"solver": "/usr/bin/solver", "model": "./data.dat"},
|
|
87
|
+
)
|
|
88
|
+
# Original should be unchanged
|
|
89
|
+
assert original["command"] == "{solver}"
|
|
90
|
+
assert original["args"] == ["{model}"]
|
|
91
|
+
# Result should have substitutions
|
|
92
|
+
assert result["command"] == "/usr/bin/solver"
|
|
93
|
+
assert result["args"] == ["./data.dat"]
|
|
94
|
+
|
|
95
|
+
def test_variable_value_converted_to_str(self):
|
|
96
|
+
"""Non-string variable values should be converted via str()."""
|
|
97
|
+
config = {"command": "{count} {flag}"}
|
|
98
|
+
result = substitute_placeholders(config, {"count": 42, "flag": True})
|
|
99
|
+
assert result["command"] == "42 True"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# ---------------------------------------------------------------------------
|
|
103
|
+
# Integration-style: full config dict with placeholders
|
|
104
|
+
# ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
class TestPlaceholderInTestCases:
|
|
107
|
+
"""End-to-end style tests with realistic config dicts."""
|
|
108
|
+
|
|
109
|
+
def test_full_json_config_with_steps(self):
|
|
110
|
+
config = {
|
|
111
|
+
"test_cases": [
|
|
112
|
+
{
|
|
113
|
+
"name": "Multi-step with placeholders",
|
|
114
|
+
"steps": [
|
|
115
|
+
{
|
|
116
|
+
"command": "{solver}",
|
|
117
|
+
"args": ["--parse", "{input}"],
|
|
118
|
+
"expected": {"return_code": 0},
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"command": "{solver}",
|
|
122
|
+
"args": ["--solve", "{input}"],
|
|
123
|
+
"expected": {"output_contains": ["Optimal"]},
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
result = substitute_placeholders(
|
|
130
|
+
config, {"solver": "/opt/solver", "input": "model.dat"},
|
|
131
|
+
)
|
|
132
|
+
steps = result["test_cases"][0]["steps"]
|
|
133
|
+
assert steps[0]["command"] == "/opt/solver"
|
|
134
|
+
assert steps[0]["args"] == ["--parse", "model.dat"]
|
|
135
|
+
assert steps[1]["command"] == "/opt/solver"
|
|
136
|
+
assert steps[1]["args"] == ["--solve", "model.dat"]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/tests/unit/runners/test_json_yaml_runner.py
RENAMED
|
@@ -82,6 +82,56 @@ class TestYAMLRunner(unittest.TestCase):
|
|
|
82
82
|
self.temp_dir.cleanup()
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
class TestPlaceholderSubstitution(unittest.TestCase):
|
|
86
|
+
"""Integration test: verify that variables flow through runner's load_test_cases."""
|
|
87
|
+
|
|
88
|
+
def setUp(self):
|
|
89
|
+
self.temp_dir = tempfile.TemporaryDirectory()
|
|
90
|
+
config = {
|
|
91
|
+
"test_cases": [
|
|
92
|
+
{
|
|
93
|
+
"name": "placeholder-test",
|
|
94
|
+
"command": "{solver}",
|
|
95
|
+
"args": ["--input", "{flag}"],
|
|
96
|
+
"expected": {"return_code": 0},
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
self.config_path = Path(self.temp_dir.name) / "placeholder_config.json"
|
|
101
|
+
self.config_path.write_text(json.dumps(config), encoding="utf-8")
|
|
102
|
+
|
|
103
|
+
def test_placeholders_substituted_in_loaded_cases(self):
|
|
104
|
+
runner = JSONRunner(
|
|
105
|
+
str(self.config_path),
|
|
106
|
+
workspace=self.temp_dir.name,
|
|
107
|
+
variables={"solver": "/usr/bin/solver", "flag": "--verbose"},
|
|
108
|
+
)
|
|
109
|
+
runner.load_test_cases()
|
|
110
|
+
|
|
111
|
+
self.assertEqual(len(runner.test_cases), 1)
|
|
112
|
+
case = runner.test_cases[0]
|
|
113
|
+
self.assertIn("/usr/bin/solver", case.command)
|
|
114
|
+
self.assertIn("--verbose", case.args)
|
|
115
|
+
self.assertNotIn("{solver}", case.command)
|
|
116
|
+
self.assertNotIn("{flag}", case.args)
|
|
117
|
+
|
|
118
|
+
def test_no_variables_still_works(self):
|
|
119
|
+
"""Without variables, placeholders should remain as-is."""
|
|
120
|
+
runner = JSONRunner(
|
|
121
|
+
str(self.config_path),
|
|
122
|
+
workspace=self.temp_dir.name,
|
|
123
|
+
)
|
|
124
|
+
runner.load_test_cases()
|
|
125
|
+
|
|
126
|
+
self.assertEqual(len(runner.test_cases), 1)
|
|
127
|
+
case = runner.test_cases[0]
|
|
128
|
+
self.assertIn("{solver}", case.command)
|
|
129
|
+
self.assertIn("{flag}", case.args)
|
|
130
|
+
|
|
131
|
+
def tearDown(self):
|
|
132
|
+
self.temp_dir.cleanup()
|
|
133
|
+
|
|
134
|
+
|
|
85
135
|
if __name__ == "__main__":
|
|
86
136
|
unittest.main()
|
|
87
137
|
|
|
@@ -109,3 +109,49 @@ def test_main_exits_nonzero_without_command(monkeypatch):
|
|
|
109
109
|
|
|
110
110
|
assert exc.value.code == 1
|
|
111
111
|
|
|
112
|
+
|
|
113
|
+
def test_parse_vars_single():
|
|
114
|
+
result = cli._parse_vars(["solver=/opt/solver"])
|
|
115
|
+
assert result == {"solver": "/opt/solver"}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def test_parse_vars_multiple():
|
|
119
|
+
result = cli._parse_vars(["solver=/opt/solver", "model=./data.dat"])
|
|
120
|
+
assert result == {"solver": "/opt/solver", "model": "./data.dat"}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def test_parse_vars_empty():
|
|
124
|
+
result = cli._parse_vars([])
|
|
125
|
+
assert result == {}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def test_parse_vars_invalid_warns(caplog):
|
|
129
|
+
result = cli._parse_vars(["bad_entry"])
|
|
130
|
+
assert result == {}
|
|
131
|
+
assert "Ignoring invalid --var" in caplog.text
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_parse_vars_key_with_spaces():
|
|
135
|
+
result = cli._parse_vars([" solver = /opt/solver "])
|
|
136
|
+
assert result == {"solver": "/opt/solver"}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def test_run_tests_passes_variables_to_runner(tmp_path, monkeypatch):
|
|
140
|
+
config = tmp_path / "cases.json"
|
|
141
|
+
config.write_text('{"test_cases": []}', encoding="utf-8")
|
|
142
|
+
captured = {}
|
|
143
|
+
|
|
144
|
+
class VarRunner(DummyRunner):
|
|
145
|
+
def __init__(self, *args, **kwargs):
|
|
146
|
+
super().__init__(*args, **kwargs)
|
|
147
|
+
captured.update(kwargs)
|
|
148
|
+
|
|
149
|
+
def run_tests(self):
|
|
150
|
+
return True
|
|
151
|
+
|
|
152
|
+
monkeypatch.setattr(cli, "JSONRunner", VarRunner)
|
|
153
|
+
|
|
154
|
+
cli.run_tests(make_args(config, var=["solver=/opt/solver"]))
|
|
155
|
+
|
|
156
|
+
assert captured.get("variables") == {"solver": "/opt/solver"}
|
|
157
|
+
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/commands/__init__.py
RENAMED
|
File without changes
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/commands/compare.py
RENAMED
|
File without changes
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/__init__.py
RENAMED
|
File without changes
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/assertions.py
RENAMED
|
File without changes
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/base_runner.py
RENAMED
|
File without changes
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/execution.py
RENAMED
|
File without changes
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/history_store.py
RENAMED
|
File without changes
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/parallel_runner.py
RENAMED
|
File without changes
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/process_worker.py
RENAMED
|
File without changes
|
|
File without changes
|
{cli_test_framework-0.9.0 → cli_test_framework-0.9.1}/src/cli_test_framework/core/test_case.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|