symtest-cli 1.3.1__tar.gz → 1.3.2__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.1/src/symtest_cli.egg-info → symtest_cli-1.3.2}/PKG-INFO +8 -5
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/README.md +3 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/docs/design.md +54 -10
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/docs/design_en.md +52 -10
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/docs/user_manual.md +133 -2
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/docs/user_manual_en.md +133 -2
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/setup.py +4 -4
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/__init__.py +1 -1
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/config/config_io.py +73 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/config/config_schema.py +38 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/core/assertions.py +1 -1
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/core/base_runner.py +90 -4
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/core/config_loader.py +73 -65
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/core/execution.py +7 -1
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/core/history_store.py +1 -1
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/core/last_run_store.py +2 -2
- symtest_cli-1.3.2/src/symtest/core/parallel_runner.py +465 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/core/process_worker.py +2 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/core/sequence_state.py +5 -3
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/core/test_case.py +48 -3
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/core/types.py +1 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/file_comparator/base_comparator.py +13 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/file_comparator/text_comparator.py +56 -32
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/runners/parallel_config_runner.py +69 -3
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/tui/screens/case_editor.py +38 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2/src/symtest_cli.egg-info}/PKG-INFO +8 -5
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest_cli.egg-info/SOURCES.txt +26 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/integration/__pycache__/test_new_cli_features.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/__pycache__/test_new_cli_features.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.2/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/integration/file_compare/test_text_compare.py +124 -0
- symtest_cli-1.3.2/tests/integration/parallel/__pycache__/test_depends_on.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.2/tests/integration/parallel/__pycache__/test_depends_on.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/integration/parallel/test_depends_on.py +229 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/test_history_feature.py +5 -3
- symtest_cli-1.3.2/tests/unit/__pycache__/test_binary_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_binary_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/__pycache__/test_cli.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_cli.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/__pycache__/test_config_io.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_config_io.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/__pycache__/test_inheritance_expander.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_inheritance_expander.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/__pycache__/test_result.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_result.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/core/__pycache__/test_case_env.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/core/__pycache__/test_case_env.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/core/__pycache__/test_execution_new_features.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_execution_new_features.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/core/__pycache__/test_last_run_store.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_last_run_store.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/core/__pycache__/test_sequence_state.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_sequence_state.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/core/__pycache__/test_validation_error.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_validation_error.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/core/__pycache__/test_xfail.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_xfail.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/core/test_case_env.py +225 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/test_sequence_state.py +1 -1
- symtest_cli-1.3.2/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/tui/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/tui/__pycache__/test_tui_run_test.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_tui_run_test.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.2/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.1/src/symtest/core/parallel_runner.py +0 -251
- symtest_cli-1.3.1/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.1/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- symtest_cli-1.3.1/tests/integration/file_compare/test_text_compare.py +0 -40
- symtest_cli-1.3.1/tests/unit/__pycache__/test_cli.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.1/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.1/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- symtest_cli-1.3.1/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/LICENSE +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/MANIFEST.in +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/docs/tui_and_config_split_design.md +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/pyproject.toml +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/setup.cfg +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/cli.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/commands/__init__.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/commands/compare.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/config/__init__.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/config/import_expander.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/config/inheritance_expander.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/core/__init__.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/core/setup.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/file_comparator/__init__.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/file_comparator/binary_comparator.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/file_comparator/csv_comparator.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/file_comparator/factory.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/file_comparator/h5_comparator.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/file_comparator/json_comparator.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/file_comparator/result.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/file_comparator/script_comparator.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/file_comparator/xml_comparator.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/logging_config.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/runners/__init__.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/runners/config_runner.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/runners/json_runner.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/runners/parallel_json_runner.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/runners/parallel_yaml_runner.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/runners/yaml_runner.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/tui/__init__.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/tui/app.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/tui/controllers/__init__.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/tui/controllers/case_controller.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/tui/screens/__init__.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/tui/screens/case_list.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/tui/widgets/__init__.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/tui/widgets/case_table.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/tui/widgets/expected_editor.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/tui/widgets/search_bar.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/tui/widgets/steps_editor.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/utils/__init__.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/utils/junit_xml_writer.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/utils/path_resolver.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest/utils/report_generator.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest_cli.egg-info/dependency_links.txt +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest_cli.egg-info/entry_points.txt +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest_cli.egg-info/requires.txt +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/src/symtest_cli.egg-info/top_level.txt +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/README.md +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/__init__.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/__pycache__/__init__.cpython-312.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/__pycache__/__init__.cpython-313.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/__pycache__/__init__.cpython-39.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/__pycache__/conftest.cpython-39-pytest-8.3.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/__pycache__/run_all.cpython-312.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/__pycache__/run_all.cpython-313.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/__pycache__/run_all.cpython-39.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/__pycache__/test_setup_module.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/conftest.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/demos/h5_filter_demo.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/demos/manual_report_example.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/demos/perf_parallel.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/e2e/__init__.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/e2e/__pycache__/__init__.cpython-312.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/e2e/__pycache__/__init__.cpython-313.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/e2e/__pycache__/__init__.cpython-39.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/e2e/__pycache__/test_user_flows.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/e2e/__pycache__/test_user_flows.cpython-39-pytest-8.3.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/e2e/test_user_flows.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/circular_config_a.json +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/circular_config_b.json +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/hourglass_stdout_mismatch.txt +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/hourglass_stdout_sample.txt +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/inheritance_base.json +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/inheritance_chain.json +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/inheritance_circular.json +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/main_config.json +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/missing_fields.json +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/mock_fail_script.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/mock_pass_script.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/setup_main.json +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/setup_sub.json +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/sub_json_tests.yaml +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/sub_text_tests.json +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/test_cases.json +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/test_cases.yaml +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/test_cases1.json +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/test_with_setup.json +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/fixtures/test_with_setup.yaml +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/__pycache__/test_history_feature.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/__pycache__/test_new_cli_features.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/__pycache__/test_real_command_execution.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/__pycache__/test_sequence.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/test_binary_compare.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/test_csv_compare.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/test_h5_compare.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/test_json_compare.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/file_compare/test_xml_compare.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-39-pytest-8.3.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/parallel/test_parallel_runner.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-39-pytest-8.3.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/path_handling/test_spaces_in_paths.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/test_new_cli_features.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/test_real_command_execution.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/integration/test_sequence.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/run_all.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_binary_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_cli.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_config_io.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_h5_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_import_expander.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_inheritance_expander.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_result.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-7.4.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/__pycache__/test_run_all.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/commands/__pycache__/test_compare_command.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/commands/test_compare_command.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_assertions.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_config_loader.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_execution.cpython-312.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_execution.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_execution_new_features.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_history_store.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_last_run_store.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_process_worker.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_setup.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_setup.cpython-39-pytest-8.3.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_validation_error.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/__pycache__/test_xfail.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/test_assertions.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/test_config_loader.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/test_config_loader_new_features.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/test_execution.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/test_execution_new_features.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/test_history_store.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/test_last_run_store.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/test_process_worker.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/test_setup.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/test_validation_error.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/core/test_xfail.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/file_comparator/__pycache__/__init__.cpython-312.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/file_comparator/test_error_analysis.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/file_comparator/test_hourglass_tangent_comparator.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/file_comparator/test_script_comparator.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/file_comparator/test_workspace_plugins.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-39-pytest-8.3.4.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/runners/test_json_yaml_runner.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/runners/test_test_case_filter.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/runners/test_test_case_tag_filter.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/test_binary_comparator.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/test_cli.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/test_config_io.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/test_h5_comparator.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/test_import_expander.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/test_inheritance_expander.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/test_result.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/test_run_all.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__init__.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/__init__.cpython-312.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/__init__.cpython-313.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_app.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_case_controller.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_search_functions.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_tui_run_test.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/__pycache__/test_widgets_data.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/conftest.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/test_app.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/test_case_controller.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/test_search_functions.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/test_tui_run_test.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/tui/test_widgets_data.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/utils/__pycache__/test_report_generator.cpython-313-pytest-9.0.2.pyc +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/utils/test_junit_xml_writer.py +0 -0
- {symtest_cli-1.3.1 → symtest_cli-1.3.2}/tests/unit/utils/test_report_generator.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: symtest-cli
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.2
|
|
4
4
|
Summary: Regression testing for CLI applications, with multi-step workflows and numerical file comparison.
|
|
5
|
-
Home-page: https://github.com/ozil111/cli
|
|
5
|
+
Home-page: https://github.com/ozil111/symtest-cli
|
|
6
6
|
Author: Xiaotong Wang
|
|
7
7
|
Author-email: xiaotongwang98@gmail.com
|
|
8
|
-
Project-URL: Documentation, https://github.com/ozil111/cli
|
|
9
|
-
Project-URL: Source, https://github.com/ozil111/cli
|
|
10
|
-
Project-URL: Tracker, https://github.com/ozil111/cli
|
|
8
|
+
Project-URL: Documentation, https://github.com/ozil111/symtest-cli/blob/main/docs/user_manual.md
|
|
9
|
+
Project-URL: Source, https://github.com/ozil111/symtest-cli
|
|
10
|
+
Project-URL: Tracker, https://github.com/ozil111/symtest-cli/issues
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
12
|
Classifier: License :: OSI Approved :: MIT License
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
@@ -298,6 +298,9 @@ requirement for using the framework.
|
|
|
298
298
|
- [User manual](docs/user_manual_en.md)
|
|
299
299
|
- [Design document](docs/design_en.md)
|
|
300
300
|
- [Plugin examples](examples/plugins/README.md)
|
|
301
|
+
- [AI Skill template](examples/skill/) — import framework knowledge into AI coding
|
|
302
|
+
assistants so they can author test cases, acceptance criteria,
|
|
303
|
+
and TDD workflows directly
|
|
301
304
|
|
|
302
305
|
## Development
|
|
303
306
|
|
|
@@ -249,6 +249,9 @@ requirement for using the framework.
|
|
|
249
249
|
- [User manual](docs/user_manual_en.md)
|
|
250
250
|
- [Design document](docs/design_en.md)
|
|
251
251
|
- [Plugin examples](examples/plugins/README.md)
|
|
252
|
+
- [AI Skill template](examples/skill/) — import framework knowledge into AI coding
|
|
253
|
+
assistants so they can author test cases, acceptance criteria,
|
|
254
|
+
and TDD workflows directly
|
|
252
255
|
|
|
253
256
|
## Development
|
|
254
257
|
|
|
@@ -259,7 +259,7 @@ load_test_cases() → _apply_test_case_filter() → setup_manager.setup_all()
|
|
|
259
259
|
支持三种过滤方式(可组合):
|
|
260
260
|
- `test_case_filter`:按名称精确匹配
|
|
261
261
|
- `test_case_tag_filter`:按 tags 匹配(交集逻辑)
|
|
262
|
-
- `last_failed`:从 `.
|
|
262
|
+
- `last_failed`:从 `.symtest/last_run.json` 读取上次失败的用例名
|
|
263
263
|
|
|
264
264
|
**xfail 机制 `_apply_xfail_status()`**:
|
|
265
265
|
|
|
@@ -318,6 +318,8 @@ class TestCase:
|
|
|
318
318
|
expected_failure: bool = False
|
|
319
319
|
xfail_reason: str = ""
|
|
320
320
|
xfail_quiet: bool = False
|
|
321
|
+
depends_on: List[str] = field(default_factory=list)
|
|
322
|
+
env: Dict[str, str] = field(default_factory=dict)
|
|
321
323
|
```
|
|
322
324
|
|
|
323
325
|
两种模式:
|
|
@@ -328,6 +330,8 @@ class TestCase:
|
|
|
328
330
|
- `tags`:标签过滤
|
|
329
331
|
- `retry_count`:失败重试次数
|
|
330
332
|
- `expected_failure` / `xfail_reason` / `xfail_quiet`:预期失败标记
|
|
333
|
+
- `depends_on`:用例级依赖声明,支持 DAG 拓扑调度
|
|
334
|
+
- `env`:case 级环境变量,注入该 case(序列模式为所有 step)的子进程,优先级高于 `setup` 与调度器注入
|
|
331
335
|
|
|
332
336
|
### 4.3 Assertions
|
|
333
337
|
|
|
@@ -426,7 +430,7 @@ class PathResolver:
|
|
|
426
430
|
`--last-failed` 状态存储模块(`core/last_run_store.py`):
|
|
427
431
|
|
|
428
432
|
```python
|
|
429
|
-
# 存储位置: <workspace>/.
|
|
433
|
+
# 存储位置: <workspace>/.symtest/last_run.json
|
|
430
434
|
# {
|
|
431
435
|
# "case_name": {"status": "passed"},
|
|
432
436
|
# ...
|
|
@@ -448,8 +452,8 @@ class PathResolver:
|
|
|
448
452
|
`--resume` 断点续跑模块(`core/sequence_state.py`):
|
|
449
453
|
|
|
450
454
|
```python
|
|
451
|
-
# 状态文件: <workspace>/.
|
|
452
|
-
# 输出缓存: <workspace>/.
|
|
455
|
+
# 状态文件: <workspace>/.symtest/sequence_state/<case_name>.json
|
|
456
|
+
# 输出缓存: <workspace>/.symtest/sequence_state/cache/<case_name>.step<N>.log
|
|
453
457
|
```
|
|
454
458
|
|
|
455
459
|
核心接口:
|
|
@@ -684,7 +688,7 @@ CaseManagerApp (Textual App)
|
|
|
684
688
|
_update_history() # 回归检测 + 更新 .symtest
|
|
685
689
|
│
|
|
686
690
|
▼
|
|
687
|
-
_save_last_run() # 写入 .
|
|
691
|
+
_save_last_run() # 写入 .symtest/last_run.json
|
|
688
692
|
│
|
|
689
693
|
▼
|
|
690
694
|
setup_manager.teardown_all() # 逆序清理
|
|
@@ -699,14 +703,14 @@ CaseManagerApp (Textual App)
|
|
|
699
703
|
ParallelConfigRunner.run_tests()
|
|
700
704
|
│
|
|
701
705
|
▼
|
|
702
|
-
LPT 排序 (
|
|
706
|
+
拓扑 LPT 排序 (depends_on 约束 + 历史 avg_duration 降序)
|
|
703
707
|
│
|
|
704
708
|
▼
|
|
705
709
|
_assign_relative_cpu_cores() # 按权重比例分配 CPU 核心
|
|
706
710
|
│
|
|
707
711
|
▼
|
|
708
712
|
┌──────────────────────────────────────┐
|
|
709
|
-
│
|
|
713
|
+
│ DAG 调度 / 或直接并行 (无依赖时) │
|
|
710
714
|
│ AtomicSemaphore.acquire(cores) │
|
|
711
715
|
│ 注入 OMP/MKL/NPROC 环境变量 │
|
|
712
716
|
│ execute_single_test_case() │
|
|
@@ -715,7 +719,45 @@ ParallelConfigRunner.run_tests()
|
|
|
715
719
|
└──────────────────────────────────────┘
|
|
716
720
|
```
|
|
717
721
|
|
|
718
|
-
### 7.3
|
|
722
|
+
### 7.3 DAG 依赖调度流
|
|
723
|
+
|
|
724
|
+
当 `TestCase.depends_on` 非空时,并行 runner 自动切换为 DAG 拓扑调度:
|
|
725
|
+
|
|
726
|
+
```
|
|
727
|
+
ParallelRunner.run_tests()
|
|
728
|
+
│
|
|
729
|
+
▼
|
|
730
|
+
has_deps? ──No──► _run_tests_flat() (fast path)
|
|
731
|
+
│
|
|
732
|
+
Yes
|
|
733
|
+
▼
|
|
734
|
+
_run_dag()
|
|
735
|
+
│
|
|
736
|
+
├── 构建 dependents 邻接表 + in_degree 入度表
|
|
737
|
+
├── 入度=0 的用例 → 就绪队列 → executor.submit()
|
|
738
|
+
│
|
|
739
|
+
▼
|
|
740
|
+
┌────────────────────────────────────────┐
|
|
741
|
+
│ as_completed() 循环: │
|
|
742
|
+
│ 完成一个 future │
|
|
743
|
+
│ │ │
|
|
744
|
+
│ ├── passed/xfailed → 后继入度-1 │
|
|
745
|
+
│ │ └── 入度=0 → submit(后继) │
|
|
746
|
+
│ │ │
|
|
747
|
+
│ └── failed/xpassed → cascade_skip │
|
|
748
|
+
│ └── BFS 标记下游全部 skipped │
|
|
749
|
+
└────────────────────────────────────────┘
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
**调度语义**:
|
|
753
|
+
- 依赖"满足" = 状态为 `passed` 或 `xfailed`
|
|
754
|
+
- 依赖"不满足" = 状态为 `failed` 或 `xpassed` → 下游全部 skip
|
|
755
|
+
- `skipped` 不计入 `failed` 计数,报告中单独列出
|
|
756
|
+
- 级联 skip:若 B 被 skip,则依赖 B 的 C 也自动 skip
|
|
757
|
+
|
|
758
|
+
**顺序 runner**(`BaseRunner.run_tests()`)同样支持拓扑排序:`_topological_order()` 使用 Kahn 算法生成拓扑序列,按序执行,依赖失败时自动跳过下游。
|
|
759
|
+
|
|
760
|
+
### 7.4 文件比较流
|
|
719
761
|
|
|
720
762
|
```
|
|
721
763
|
symtest compare file1 file2 [options]
|
|
@@ -737,7 +779,7 @@ symtest compare file1 file2 [options]
|
|
|
737
779
|
format_result(result, --output-format) # text / json / html
|
|
738
780
|
```
|
|
739
781
|
|
|
740
|
-
### 7.
|
|
782
|
+
### 7.5 --resume 断点续跑流
|
|
741
783
|
|
|
742
784
|
```
|
|
743
785
|
序列测试用例执行
|
|
@@ -781,14 +823,16 @@ symtest compare file1 file2 [options]
|
|
|
781
823
|
| LPT 调度策略 | 长任务先启动,减少尾延迟;优先使用 `.symtest` 历史数据 |
|
|
782
824
|
| 累计平均更新历史 | 直觉简单,随运行次数增多单次异常自然稀释 |
|
|
783
825
|
| 回归检测在更新前执行 | 先与旧均值比较再更新,确保对比的是"历史基线" |
|
|
784
|
-
| `.symtest
|
|
826
|
+
| `.symtest/` 目录 | 不干扰用户目录视图,JSON 格式便于调试;状态文件统一管理 |
|
|
785
827
|
| 环境变量注入 | 科学计算求解器常忽略 Python 级线程控制 |
|
|
828
|
+
| case 级 env 通过 subprocess 注入 | 不改进程全局 `os.environ`,进程隔离、并行线程安全;优先级 `os.environ` < 调度器 < case env |
|
|
786
829
|
| Comparator 工厂 + 插件发现 | 按文件类型创建比较器,workspace `comparators/` 目录自动发现插件 |
|
|
787
830
|
| subprocess 隔离执行 | 每个 test case 独立子进程,保证测试间互不影响 |
|
|
788
831
|
| xfail 机制 | 支持预期失败的测试(CI 中不阻塞流水线),意外通过时告警 |
|
|
789
832
|
| --last-failed 覆写策略 | 只覆写本次执行的用例状态,避免子集运行时丢失未执行用例的状态 |
|
|
790
833
|
| --resume 纯信任模型 | 不验证 artifact,由用户保证 workspace 未被修改,简化实现 |
|
|
791
834
|
| retry_count 重试机制 | 应对偶发性网络抖动或竞态条件,首次失败后自动重试 |
|
|
835
|
+
| DAG 依赖调度 | 基于 Kahn 拓扑 + 就绪队列,依赖满足后立即提交;依赖失败级联 skip 下游;无依赖时走 fast path 零开销 |
|
|
792
836
|
| --update-baseline | 比较失败时自动将实际输出覆盖 baseline,适合批量更新基准 |
|
|
793
837
|
| next_action_hint 结构化建议 | 失败结果附带下一步操作建议(update_baseline / update_expected / increase_timeout / investigate),便于 AI 消费 |
|
|
794
838
|
| TUI 基于 Textual | 利用成熟的终端 UI 框架,提供交互式用例管理 |
|
|
@@ -259,7 +259,7 @@ load_test_cases() → _apply_test_case_filter() → setup_manager.setup_all()
|
|
|
259
259
|
Supports three filter modes (combinable):
|
|
260
260
|
- `test_case_filter`: exact name match
|
|
261
261
|
- `test_case_tag_filter`: tag-based match (intersection logic)
|
|
262
|
-
- `last_failed`: reads previously failed case names from `.
|
|
262
|
+
- `last_failed`: reads previously failed case names from `.symtest/last_run.json`
|
|
263
263
|
|
|
264
264
|
**xfail mechanism `_apply_xfail_status()`**:
|
|
265
265
|
|
|
@@ -318,6 +318,7 @@ class TestCase:
|
|
|
318
318
|
expected_failure: bool = False
|
|
319
319
|
xfail_reason: str = ""
|
|
320
320
|
xfail_quiet: bool = False
|
|
321
|
+
depends_on: List[str] = field(default_factory=list)
|
|
321
322
|
```
|
|
322
323
|
|
|
323
324
|
Two modes:
|
|
@@ -426,7 +427,7 @@ Core interfaces:
|
|
|
426
427
|
`--last-failed` state storage module (`core/last_run_store.py`):
|
|
427
428
|
|
|
428
429
|
```python
|
|
429
|
-
# Storage location: <workspace>/.
|
|
430
|
+
# Storage location: <workspace>/.symtest/last_run.json
|
|
430
431
|
# {
|
|
431
432
|
# "case_name": {"status": "passed"},
|
|
432
433
|
# ...
|
|
@@ -448,8 +449,8 @@ Each run **overwrites** the status of executed cases; unexecuted cases retain th
|
|
|
448
449
|
`--resume` step-level resume module (`core/sequence_state.py`):
|
|
449
450
|
|
|
450
451
|
```python
|
|
451
|
-
# State file: <workspace>/.
|
|
452
|
-
# Output cache: <workspace>/.
|
|
452
|
+
# State file: <workspace>/.symtest/sequence_state/<case_name>.json
|
|
453
|
+
# Output cache: <workspace>/.symtest/sequence_state/cache/<case_name>.step<N>.log
|
|
453
454
|
```
|
|
454
455
|
|
|
455
456
|
Core interfaces:
|
|
@@ -684,7 +685,7 @@ Config file (JSON/YAML)
|
|
|
684
685
|
_update_history() # Regression detection + update .symtest
|
|
685
686
|
│
|
|
686
687
|
▼
|
|
687
|
-
_save_last_run() # Write .
|
|
688
|
+
_save_last_run() # Write .symtest/last_run.json
|
|
688
689
|
│
|
|
689
690
|
▼
|
|
690
691
|
setup_manager.teardown_all() # Reverse cleanup
|
|
@@ -699,14 +700,14 @@ Config file (JSON/YAML)
|
|
|
699
700
|
ParallelConfigRunner.run_tests()
|
|
700
701
|
│
|
|
701
702
|
▼
|
|
702
|
-
LPT sort (historical avg_duration
|
|
703
|
+
Topology-constrained LPT sort (depends_on + historical avg_duration desc)
|
|
703
704
|
│
|
|
704
705
|
▼
|
|
705
706
|
_assign_relative_cpu_cores() # Proportional CPU core assignment by weight
|
|
706
707
|
│
|
|
707
708
|
▼
|
|
708
709
|
┌──────────────────────────────────────┐
|
|
709
|
-
│
|
|
710
|
+
│ DAG scheduling / flat (no deps) │
|
|
710
711
|
│ AtomicSemaphore.acquire(cores) │
|
|
711
712
|
│ Inject OMP/MKL/NPROC env vars │
|
|
712
713
|
│ execute_single_test_case() │
|
|
@@ -715,7 +716,47 @@ ParallelConfigRunner.run_tests()
|
|
|
715
716
|
└──────────────────────────────────────┘
|
|
716
717
|
```
|
|
717
718
|
|
|
718
|
-
### 7.3
|
|
719
|
+
### 7.3 DAG Dependency Scheduling Flow
|
|
720
|
+
|
|
721
|
+
When `TestCase.depends_on` is non-empty, the parallel runner switches to DAG topology scheduling:
|
|
722
|
+
|
|
723
|
+
```
|
|
724
|
+
ParallelRunner.run_tests()
|
|
725
|
+
│
|
|
726
|
+
▼
|
|
727
|
+
has_deps? ──No──► _run_tests_flat() (fast path)
|
|
728
|
+
│
|
|
729
|
+
Yes
|
|
730
|
+
▼
|
|
731
|
+
_run_dag()
|
|
732
|
+
│
|
|
733
|
+
├── Build dependents adjacency + in_degree table
|
|
734
|
+
├── in_degree=0 cases → ready queue → executor.submit()
|
|
735
|
+
│
|
|
736
|
+
▼
|
|
737
|
+
┌────────────────────────────────────────┐
|
|
738
|
+
│ as_completed() loop: │
|
|
739
|
+
│ Complete one future │
|
|
740
|
+
│ │ │
|
|
741
|
+
│ ├── passed/xfailed → decrement │
|
|
742
|
+
│ │ successor in-degree │
|
|
743
|
+
│ │ └── in_degree=0 → submit() │
|
|
744
|
+
│ │ │
|
|
745
|
+
│ └── failed/xpassed → cascade_skip │
|
|
746
|
+
│ └── BFS mark all downstream │
|
|
747
|
+
│ as skipped │
|
|
748
|
+
└────────────────────────────────────────┘
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
**Scheduling semantics**:
|
|
752
|
+
- Dependency "satisfied" = status is `passed` or `xfailed`
|
|
753
|
+
- Dependency "unsatisfied" = status is `failed` or `xpassed` → all downstream skipped
|
|
754
|
+
- `skipped` is NOT counted as `failed`; listed separately in reports
|
|
755
|
+
- Cascade skip: if B is skipped, C (which depends on B) is also skipped
|
|
756
|
+
|
|
757
|
+
**Sequential runner** (`BaseRunner.run_tests()`) also supports topological ordering: `_topological_order()` uses Kahn's algorithm to generate a topological sequence, runs in order, and auto-skips downstream on dependency failure.
|
|
758
|
+
|
|
759
|
+
### 7.4 File Comparison Flow
|
|
719
760
|
|
|
720
761
|
```
|
|
721
762
|
symtest compare file1 file2 [options]
|
|
@@ -737,7 +778,7 @@ symtest compare file1 file2 [options]
|
|
|
737
778
|
format_result(result, --output-format) # text / json / html
|
|
738
779
|
```
|
|
739
780
|
|
|
740
|
-
### 7.
|
|
781
|
+
### 7.5 --resume Checkpoint Flow
|
|
741
782
|
|
|
742
783
|
```
|
|
743
784
|
Sequence test case execution
|
|
@@ -781,7 +822,7 @@ Sequence test case execution
|
|
|
781
822
|
| LPT scheduling strategy | Long tasks start first, reducing tail latency; prioritizes `.symtest` historical data |
|
|
782
823
|
| Cumulative average history update | Simple and intuitive; single anomalies are naturally diluted over many runs |
|
|
783
824
|
| Regression check before update | Compare against old average first, then update; ensures comparison is against the "historical baseline" |
|
|
784
|
-
| `.symtest
|
|
825
|
+
| `.symtest/` directory | Non-intrusive to the user's directory view; JSON format for easy debugging; state files centrally managed |
|
|
785
826
|
| Environment variable injection | Scientific computing solvers often ignore Python-level thread control |
|
|
786
827
|
| Comparator factory + plugin discovery | Creates comparators by file type; workspace `comparators/` directory for auto-discovered plugins |
|
|
787
828
|
| subprocess isolated execution | Each test case runs in an independent subprocess, ensuring tests don't affect each other |
|
|
@@ -789,6 +830,7 @@ Sequence test case execution
|
|
|
789
830
|
| --last-failed overwrite strategy | Only overwrites status of executed cases; avoids losing state of unexecuted cases during subset runs |
|
|
790
831
|
| --resume pure trust model | No artifact validation; user guarantees workspace is unchanged, simplifying implementation |
|
|
791
832
|
| retry_count retry mechanism | Handles transient network glitches or race conditions; auto-retries on first failure |
|
|
833
|
+
| DAG dependency scheduling | Kahn topology + ready queue; submits dependents immediately once deps are satisfied; cascade-skips downstream on dep failure; zero-overhead fast path when no deps declared |
|
|
792
834
|
| --update-baseline | Automatically overwrites baseline files with actual output on comparison failure; ideal for batch baseline updates |
|
|
793
835
|
| next_action_hint structured suggestions | Failed results include actionable suggestions (update_baseline / update_expected / increase_timeout / investigate), convenient for AI consumption |
|
|
794
836
|
| TUI based on Textual | Leverages a mature terminal UI framework for interactive case management |
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
- [安装](#安装)
|
|
6
6
|
- [测试用例定义](#测试用例定义)
|
|
7
|
+
- [Case 级环境变量](#case-级环境变量env)
|
|
7
8
|
- [配置拆分机制](#配置拆分机制)
|
|
8
9
|
- [配置继承](#配置继承)
|
|
9
10
|
- [配置校验](#配置校验)
|
|
@@ -159,6 +160,78 @@ test_cases:
|
|
|
159
160
|
}
|
|
160
161
|
```
|
|
161
162
|
|
|
163
|
+
### 测试依赖(depends_on)
|
|
164
|
+
|
|
165
|
+
当测试用例之间存在先后依赖时(例如 D 需要 A、B、C 先生成数据),通过 `depends_on` 声明依赖关系,框架会自动按 DAG 拓扑顺序调度:
|
|
166
|
+
|
|
167
|
+
**并行模式**:A、B、C 并行执行,全部通过后 D 才被提交。依赖失败的用例会自动 skip 其下游(级联 skip)。
|
|
168
|
+
|
|
169
|
+
**顺序模式**:框架按拓扑序重排用例,保证依赖在前的先执行,依赖失败时同样跳过下游。
|
|
170
|
+
|
|
171
|
+
**JSON 示例**:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"test_cases": [
|
|
176
|
+
{ "name": "A", "command": "python", "args": ["gen_a.py"], "expected": {"return_code": 0} },
|
|
177
|
+
{ "name": "B", "command": "python", "args": ["gen_b.py"], "expected": {"return_code": 0} },
|
|
178
|
+
{ "name": "C", "command": "python", "args": ["gen_c.py"], "expected": {"return_code": 0} },
|
|
179
|
+
{
|
|
180
|
+
"name": "D", "command": "python", "args": ["merge.py"],
|
|
181
|
+
"depends_on": ["A", "B", "C"],
|
|
182
|
+
"expected": {"return_code": 0, "compare_files": [{"file": "output.h5", "type": "hdf5"}]}
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**YAML 示例**:
|
|
189
|
+
|
|
190
|
+
```yaml
|
|
191
|
+
test_cases:
|
|
192
|
+
- name: A
|
|
193
|
+
command: python
|
|
194
|
+
args: ["gen_a.py"]
|
|
195
|
+
expected: { return_code: 0 }
|
|
196
|
+
|
|
197
|
+
- name: B
|
|
198
|
+
command: python
|
|
199
|
+
args: ["gen_b.py"]
|
|
200
|
+
expected: { return_code: 0 }
|
|
201
|
+
|
|
202
|
+
- name: C
|
|
203
|
+
command: python
|
|
204
|
+
args: ["gen_c.py"]
|
|
205
|
+
expected: { return_code: 0 }
|
|
206
|
+
|
|
207
|
+
- name: D
|
|
208
|
+
command: python
|
|
209
|
+
args: ["merge.py"]
|
|
210
|
+
depends_on: [A, B, C]
|
|
211
|
+
expected:
|
|
212
|
+
return_code: 0
|
|
213
|
+
compare_files:
|
|
214
|
+
- file: output.h5
|
|
215
|
+
type: hdf5
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**调度语义**:
|
|
219
|
+
|
|
220
|
+
| 依赖状态 | 下游行为 |
|
|
221
|
+
|---|---|
|
|
222
|
+
| `passed` 或 `xfailed` | 依赖"满足",下游正常执行 |
|
|
223
|
+
| `failed` 或 `xpassed` | 依赖"不满足",下游标记为 `skipped`,并级联 skip |
|
|
224
|
+
| 存在循环依赖 | 配置校验阶段报错,禁止运行 |
|
|
225
|
+
|
|
226
|
+
`skipped` 不计入 `failed` 计数,在报告摘要中单独显示 `Skipped: N`。
|
|
227
|
+
|
|
228
|
+
**约束**:
|
|
229
|
+
- 依赖名称必须在同配置文件的 `test_cases` 中存在
|
|
230
|
+
- 不允许自依赖(`depends_on: ["self"]`)
|
|
231
|
+
- 不允许循环依赖(A → B → A)
|
|
232
|
+
- 与 `steps` 模式互不影响——`depends_on` 是用例级概念,`steps` 是用例内步骤级概念
|
|
233
|
+
- 无依赖时走 fast path,调度开销为零
|
|
234
|
+
|
|
162
235
|
### 字段说明
|
|
163
236
|
|
|
164
237
|
| 字段 | 必填 | 说明 |
|
|
@@ -174,11 +247,69 @@ test_cases:
|
|
|
174
247
|
| `expected_failure` | 否 | 标记为预期失败(xfail)。设为 `true` 时,失败计为 XFailed(不影响退出码),意外通过计为 XPassed(视作失败) |
|
|
175
248
|
| `xfail_reason` | 否 | xfail 的原因说明,报告中将展示此文本(如 "Bug #42 尚未修复") |
|
|
176
249
|
| `xfail_quiet` | 否 | 设为 `true` 时,xfailed 状态下报告中不输出 Command Output(stdout/stderr 大段输出),仅保留命令、返回码、失败原因等元信息 |
|
|
250
|
+
| `depends_on` | 否 | 依赖的测试用例名称列表(如 `["A", "B"]`)。当前用例必须等待所有依赖用例通过后才执行。依赖失败时自动 skip 当前用例及下游。支持并行和顺序两种 runner |
|
|
251
|
+
| `env` | 否 | case 级环境变量字典(如 `{"UEL_SYSID_SCALE": "1.0"}`),仅在执行该 case(序列模式为所有 step)时注入子进程,见 [Case 级环境变量](#case-级环境变量env) |
|
|
177
252
|
| `expected.return_code` | 否 | 期望返回码 |
|
|
178
253
|
| `expected.output_contains` | 否 | 输出需包含的字符串列表 |
|
|
179
254
|
| `expected.output_matches` | 否 | 输出需匹配的正则表达式(单个字符串) |
|
|
180
255
|
| `expected.compare_files` | 否 | 文件比较断言列表,见下文 |
|
|
181
256
|
|
|
257
|
+
## Case 级环境变量(env)
|
|
258
|
+
|
|
259
|
+
通过 case 下与 `name` 同级的 `env` 字段,可为单个用例注入环境变量,仅在该用例(序列模式为所有 step)的子进程内生效,不影响其他用例。
|
|
260
|
+
|
|
261
|
+
### JSON
|
|
262
|
+
|
|
263
|
+
```json
|
|
264
|
+
{
|
|
265
|
+
"name": "UEL 缩放测试",
|
|
266
|
+
"command": "solver",
|
|
267
|
+
"args": ["-i", "input.dat"],
|
|
268
|
+
"env": {
|
|
269
|
+
"UEL_SYSID_SCALE": "1.0",
|
|
270
|
+
"OMP_NUM_THREADS": "8"
|
|
271
|
+
},
|
|
272
|
+
"expected": { "return_code": 0 }
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### YAML
|
|
277
|
+
|
|
278
|
+
```yaml
|
|
279
|
+
- name: UEL 缩放测试
|
|
280
|
+
command: solver
|
|
281
|
+
args: ["-i", "input.dat"]
|
|
282
|
+
env:
|
|
283
|
+
UEL_SYSID_SCALE: "1.0"
|
|
284
|
+
expected: { return_code: 0 }
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### 序列模式
|
|
288
|
+
|
|
289
|
+
`env` 定义在 case 级(与 `steps` 同级),对该 case 的**所有 step** 生效:
|
|
290
|
+
|
|
291
|
+
```json
|
|
292
|
+
{
|
|
293
|
+
"name": "多步骤+环境变量",
|
|
294
|
+
"env": { "UEL_SYSID_SCALE": "1.0" },
|
|
295
|
+
"steps": [
|
|
296
|
+
{ "command": "python", "args": ["./step1.py"], "expected": { "return_code": 0 } },
|
|
297
|
+
{ "command": "python", "args": ["./step2.py"], "expected": { "return_code": 0 } }
|
|
298
|
+
]
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### 语义
|
|
303
|
+
|
|
304
|
+
| 决策点 | 行为 |
|
|
305
|
+
|---|---|
|
|
306
|
+
| 生效方式 | 通过子进程 `env` 注入,不修改进程全局 `os.environ`,天然进程隔离、线程安全 |
|
|
307
|
+
| 优先级 | `os.environ`(含 `setup.environment_variables`)< 调度器注入(`OMP/MKL/NPROC`)< **case `env`(最高)**,即 case env 可覆盖调度器的 `OMP_NUM_THREADS` |
|
|
308
|
+
| 作用范围 | 仅当前 case,不污染其他 case(区别于全局 `setup.environment_variables`) |
|
|
309
|
+
| 占位符 | 自动支持,`"env": {"SCALE": "{scale}"}` 会被 `variables`/`--var` 替换 |
|
|
310
|
+
| 继承(extends) | 自动支持,`env` 为 dict,深合并、子类覆盖父类同名 key |
|
|
311
|
+
| 值类型 | 字符串;数字/布尔在解析时自动 `str()` 化 |
|
|
312
|
+
|
|
182
313
|
### 文件比较断言(compare_files)
|
|
183
314
|
|
|
184
315
|
在 `expected` 中通过 `compare_files` 可声明一条或多条文件比较规则,框架会在命令执行后自动用对应的比较器对比实际产出文件与基线文件。所有比较通过才算用例通过,可与 `return_code`、`output_contains` 等断言共存。
|
|
@@ -702,7 +833,7 @@ symtest run test_cases.json --error-analysis
|
|
|
702
833
|
**xfail 语义**:标记为 `expected_failure` 的用例如果失败(`xfailed`),是预期行为,**不会**被 `--last-failed` 选中重跑。但如果 xfail 标记的用例意外通过(`xpassed`),则被视为真正失败,**会**被选中。
|
|
703
834
|
|
|
704
835
|
**工作原理**:
|
|
705
|
-
- 每次运行结束后,框架在 `<workspace>/.
|
|
836
|
+
- 每次运行结束后,框架在 `<workspace>/.symtest/last_run.json` 中记录每个用例的状态
|
|
706
837
|
- 记录采用**覆盖式更新**:本次跑到的用例用新结果覆盖旧结果,没跑到的保留原状态
|
|
707
838
|
- 这意味着修好的 case 在下一次显示中不再是"failed"
|
|
708
839
|
- 如果文件不存在(首次运行),`--last-failed` 会提示并正常运行全部用例
|
|
@@ -725,7 +856,7 @@ symtest run config.json
|
|
|
725
856
|
`--resume` 针对**顺序步骤测试(sequence)**,跳过上次运行中已通过的步骤,直接从失败步骤继续执行。适合耗时长的多步骤用例——例如有限元分析中 step 1-3 通过了(各耗时几十秒甚至分钟),只有 step 4 的断言失败,`--resume` 可以跳过 1-3、只重跑 step 4。
|
|
726
857
|
|
|
727
858
|
**工作原理**:
|
|
728
|
-
- 每个步骤通过后,框架在 `<workspace>/.
|
|
859
|
+
- 每个步骤通过后,框架在 `<workspace>/.symtest/sequence_state/<case_name>.json` 中记录步骤状态,并将输出缓存到 `cache/` 子目录
|
|
729
860
|
- 下次 `--resume` 时,计算配置哈希(所有步骤的 command/args/expected/timeout/retry_count 及 case 级 expected 的 SHA256)与已保存状态比对
|
|
730
861
|
- 哈希匹配 → 跳过已通过的步骤,从缓存重建 `combined_output`(确保 case 级 `expected` 断言能正常执行)
|
|
731
862
|
- 用例全部通过 → 自动删除状态文件和缓存,避免残留影响后续运行
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
- [Installation](#installation)
|
|
6
6
|
- [Test Case Definition](#test-case-definition)
|
|
7
|
+
- [Case-Level Environment Variables](#case-level-environment-variables-env)
|
|
7
8
|
- [Configuration Splitting](#configuration-splitting)
|
|
8
9
|
- [Configuration Inheritance](#configuration-inheritance)
|
|
9
10
|
- [Configuration Validation](#configuration-validation)
|
|
@@ -159,6 +160,78 @@ When xfailed case output is extremely verbose (e.g., hundreds of lines of solver
|
|
|
159
160
|
}
|
|
160
161
|
```
|
|
161
162
|
|
|
163
|
+
### Test Dependencies (depends_on)
|
|
164
|
+
|
|
165
|
+
When test cases have ordering dependencies (e.g., D requires A, B, and C to generate data first), declare them via `depends_on`. The framework automatically schedules execution in DAG topological order:
|
|
166
|
+
|
|
167
|
+
**Parallel mode**: A, B, and C run concurrently. D is submitted only after all three pass. If a dependency fails, its downstream cases are auto-skipped (cascade skip).
|
|
168
|
+
|
|
169
|
+
**Sequential mode**: The framework reorders cases topologically, ensuring dependencies run first. Downstream cases are skipped on dependency failure.
|
|
170
|
+
|
|
171
|
+
**JSON example**:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"test_cases": [
|
|
176
|
+
{ "name": "A", "command": "python", "args": ["gen_a.py"], "expected": {"return_code": 0} },
|
|
177
|
+
{ "name": "B", "command": "python", "args": ["gen_b.py"], "expected": {"return_code": 0} },
|
|
178
|
+
{ "name": "C", "command": "python", "args": ["gen_c.py"], "expected": {"return_code": 0} },
|
|
179
|
+
{
|
|
180
|
+
"name": "D", "command": "python", "args": ["merge.py"],
|
|
181
|
+
"depends_on": ["A", "B", "C"],
|
|
182
|
+
"expected": {"return_code": 0, "compare_files": [{"file": "output.h5", "type": "hdf5"}]}
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**YAML example**:
|
|
189
|
+
|
|
190
|
+
```yaml
|
|
191
|
+
test_cases:
|
|
192
|
+
- name: A
|
|
193
|
+
command: python
|
|
194
|
+
args: ["gen_a.py"]
|
|
195
|
+
expected: { return_code: 0 }
|
|
196
|
+
|
|
197
|
+
- name: B
|
|
198
|
+
command: python
|
|
199
|
+
args: ["gen_b.py"]
|
|
200
|
+
expected: { return_code: 0 }
|
|
201
|
+
|
|
202
|
+
- name: C
|
|
203
|
+
command: python
|
|
204
|
+
args: ["gen_c.py"]
|
|
205
|
+
expected: { return_code: 0 }
|
|
206
|
+
|
|
207
|
+
- name: D
|
|
208
|
+
command: python
|
|
209
|
+
args: ["merge.py"]
|
|
210
|
+
depends_on: [A, B, C]
|
|
211
|
+
expected:
|
|
212
|
+
return_code: 0
|
|
213
|
+
compare_files:
|
|
214
|
+
- file: output.h5
|
|
215
|
+
type: hdf5
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Scheduling semantics**:
|
|
219
|
+
|
|
220
|
+
| Dependency Status | Downstream Behavior |
|
|
221
|
+
|---|---|
|
|
222
|
+
| `passed` or `xfailed` | Dependency "satisfied", downstream runs normally |
|
|
223
|
+
| `failed` or `xpassed` | Dependency "unsatisfied", downstream marked `skipped` with cascade skip |
|
|
224
|
+
| Circular dependency | Configuration validation error, execution blocked |
|
|
225
|
+
|
|
226
|
+
`skipped` is NOT counted as `failed`; shown separately as `Skipped: N` in the report summary.
|
|
227
|
+
|
|
228
|
+
**Constraints**:
|
|
229
|
+
- Dependency names must exist in the same config file's `test_cases`
|
|
230
|
+
- Self-dependency is not allowed (`depends_on: ["self"]`)
|
|
231
|
+
- Circular dependencies are not allowed (A → B → A)
|
|
232
|
+
- `depends_on` and `steps` are independent—`depends_on` is a case-level concept, `steps` is an intra-case step-level concept
|
|
233
|
+
- Zero-overhead fast path when no dependencies are declared
|
|
234
|
+
|
|
162
235
|
### Field Descriptions
|
|
163
236
|
|
|
164
237
|
| Field | Required | Description |
|
|
@@ -174,6 +247,8 @@ When xfailed case output is extremely verbose (e.g., hundreds of lines of solver
|
|
|
174
247
|
| `expected_failure` | No | Mark as expected failure (xfail). When `true`, failure is counted as XFailed (no exit code impact); unexpected pass is counted as XPassed (treated as failure) |
|
|
175
248
|
| `xfail_reason` | No | Reason text for xfail, displayed in the report (e.g., "Bug #42 not yet fixed") |
|
|
176
249
|
| `xfail_quiet` | No | When `true`, suppress Command Output (stdout/stderr) for xfailed cases in the report; only command, return code, and failure reason metadata retained |
|
|
250
|
+
| `depends_on` | No | List of test case names this case depends on (e.g., `["A", "B"]`). The case will wait until all dependencies pass before executing. On dependency failure, the case and its downstream are auto-skipped. Works with both parallel and sequential runners |
|
|
251
|
+
| `env` | No | Case-level environment variable mapping (e.g. `{"UEL_SYSID_SCALE": "1.0"}`), injected into the subprocess only when this case runs (all steps in sequence mode). See [Case-Level Environment Variables](#case-level-environment-variables-env) |
|
|
177
252
|
| `expected.return_code` | No | Expected return code |
|
|
178
253
|
| `expected.output_contains` | No | List of strings the output must contain |
|
|
179
254
|
| `expected.output_matches` | No | Regex pattern the output must match (single string) |
|
|
@@ -216,6 +291,62 @@ Fields for each comparison rule:
|
|
|
216
291
|
}
|
|
217
292
|
```
|
|
218
293
|
|
|
294
|
+
## Case-Level Environment Variables (env)
|
|
295
|
+
|
|
296
|
+
Use the `env` field (same level as `name`) to inject environment variables into a single case's subprocess. The variables apply only to that case (all steps in sequence mode) and do not affect other cases.
|
|
297
|
+
|
|
298
|
+
### JSON
|
|
299
|
+
|
|
300
|
+
```json
|
|
301
|
+
{
|
|
302
|
+
"name": "UEL scale test",
|
|
303
|
+
"command": "solver",
|
|
304
|
+
"args": ["-i", "input.dat"],
|
|
305
|
+
"env": {
|
|
306
|
+
"UEL_SYSID_SCALE": "1.0",
|
|
307
|
+
"OMP_NUM_THREADS": "8"
|
|
308
|
+
},
|
|
309
|
+
"expected": { "return_code": 0 }
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### YAML
|
|
314
|
+
|
|
315
|
+
```yaml
|
|
316
|
+
- name: UEL scale test
|
|
317
|
+
command: solver
|
|
318
|
+
args: ["-i", "input.dat"]
|
|
319
|
+
env:
|
|
320
|
+
UEL_SYSID_SCALE: "1.0"
|
|
321
|
+
expected: { return_code: 0 }
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Sequence Mode
|
|
325
|
+
|
|
326
|
+
`env` is defined at the case level (same level as `steps`) and applies to **all steps** of that case:
|
|
327
|
+
|
|
328
|
+
```json
|
|
329
|
+
{
|
|
330
|
+
"name": "multi-step with env",
|
|
331
|
+
"env": { "UEL_SYSID_SCALE": "1.0" },
|
|
332
|
+
"steps": [
|
|
333
|
+
{ "command": "python", "args": ["./step1.py"], "expected": { "return_code": 0 } },
|
|
334
|
+
{ "command": "python", "args": ["./step2.py"], "expected": { "return_code": 0 } }
|
|
335
|
+
]
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Semantics
|
|
340
|
+
|
|
341
|
+
| Aspect | Behavior |
|
|
342
|
+
|---|---|
|
|
343
|
+
| Injection mechanism | Injected via subprocess `env`, never mutates the global `os.environ`; process-isolated and thread-safe |
|
|
344
|
+
| Precedence | `os.environ` (incl. `setup.environment_variables`) < scheduler-injected (`OMP/MKL/NPROC`) < **case `env` (highest)** — case env can override `OMP_NUM_THREADS` |
|
|
345
|
+
| Scope | Current case only, no cross-case pollution (unlike global `setup.environment_variables`) |
|
|
346
|
+
| Placeholders | Auto-supported; `"env": {"SCALE": "{scale}"}` is substituted via `variables`/`--var` |
|
|
347
|
+
| Inheritance (extends) | Auto-supported; `env` is a dict, deep-merged with child keys overriding parent |
|
|
348
|
+
| Value type | Strings; numeric/boolean values are coerced with `str()` at parse time |
|
|
349
|
+
|
|
219
350
|
## Configuration Splitting
|
|
220
351
|
|
|
221
352
|
When a test project grows to dozens or even hundreds of test cases, a single config file becomes hard to maintain. The configuration splitting mechanism lets you break a large file into multiple sub-files by module/feature and assemble them via `import` references, which are merged at load time automatically.
|
|
@@ -702,7 +833,7 @@ symtest run test_cases.json --error-analysis
|
|
|
702
833
|
**xfail semantics**: Cases marked `expected_failure` that fail (`xfailed`) are _expected behavior_ and are **not** selected by `--last-failed` for rerun. However, if an xfail-marked case unexpectedly passes (`xpassed`), it is treated as a true failure and **is** selected.
|
|
703
834
|
|
|
704
835
|
**How it works**:
|
|
705
|
-
- After each run, the framework records each case's status in `<workspace>/.
|
|
836
|
+
- After each run, the framework records each case's status in `<workspace>/.symtest/last_run.json`
|
|
706
837
|
- Recording uses **overwrite-update**: cases run this time get new results overwriting old ones; un-run cases retain their previous status
|
|
707
838
|
- This means a fixed case won't show as "failed" in the next display
|
|
708
839
|
- If the file doesn't exist (first run), `--last-failed` warns and runs all cases normally
|
|
@@ -725,7 +856,7 @@ symtest run config.json
|
|
|
725
856
|
`--resume` is for **sequential step tests (sequence)**. It skips steps that passed in the previous run and continues directly from the failed step. Ideal for long-running multi-step cases — for example, in an FEM analysis where steps 1-3 passed (each taking tens of seconds or minutes), only step 4's assertion failed. `--resume` skips 1-3 and reruns only step 4.
|
|
726
857
|
|
|
727
858
|
**How it works**:
|
|
728
|
-
- After each step passes, the framework records step status in `<workspace>/.
|
|
859
|
+
- After each step passes, the framework records step status in `<workspace>/.symtest/sequence_state/<case_name>.json` and caches output to the `cache/` subdirectory
|
|
729
860
|
- On the next `--resume`, a config hash (SHA256 of every step's command/args/expected/timeout/retry_count plus case-level expected) is computed and compared against saved state
|
|
730
861
|
- Hash match → skip passed steps, rebuild `combined_output` from cache (so case-level `expected` assertions run correctly)
|
|
731
862
|
- All steps pass → state file and cache automatically deleted to avoid stale data affecting subsequent runs
|