symtest-cli 1.3.0__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.
- symtest_cli-1.3.0/LICENSE +21 -0
- symtest_cli-1.3.0/MANIFEST.in +4 -0
- symtest_cli-1.3.0/PKG-INFO +316 -0
- symtest_cli-1.3.0/README.md +267 -0
- symtest_cli-1.3.0/docs/design.md +796 -0
- symtest_cli-1.3.0/docs/design_en.md +796 -0
- symtest_cli-1.3.0/docs/tui_and_config_split_design.md +818 -0
- symtest_cli-1.3.0/docs/user_manual.md +1960 -0
- symtest_cli-1.3.0/docs/user_manual_en.md +1958 -0
- symtest_cli-1.3.0/pyproject.toml +3 -0
- symtest_cli-1.3.0/setup.cfg +4 -0
- symtest_cli-1.3.0/setup.py +75 -0
- symtest_cli-1.3.0/src/symtest/__init__.py +45 -0
- symtest_cli-1.3.0/src/symtest/cli.py +549 -0
- symtest_cli-1.3.0/src/symtest/commands/__init__.py +9 -0
- symtest_cli-1.3.0/src/symtest/commands/compare.py +221 -0
- symtest_cli-1.3.0/src/symtest/config/__init__.py +7 -0
- symtest_cli-1.3.0/src/symtest/config/config_io.py +346 -0
- symtest_cli-1.3.0/src/symtest/config/config_schema.py +330 -0
- symtest_cli-1.3.0/src/symtest/config/import_expander.py +149 -0
- symtest_cli-1.3.0/src/symtest/config/inheritance_expander.py +197 -0
- symtest_cli-1.3.0/src/symtest/core/__init__.py +15 -0
- symtest_cli-1.3.0/src/symtest/core/assertions.py +253 -0
- symtest_cli-1.3.0/src/symtest/core/base_runner.py +299 -0
- symtest_cli-1.3.0/src/symtest/core/config_loader.py +536 -0
- symtest_cli-1.3.0/src/symtest/core/execution.py +498 -0
- symtest_cli-1.3.0/src/symtest/core/history_store.py +96 -0
- symtest_cli-1.3.0/src/symtest/core/last_run_store.py +109 -0
- symtest_cli-1.3.0/src/symtest/core/parallel_runner.py +251 -0
- symtest_cli-1.3.0/src/symtest/core/process_worker.py +93 -0
- symtest_cli-1.3.0/src/symtest/core/sequence_state.py +143 -0
- symtest_cli-1.3.0/src/symtest/core/setup.py +137 -0
- symtest_cli-1.3.0/src/symtest/core/test_case.py +76 -0
- symtest_cli-1.3.0/src/symtest/core/types.py +92 -0
- symtest_cli-1.3.0/src/symtest/file_comparator/__init__.py +10 -0
- symtest_cli-1.3.0/src/symtest/file_comparator/base_comparator.py +109 -0
- symtest_cli-1.3.0/src/symtest/file_comparator/binary_comparator.py +399 -0
- symtest_cli-1.3.0/src/symtest/file_comparator/csv_comparator.py +241 -0
- symtest_cli-1.3.0/src/symtest/file_comparator/factory.py +191 -0
- symtest_cli-1.3.0/src/symtest/file_comparator/h5_comparator.py +777 -0
- symtest_cli-1.3.0/src/symtest/file_comparator/json_comparator.py +323 -0
- symtest_cli-1.3.0/src/symtest/file_comparator/result.py +213 -0
- symtest_cli-1.3.0/src/symtest/file_comparator/script_comparator.py +182 -0
- symtest_cli-1.3.0/src/symtest/file_comparator/text_comparator.py +182 -0
- symtest_cli-1.3.0/src/symtest/file_comparator/xml_comparator.py +150 -0
- symtest_cli-1.3.0/src/symtest/logging_config.py +66 -0
- symtest_cli-1.3.0/src/symtest/runners/__init__.py +15 -0
- symtest_cli-1.3.0/src/symtest/runners/config_runner.py +96 -0
- symtest_cli-1.3.0/src/symtest/runners/json_runner.py +21 -0
- symtest_cli-1.3.0/src/symtest/runners/parallel_config_runner.py +278 -0
- symtest_cli-1.3.0/src/symtest/runners/parallel_json_runner.py +26 -0
- symtest_cli-1.3.0/src/symtest/runners/parallel_yaml_runner.py +31 -0
- symtest_cli-1.3.0/src/symtest/runners/yaml_runner.py +26 -0
- symtest_cli-1.3.0/src/symtest/tui/__init__.py +11 -0
- symtest_cli-1.3.0/src/symtest/tui/app.py +90 -0
- symtest_cli-1.3.0/src/symtest/tui/controllers/__init__.py +0 -0
- symtest_cli-1.3.0/src/symtest/tui/controllers/case_controller.py +322 -0
- symtest_cli-1.3.0/src/symtest/tui/screens/__init__.py +0 -0
- symtest_cli-1.3.0/src/symtest/tui/screens/case_editor.py +244 -0
- symtest_cli-1.3.0/src/symtest/tui/screens/case_list.py +255 -0
- symtest_cli-1.3.0/src/symtest/tui/widgets/__init__.py +0 -0
- symtest_cli-1.3.0/src/symtest/tui/widgets/case_table.py +113 -0
- symtest_cli-1.3.0/src/symtest/tui/widgets/expected_editor.py +159 -0
- symtest_cli-1.3.0/src/symtest/tui/widgets/search_bar.py +160 -0
- symtest_cli-1.3.0/src/symtest/tui/widgets/steps_editor.py +243 -0
- symtest_cli-1.3.0/src/symtest/utils/__init__.py +21 -0
- symtest_cli-1.3.0/src/symtest/utils/junit_xml_writer.py +137 -0
- symtest_cli-1.3.0/src/symtest/utils/path_resolver.py +124 -0
- symtest_cli-1.3.0/src/symtest/utils/report_generator.py +208 -0
- symtest_cli-1.3.0/src/symtest_cli.egg-info/PKG-INFO +316 -0
- symtest_cli-1.3.0/src/symtest_cli.egg-info/SOURCES.txt +305 -0
- symtest_cli-1.3.0/src/symtest_cli.egg-info/dependency_links.txt +1 -0
- symtest_cli-1.3.0/src/symtest_cli.egg-info/entry_points.txt +4 -0
- symtest_cli-1.3.0/src/symtest_cli.egg-info/requires.txt +24 -0
- symtest_cli-1.3.0/src/symtest_cli.egg-info/top_level.txt +1 -0
- symtest_cli-1.3.0/tests/README.md +25 -0
- symtest_cli-1.3.0/tests/__init__.py +3 -0
- symtest_cli-1.3.0/tests/__pycache__/__init__.cpython-312.pyc +0 -0
- symtest_cli-1.3.0/tests/__pycache__/__init__.cpython-313.pyc +0 -0
- symtest_cli-1.3.0/tests/__pycache__/__init__.cpython-39.pyc +0 -0
- symtest_cli-1.3.0/tests/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/__pycache__/conftest.cpython-39-pytest-8.3.4.pyc +0 -0
- symtest_cli-1.3.0/tests/__pycache__/run_all.cpython-312.pyc +0 -0
- symtest_cli-1.3.0/tests/__pycache__/run_all.cpython-313.pyc +0 -0
- symtest_cli-1.3.0/tests/__pycache__/run_all.cpython-39.pyc +0 -0
- symtest_cli-1.3.0/tests/__pycache__/test_setup_module.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/conftest.py +15 -0
- symtest_cli-1.3.0/tests/demos/h5_filter_demo.py +107 -0
- symtest_cli-1.3.0/tests/demos/manual_report_example.py +32 -0
- symtest_cli-1.3.0/tests/demos/perf_parallel.py +121 -0
- symtest_cli-1.3.0/tests/e2e/__init__.py +2 -0
- symtest_cli-1.3.0/tests/e2e/__pycache__/__init__.cpython-312.pyc +0 -0
- symtest_cli-1.3.0/tests/e2e/__pycache__/__init__.cpython-313.pyc +0 -0
- symtest_cli-1.3.0/tests/e2e/__pycache__/__init__.cpython-39.pyc +0 -0
- symtest_cli-1.3.0/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/e2e/__pycache__/test_user_flows.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/e2e/__pycache__/test_user_flows.cpython-39-pytest-8.3.4.pyc +0 -0
- symtest_cli-1.3.0/tests/e2e/test_user_flows.py +74 -0
- symtest_cli-1.3.0/tests/fixtures/circular_config_a.json +7 -0
- symtest_cli-1.3.0/tests/fixtures/circular_config_b.json +7 -0
- symtest_cli-1.3.0/tests/fixtures/hourglass_stdout_mismatch.txt +35 -0
- symtest_cli-1.3.0/tests/fixtures/hourglass_stdout_sample.txt +70 -0
- symtest_cli-1.3.0/tests/fixtures/inheritance_base.json +31 -0
- symtest_cli-1.3.0/tests/fixtures/inheritance_chain.json +37 -0
- symtest_cli-1.3.0/tests/fixtures/inheritance_circular.json +16 -0
- symtest_cli-1.3.0/tests/fixtures/main_config.json +24 -0
- symtest_cli-1.3.0/tests/fixtures/missing_fields.json +22 -0
- symtest_cli-1.3.0/tests/fixtures/mock_fail_script.py +10 -0
- symtest_cli-1.3.0/tests/fixtures/mock_pass_script.py +9 -0
- symtest_cli-1.3.0/tests/fixtures/setup_main.json +13 -0
- symtest_cli-1.3.0/tests/fixtures/setup_sub.json +18 -0
- symtest_cli-1.3.0/tests/fixtures/sub_json_tests.yaml +27 -0
- symtest_cli-1.3.0/tests/fixtures/sub_text_tests.json +22 -0
- symtest_cli-1.3.0/tests/fixtures/test_cases.json +57 -0
- symtest_cli-1.3.0/tests/fixtures/test_cases.yaml +10 -0
- symtest_cli-1.3.0/tests/fixtures/test_cases1.json +182 -0
- symtest_cli-1.3.0/tests/fixtures/test_with_setup.json +42 -0
- symtest_cli-1.3.0/tests/fixtures/test_with_setup.yaml +42 -0
- symtest_cli-1.3.0/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/__pycache__/test_history_feature.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/__pycache__/test_new_cli_features.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/__pycache__/test_new_cli_features.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/__pycache__/test_real_command_execution.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/__pycache__/test_sequence.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/__pycache__/test_sequence.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/__pycache__/test_sequence.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_json_compare.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_json_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_text_compare.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_text_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/file_compare/test_binary_compare.py +152 -0
- symtest_cli-1.3.0/tests/integration/file_compare/test_csv_compare.py +166 -0
- symtest_cli-1.3.0/tests/integration/file_compare/test_h5_compare.py +107 -0
- symtest_cli-1.3.0/tests/integration/file_compare/test_json_compare.py +48 -0
- symtest_cli-1.3.0/tests/integration/file_compare/test_text_compare.py +40 -0
- symtest_cli-1.3.0/tests/integration/file_compare/test_xml_compare.py +72 -0
- symtest_cli-1.3.0/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-39-pytest-8.3.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/parallel/test_parallel_runner.py +145 -0
- symtest_cli-1.3.0/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-39-pytest-8.3.4.pyc +0 -0
- symtest_cli-1.3.0/tests/integration/path_handling/test_spaces_in_paths.py +116 -0
- symtest_cli-1.3.0/tests/integration/test_history_feature.py +176 -0
- symtest_cli-1.3.0/tests/integration/test_new_cli_features.py +118 -0
- symtest_cli-1.3.0/tests/integration/test_real_command_execution.py +124 -0
- symtest_cli-1.3.0/tests/integration/test_sequence.py +307 -0
- symtest_cli-1.3.0/tests/run_all.py +65 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_binary_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_binary_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_cli.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_cli.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_cli.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_config_io.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_config_io.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_h5_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_import_expander.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_inheritance_expander.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_inheritance_expander.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_result.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_result.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_run_all.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_run_all.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/__pycache__/test_run_all.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/commands/__pycache__/test_compare_command.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/commands/test_compare_command.py +73 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_assertions.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_config_loader.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_execution.cpython-312.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_execution.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_execution_new_features.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_execution_new_features.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_history_store.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_last_run_store.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_last_run_store.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_process_worker.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_sequence_state.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_setup.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_setup.cpython-39-pytest-8.3.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_validation_error.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_validation_error.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_xfail.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/__pycache__/test_xfail.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/core/test_assertions.py +411 -0
- symtest_cli-1.3.0/tests/unit/core/test_config_loader.py +524 -0
- symtest_cli-1.3.0/tests/unit/core/test_config_loader_new_features.py +224 -0
- symtest_cli-1.3.0/tests/unit/core/test_execution.py +241 -0
- symtest_cli-1.3.0/tests/unit/core/test_execution_new_features.py +323 -0
- symtest_cli-1.3.0/tests/unit/core/test_history_store.py +140 -0
- symtest_cli-1.3.0/tests/unit/core/test_last_run_store.py +142 -0
- symtest_cli-1.3.0/tests/unit/core/test_process_worker.py +143 -0
- symtest_cli-1.3.0/tests/unit/core/test_sequence_state.py +85 -0
- symtest_cli-1.3.0/tests/unit/core/test_setup.py +278 -0
- symtest_cli-1.3.0/tests/unit/core/test_validation_error.py +254 -0
- symtest_cli-1.3.0/tests/unit/core/test_xfail.py +133 -0
- symtest_cli-1.3.0/tests/unit/file_comparator/__pycache__/__init__.cpython-312.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/file_comparator/test_error_analysis.py +119 -0
- symtest_cli-1.3.0/tests/unit/file_comparator/test_hourglass_tangent_comparator.py +123 -0
- symtest_cli-1.3.0/tests/unit/file_comparator/test_script_comparator.py +83 -0
- symtest_cli-1.3.0/tests/unit/file_comparator/test_workspace_plugins.py +104 -0
- symtest_cli-1.3.0/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-39-pytest-8.3.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/runners/__pycache__/test_test_case_filter.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/runners/test_json_yaml_runner.py +142 -0
- symtest_cli-1.3.0/tests/unit/runners/test_test_case_filter.py +207 -0
- symtest_cli-1.3.0/tests/unit/runners/test_test_case_tag_filter.py +254 -0
- symtest_cli-1.3.0/tests/unit/test_binary_comparator.py +428 -0
- symtest_cli-1.3.0/tests/unit/test_cli.py +818 -0
- symtest_cli-1.3.0/tests/unit/test_config_io.py +362 -0
- symtest_cli-1.3.0/tests/unit/test_h5_comparator.py +696 -0
- symtest_cli-1.3.0/tests/unit/test_import_expander.py +124 -0
- symtest_cli-1.3.0/tests/unit/test_inheritance_expander.py +469 -0
- symtest_cli-1.3.0/tests/unit/test_result.py +421 -0
- symtest_cli-1.3.0/tests/unit/test_run_all.py +18 -0
- symtest_cli-1.3.0/tests/unit/tui/__init__.py +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/__init__.cpython-312.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/__init__.cpython-313.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_app.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_case_controller.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_search_functions.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_tui_run_test.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_tui_run_test.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/__pycache__/test_widgets_data.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/tui/conftest.py +73 -0
- symtest_cli-1.3.0/tests/unit/tui/test_app.py +106 -0
- symtest_cli-1.3.0/tests/unit/tui/test_case_controller.py +425 -0
- symtest_cli-1.3.0/tests/unit/tui/test_search_functions.py +187 -0
- symtest_cli-1.3.0/tests/unit/tui/test_tui_run_test.py +384 -0
- symtest_cli-1.3.0/tests/unit/tui/test_widgets_data.py +188 -0
- symtest_cli-1.3.0/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/utils/__pycache__/test_report_generator.cpython-313-pytest-9.0.2.pyc +0 -0
- symtest_cli-1.3.0/tests/unit/utils/test_junit_xml_writer.py +334 -0
- symtest_cli-1.3.0/tests/unit/utils/test_report_generator.py +149 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 CLI Test Framework Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR OUT OF IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: symtest-cli
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: Regression testing for CLI applications, with multi-step workflows and numerical file comparison.
|
|
5
|
+
Home-page: https://github.com/ozil111/symtest
|
|
6
|
+
Author: Xiaotong Wang
|
|
7
|
+
Author-email: xiaotongwang98@gmail.com
|
|
8
|
+
Project-URL: Documentation, https://github.com/ozil111/symtest/blob/main/docs/user_manual.md
|
|
9
|
+
Project-URL: Source, https://github.com/ozil111/symtest
|
|
10
|
+
Project-URL: Tracker, https://github.com/ozil111/symtest/issues
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Topic :: Software Development :: Testing
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: >=3.9
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: h5py<4.0.0,>=3.11.0
|
|
22
|
+
Requires-Dist: numpy>=1.21.0; python_version < "3.12"
|
|
23
|
+
Requires-Dist: numpy>=1.26.0; python_version >= "3.12"
|
|
24
|
+
Provides-Extra: yaml
|
|
25
|
+
Requires-Dist: PyYAML>=6.0; extra == "yaml"
|
|
26
|
+
Provides-Extra: tui
|
|
27
|
+
Requires-Dist: textual>=0.40.0; extra == "tui"
|
|
28
|
+
Provides-Extra: all
|
|
29
|
+
Requires-Dist: PyYAML>=6.0; extra == "all"
|
|
30
|
+
Requires-Dist: textual>=0.40.0; extra == "all"
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: PyYAML>=6.0; extra == "dev"
|
|
33
|
+
Requires-Dist: textual>=0.40.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
37
|
+
Dynamic: author
|
|
38
|
+
Dynamic: author-email
|
|
39
|
+
Dynamic: classifier
|
|
40
|
+
Dynamic: description
|
|
41
|
+
Dynamic: description-content-type
|
|
42
|
+
Dynamic: home-page
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
Dynamic: project-url
|
|
45
|
+
Dynamic: provides-extra
|
|
46
|
+
Dynamic: requires-dist
|
|
47
|
+
Dynamic: requires-python
|
|
48
|
+
Dynamic: summary
|
|
49
|
+
|
|
50
|
+
# CLI Test Framework
|
|
51
|
+
|
|
52
|
+
[中文](README_cn.md) | English
|
|
53
|
+
|
|
54
|
+
> **Note:** This project was formerly known as `cli-test-framework`.
|
|
55
|
+
> Since version 1.3.0 it is released as
|
|
56
|
+
> [`symtest`](https://pypi.org/project/symtest/); the old package name is no
|
|
57
|
+
> longer updated. Install with:
|
|
58
|
+
>
|
|
59
|
+
> ```bash
|
|
60
|
+
> pip install symtest
|
|
61
|
+
> ```
|
|
62
|
+
|
|
63
|
+
A feature-focused automated testing framework for command-line applications.
|
|
64
|
+
It is built for regression suites that need more than an exit-code check:
|
|
65
|
+
multi-step commands, numerical result comparison, large configuration sets,
|
|
66
|
+
parallel execution, and CI-ready reports.
|
|
67
|
+
|
|
68
|
+
The project grew out of finite-element solver development, where a single test
|
|
69
|
+
may run several programs, produce HDF5 or CSV results, compare them with
|
|
70
|
+
tolerances, and track execution time across revisions.
|
|
71
|
+
|
|
72
|
+
## What it solves
|
|
73
|
+
|
|
74
|
+
CLI Test Framework keeps the execution workflow and its acceptance criteria in
|
|
75
|
+
one JSON or YAML configuration:
|
|
76
|
+
|
|
77
|
+
- **Execute workflows** — single commands or fail-fast step sequences, with
|
|
78
|
+
timeouts, retries, variables, tags, and expected-failure support.
|
|
79
|
+
- **Verify results** — return codes, output text and regular expressions, plus
|
|
80
|
+
text, JSON, CSV, XML, HDF5, binary, and custom-script file comparisons.
|
|
81
|
+
- **Manage large suites** — split configurations with `import`, reuse templates
|
|
82
|
+
with `extends`, filter by name or tag, and inspect cases across files in the
|
|
83
|
+
optional TUI.
|
|
84
|
+
- **Iterate and integrate** — parallel execution, `--last-failed`, step-level
|
|
85
|
+
`--resume`, runtime history, structured reports, and JUnit XML output.
|
|
86
|
+
|
|
87
|
+
The emphasis is practical: features are added to solve test workflows that
|
|
88
|
+
occur in real CLI and scientific-computing projects.
|
|
89
|
+
|
|
90
|
+
## Installation
|
|
91
|
+
|
|
92
|
+
Python 3.9 or newer is required.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pip install symtest
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
YAML and the TUI are optional:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip install "symtest[yaml]"
|
|
102
|
+
pip install "symtest[tui]"
|
|
103
|
+
pip install "symtest[all]"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The default installation includes HDF5 and numerical comparison support.
|
|
107
|
+
|
|
108
|
+
## Quick start
|
|
109
|
+
|
|
110
|
+
Create `test_cases.json`:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"test_cases": [
|
|
115
|
+
{
|
|
116
|
+
"name": "hello",
|
|
117
|
+
"command": "echo",
|
|
118
|
+
"args": ["Hello World"],
|
|
119
|
+
"tags": ["smoke"],
|
|
120
|
+
"expected": {
|
|
121
|
+
"return_code": 0,
|
|
122
|
+
"output_contains": ["Hello World"]
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Run it:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
symtest run test_cases.json
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Validate a configuration without executing it:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
symtest validate test_cases.json
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Numerical golden-file testing
|
|
142
|
+
|
|
143
|
+
File comparisons can be part of a test's acceptance criteria. Comparator
|
|
144
|
+
parameters such as tolerances, table selection, filters, and encodings are
|
|
145
|
+
declared next to the command:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"test_cases": [
|
|
150
|
+
{
|
|
151
|
+
"name": "FEA displacement check",
|
|
152
|
+
"command": "my_solver",
|
|
153
|
+
"args": ["--input", "case1.dat", "--output", "out.h5"],
|
|
154
|
+
"expected": {
|
|
155
|
+
"return_code": 0,
|
|
156
|
+
"output_contains": ["simulation finished"],
|
|
157
|
+
"compare_files": [
|
|
158
|
+
{
|
|
159
|
+
"actual": "out.h5",
|
|
160
|
+
"baseline": "ref/golden.h5",
|
|
161
|
+
"rtol": 1e-5,
|
|
162
|
+
"atol": 1e-8,
|
|
163
|
+
"tables": ["NASTRAN/RESULT/NODAL/DISPLACEMENT"]
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"actual": "summary.csv",
|
|
167
|
+
"baseline": "ref/summary.csv",
|
|
168
|
+
"rtol": 1e-6
|
|
169
|
+
}
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The comparator type is inferred from the extension when `type` is omitted.
|
|
178
|
+
Built-in types are `text`, `json`, `csv`, `xml`, `h5`, `binary`, and `script`.
|
|
179
|
+
Workspace comparators can be added without changing the framework.
|
|
180
|
+
|
|
181
|
+
To intentionally accept changed outputs, use `--update-baseline`. Because this
|
|
182
|
+
can overwrite reference files, interactive runs require typing `yes`;
|
|
183
|
+
non-interactive runs must explicitly add `--yes`:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
symtest run test_cases.json --update-baseline
|
|
187
|
+
symtest run test_cases.json --update-baseline --yes # automation / CI
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Keep baselines under version control and review every update.
|
|
191
|
+
|
|
192
|
+
## Multi-step and iterative workflows
|
|
193
|
+
|
|
194
|
+
A case may contain an ordered `steps` list. Execution stops at the first failed
|
|
195
|
+
step. For long workflows, `--resume` reuses saved state and skips steps that
|
|
196
|
+
already passed:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
symtest run solver_tests.json
|
|
200
|
+
symtest run solver_tests.json --last-failed
|
|
201
|
+
symtest run solver_tests.json -t long_case --resume
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
`--resume` deliberately trusts that workspace artifacts have not changed
|
|
205
|
+
between runs.
|
|
206
|
+
|
|
207
|
+
## Large test suites and the optional TUI
|
|
208
|
+
|
|
209
|
+
Large suites can be divided into sub-configurations:
|
|
210
|
+
|
|
211
|
+
```json
|
|
212
|
+
{
|
|
213
|
+
"test_cases": [
|
|
214
|
+
{"import": "cases/text_tests.json", "tags": ["text"]},
|
|
215
|
+
{"import": "cases/h5_tests.json", "tags": ["h5", "regression"]}
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
The optional TUI provides one searchable view across imported files. It is
|
|
221
|
+
intended as an aid for locating cases and reviewing scenario coverage in large
|
|
222
|
+
projects, rather than a requirement for normal test execution.
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
symtest tui main_config.json
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Parallel execution and resources
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
symtest run test_cases.json --parallel --workers 4
|
|
232
|
+
symtest run test_cases.json --parallel --execution-mode process
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Thread mode currently supports CPU-token allocation, solver thread environment
|
|
236
|
+
variables, and longest-processing-time-first scheduling using estimates or
|
|
237
|
+
runtime history. Process mode provides execution isolation but does not yet use
|
|
238
|
+
the resource scheduler. Memory enforcement, priority semantics, and broader
|
|
239
|
+
resource scheduling remain active areas of development.
|
|
240
|
+
|
|
241
|
+
## CI and reports
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
symtest run test_cases.json \
|
|
245
|
+
--parallel --workers 4 \
|
|
246
|
+
--junit-xml report.xml
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
The current suite contains 750 unit, integration, and end-to-end tests with 83%
|
|
250
|
+
line coverage. CI exercises Windows and Linux across Python 3.9 through 3.13.
|
|
251
|
+
|
|
252
|
+
## Python API
|
|
253
|
+
|
|
254
|
+
```python
|
|
255
|
+
from symtest.runners import JSONRunner, ParallelJSONRunner
|
|
256
|
+
|
|
257
|
+
runner = ParallelJSONRunner(
|
|
258
|
+
config_file="test_cases.json",
|
|
259
|
+
max_workers=4,
|
|
260
|
+
execution_mode="thread",
|
|
261
|
+
history_dir="./hist",
|
|
262
|
+
variables={"solver": "/opt/solver/bin/solver"},
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
success = runner.run_tests()
|
|
266
|
+
for detail in runner.results["details"]:
|
|
267
|
+
print(detail["name"], detail["status"], detail.get("duration"))
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Standalone file comparison
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
compare-files result1.h5 result2.h5 --h5-table-regex "output_.*" --h5-rtol 1e-5
|
|
274
|
+
compare-files data1.csv data2.csv --csv-rtol 1e-4 --csv-data-filter ">1e-6"
|
|
275
|
+
compare-files data1.json data2.json --json-compare-mode key-based --json-key-field id
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## AI-assisted TDD, as a side benefit
|
|
279
|
+
|
|
280
|
+
The same configuration can serve as a machine-readable acceptance contract.
|
|
281
|
+
Structured validation failures, comparison details, and targeted reruns work
|
|
282
|
+
well in an AI-assisted TDD loop:
|
|
283
|
+
|
|
284
|
+
```text
|
|
285
|
+
define acceptance criteria
|
|
286
|
+
→ run the relevant cases
|
|
287
|
+
→ inspect the structured failure
|
|
288
|
+
→ change the implementation
|
|
289
|
+
→ rerun with --last-failed
|
|
290
|
+
→ run the full regression suite
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
This is a useful consequence of explicit tests and structured results, not a
|
|
294
|
+
requirement for using the framework.
|
|
295
|
+
|
|
296
|
+
## Documentation
|
|
297
|
+
|
|
298
|
+
- [User manual](docs/user_manual_en.md)
|
|
299
|
+
- [Design document](docs/design_en.md)
|
|
300
|
+
- [Plugin examples](examples/plugins/README.md)
|
|
301
|
+
|
|
302
|
+
## Development
|
|
303
|
+
|
|
304
|
+
Install the package with all optional and test dependencies:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
pip install -e ".[dev]"
|
|
308
|
+
python -m pytest tests/unit tests/integration tests/e2e
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Bug fixes, comparator plugins, documentation improvements, and reports from
|
|
312
|
+
real-world test workflows are welcome.
|
|
313
|
+
|
|
314
|
+
## License
|
|
315
|
+
|
|
316
|
+
MIT
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# CLI Test Framework
|
|
2
|
+
|
|
3
|
+
[中文](README_cn.md) | English
|
|
4
|
+
|
|
5
|
+
> **Note:** This project was formerly known as `cli-test-framework`.
|
|
6
|
+
> Since version 1.3.0 it is released as
|
|
7
|
+
> [`symtest`](https://pypi.org/project/symtest/); the old package name is no
|
|
8
|
+
> longer updated. Install with:
|
|
9
|
+
>
|
|
10
|
+
> ```bash
|
|
11
|
+
> pip install symtest
|
|
12
|
+
> ```
|
|
13
|
+
|
|
14
|
+
A feature-focused automated testing framework for command-line applications.
|
|
15
|
+
It is built for regression suites that need more than an exit-code check:
|
|
16
|
+
multi-step commands, numerical result comparison, large configuration sets,
|
|
17
|
+
parallel execution, and CI-ready reports.
|
|
18
|
+
|
|
19
|
+
The project grew out of finite-element solver development, where a single test
|
|
20
|
+
may run several programs, produce HDF5 or CSV results, compare them with
|
|
21
|
+
tolerances, and track execution time across revisions.
|
|
22
|
+
|
|
23
|
+
## What it solves
|
|
24
|
+
|
|
25
|
+
CLI Test Framework keeps the execution workflow and its acceptance criteria in
|
|
26
|
+
one JSON or YAML configuration:
|
|
27
|
+
|
|
28
|
+
- **Execute workflows** — single commands or fail-fast step sequences, with
|
|
29
|
+
timeouts, retries, variables, tags, and expected-failure support.
|
|
30
|
+
- **Verify results** — return codes, output text and regular expressions, plus
|
|
31
|
+
text, JSON, CSV, XML, HDF5, binary, and custom-script file comparisons.
|
|
32
|
+
- **Manage large suites** — split configurations with `import`, reuse templates
|
|
33
|
+
with `extends`, filter by name or tag, and inspect cases across files in the
|
|
34
|
+
optional TUI.
|
|
35
|
+
- **Iterate and integrate** — parallel execution, `--last-failed`, step-level
|
|
36
|
+
`--resume`, runtime history, structured reports, and JUnit XML output.
|
|
37
|
+
|
|
38
|
+
The emphasis is practical: features are added to solve test workflows that
|
|
39
|
+
occur in real CLI and scientific-computing projects.
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
Python 3.9 or newer is required.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install symtest
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
YAML and the TUI are optional:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install "symtest[yaml]"
|
|
53
|
+
pip install "symtest[tui]"
|
|
54
|
+
pip install "symtest[all]"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The default installation includes HDF5 and numerical comparison support.
|
|
58
|
+
|
|
59
|
+
## Quick start
|
|
60
|
+
|
|
61
|
+
Create `test_cases.json`:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"test_cases": [
|
|
66
|
+
{
|
|
67
|
+
"name": "hello",
|
|
68
|
+
"command": "echo",
|
|
69
|
+
"args": ["Hello World"],
|
|
70
|
+
"tags": ["smoke"],
|
|
71
|
+
"expected": {
|
|
72
|
+
"return_code": 0,
|
|
73
|
+
"output_contains": ["Hello World"]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Run it:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
symtest run test_cases.json
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Validate a configuration without executing it:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
symtest validate test_cases.json
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Numerical golden-file testing
|
|
93
|
+
|
|
94
|
+
File comparisons can be part of a test's acceptance criteria. Comparator
|
|
95
|
+
parameters such as tolerances, table selection, filters, and encodings are
|
|
96
|
+
declared next to the command:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"test_cases": [
|
|
101
|
+
{
|
|
102
|
+
"name": "FEA displacement check",
|
|
103
|
+
"command": "my_solver",
|
|
104
|
+
"args": ["--input", "case1.dat", "--output", "out.h5"],
|
|
105
|
+
"expected": {
|
|
106
|
+
"return_code": 0,
|
|
107
|
+
"output_contains": ["simulation finished"],
|
|
108
|
+
"compare_files": [
|
|
109
|
+
{
|
|
110
|
+
"actual": "out.h5",
|
|
111
|
+
"baseline": "ref/golden.h5",
|
|
112
|
+
"rtol": 1e-5,
|
|
113
|
+
"atol": 1e-8,
|
|
114
|
+
"tables": ["NASTRAN/RESULT/NODAL/DISPLACEMENT"]
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"actual": "summary.csv",
|
|
118
|
+
"baseline": "ref/summary.csv",
|
|
119
|
+
"rtol": 1e-6
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The comparator type is inferred from the extension when `type` is omitted.
|
|
129
|
+
Built-in types are `text`, `json`, `csv`, `xml`, `h5`, `binary`, and `script`.
|
|
130
|
+
Workspace comparators can be added without changing the framework.
|
|
131
|
+
|
|
132
|
+
To intentionally accept changed outputs, use `--update-baseline`. Because this
|
|
133
|
+
can overwrite reference files, interactive runs require typing `yes`;
|
|
134
|
+
non-interactive runs must explicitly add `--yes`:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
symtest run test_cases.json --update-baseline
|
|
138
|
+
symtest run test_cases.json --update-baseline --yes # automation / CI
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Keep baselines under version control and review every update.
|
|
142
|
+
|
|
143
|
+
## Multi-step and iterative workflows
|
|
144
|
+
|
|
145
|
+
A case may contain an ordered `steps` list. Execution stops at the first failed
|
|
146
|
+
step. For long workflows, `--resume` reuses saved state and skips steps that
|
|
147
|
+
already passed:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
symtest run solver_tests.json
|
|
151
|
+
symtest run solver_tests.json --last-failed
|
|
152
|
+
symtest run solver_tests.json -t long_case --resume
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`--resume` deliberately trusts that workspace artifacts have not changed
|
|
156
|
+
between runs.
|
|
157
|
+
|
|
158
|
+
## Large test suites and the optional TUI
|
|
159
|
+
|
|
160
|
+
Large suites can be divided into sub-configurations:
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"test_cases": [
|
|
165
|
+
{"import": "cases/text_tests.json", "tags": ["text"]},
|
|
166
|
+
{"import": "cases/h5_tests.json", "tags": ["h5", "regression"]}
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The optional TUI provides one searchable view across imported files. It is
|
|
172
|
+
intended as an aid for locating cases and reviewing scenario coverage in large
|
|
173
|
+
projects, rather than a requirement for normal test execution.
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
symtest tui main_config.json
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Parallel execution and resources
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
symtest run test_cases.json --parallel --workers 4
|
|
183
|
+
symtest run test_cases.json --parallel --execution-mode process
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Thread mode currently supports CPU-token allocation, solver thread environment
|
|
187
|
+
variables, and longest-processing-time-first scheduling using estimates or
|
|
188
|
+
runtime history. Process mode provides execution isolation but does not yet use
|
|
189
|
+
the resource scheduler. Memory enforcement, priority semantics, and broader
|
|
190
|
+
resource scheduling remain active areas of development.
|
|
191
|
+
|
|
192
|
+
## CI and reports
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
symtest run test_cases.json \
|
|
196
|
+
--parallel --workers 4 \
|
|
197
|
+
--junit-xml report.xml
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
The current suite contains 750 unit, integration, and end-to-end tests with 83%
|
|
201
|
+
line coverage. CI exercises Windows and Linux across Python 3.9 through 3.13.
|
|
202
|
+
|
|
203
|
+
## Python API
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
from symtest.runners import JSONRunner, ParallelJSONRunner
|
|
207
|
+
|
|
208
|
+
runner = ParallelJSONRunner(
|
|
209
|
+
config_file="test_cases.json",
|
|
210
|
+
max_workers=4,
|
|
211
|
+
execution_mode="thread",
|
|
212
|
+
history_dir="./hist",
|
|
213
|
+
variables={"solver": "/opt/solver/bin/solver"},
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
success = runner.run_tests()
|
|
217
|
+
for detail in runner.results["details"]:
|
|
218
|
+
print(detail["name"], detail["status"], detail.get("duration"))
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Standalone file comparison
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
compare-files result1.h5 result2.h5 --h5-table-regex "output_.*" --h5-rtol 1e-5
|
|
225
|
+
compare-files data1.csv data2.csv --csv-rtol 1e-4 --csv-data-filter ">1e-6"
|
|
226
|
+
compare-files data1.json data2.json --json-compare-mode key-based --json-key-field id
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## AI-assisted TDD, as a side benefit
|
|
230
|
+
|
|
231
|
+
The same configuration can serve as a machine-readable acceptance contract.
|
|
232
|
+
Structured validation failures, comparison details, and targeted reruns work
|
|
233
|
+
well in an AI-assisted TDD loop:
|
|
234
|
+
|
|
235
|
+
```text
|
|
236
|
+
define acceptance criteria
|
|
237
|
+
→ run the relevant cases
|
|
238
|
+
→ inspect the structured failure
|
|
239
|
+
→ change the implementation
|
|
240
|
+
→ rerun with --last-failed
|
|
241
|
+
→ run the full regression suite
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
This is a useful consequence of explicit tests and structured results, not a
|
|
245
|
+
requirement for using the framework.
|
|
246
|
+
|
|
247
|
+
## Documentation
|
|
248
|
+
|
|
249
|
+
- [User manual](docs/user_manual_en.md)
|
|
250
|
+
- [Design document](docs/design_en.md)
|
|
251
|
+
- [Plugin examples](examples/plugins/README.md)
|
|
252
|
+
|
|
253
|
+
## Development
|
|
254
|
+
|
|
255
|
+
Install the package with all optional and test dependencies:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
pip install -e ".[dev]"
|
|
259
|
+
python -m pytest tests/unit tests/integration tests/e2e
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Bug fixes, comparator plugins, documentation improvements, and reports from
|
|
263
|
+
real-world test workflows are welcome.
|
|
264
|
+
|
|
265
|
+
## License
|
|
266
|
+
|
|
267
|
+
MIT
|