cli-test-framework 1.0.1__tar.gz → 1.0.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.
- {cli_test_framework-1.0.1/src/cli_test_framework.egg-info → cli_test_framework-1.0.2}/PKG-INFO +1 -1
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/docs/user_manual.md +6 -2
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/setup.py +1 -1
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/base_runner.py +4 -1
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/config_loader.py +5 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/execution.py +49 -9
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/parallel_runner.py +2 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/process_worker.py +1 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/test_case.py +5 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/types.py +1 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/tui/screens/case_editor.py +8 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/tui/widgets/steps_editor.py +11 -1
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2/src/cli_test_framework.egg-info}/PKG-INFO +1 -1
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework.egg-info/SOURCES.txt +1 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/test_sequence.py +7 -2
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/__pycache__/test_binary_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/__pycache__/test_cli.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/__pycache__/test_config_io.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/__pycache__/test_result.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.2/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.2/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.2/tests/unit/core/__pycache__/test_execution.cpython-312.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/test_config_loader.py +87 -2
- cli_test_framework-1.0.2/tests/unit/core/test_execution.py +241 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/test_process_worker.py +37 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.2/tests/unit/tui/__pycache__/__init__.cpython-312.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/__pycache__/test_tui_run_test.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/test_widgets_data.py +14 -1
- cli_test_framework-1.0.1/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.1/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.1/tests/unit/core/test_execution.py +0 -70
- cli_test_framework-1.0.1/tests/unit/tui/__pycache__/__init__.cpython-312.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/MANIFEST.in +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/README.md +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/docs/design.md +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/docs/design_en.md +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/docs/tui_and_config_split_design.md +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/docs/user_manual_en.md +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/pyproject.toml +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/setup.cfg +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/cli.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/commands/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/commands/compare.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/config/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/config/config_io.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/config/import_expander.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/assertions.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/history_store.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/setup.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/file_comparator/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/file_comparator/base_comparator.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/file_comparator/binary_comparator.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/file_comparator/csv_comparator.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/file_comparator/factory.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/file_comparator/h5_comparator.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/file_comparator/json_comparator.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/file_comparator/result.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/file_comparator/text_comparator.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/file_comparator/xml_comparator.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/logging_config.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/runners/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/runners/config_runner.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/runners/json_runner.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/runners/parallel_config_runner.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/runners/parallel_json_runner.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/runners/parallel_yaml_runner.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/runners/yaml_runner.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/tui/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/tui/app.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/tui/controllers/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/tui/controllers/case_controller.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/tui/screens/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/tui/screens/case_list.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/tui/widgets/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/tui/widgets/case_table.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/tui/widgets/expected_editor.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/tui/widgets/search_bar.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/utils/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/utils/junit_xml_writer.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/utils/path_resolver.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/utils/report_generator.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework.egg-info/dependency_links.txt +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework.egg-info/entry_points.txt +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework.egg-info/requires.txt +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework.egg-info/top_level.txt +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/README.md +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/__pycache__/__init__.cpython-312.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/__pycache__/__init__.cpython-39.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/__pycache__/conftest.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/__pycache__/run_all.cpython-312.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/__pycache__/run_all.cpython-39.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/__pycache__/test_setup_module.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/conftest.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/demos/h5_filter_demo.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/demos/manual_report_example.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/demos/perf_parallel.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/e2e/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/e2e/__pycache__/__init__.cpython-312.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/e2e/__pycache__/__init__.cpython-39.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/e2e/__pycache__/test_user_flows.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/e2e/test_user_flows.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/fixtures/circular_config_a.json +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/fixtures/circular_config_b.json +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/fixtures/main_config.json +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/fixtures/missing_fields.json +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/fixtures/setup_main.json +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/fixtures/setup_sub.json +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/fixtures/sub_json_tests.yaml +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/fixtures/sub_text_tests.json +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/fixtures/test_cases.json +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/fixtures/test_cases.yaml +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/fixtures/test_cases1.json +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/fixtures/test_with_setup.json +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/fixtures/test_with_setup.yaml +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/test_binary_compare.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/test_csv_compare.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/test_h5_compare.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/test_json_compare.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/test_text_compare.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/file_compare/test_xml_compare.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/parallel/test_parallel_runner.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/path_handling/test_spaces_in_paths.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/test_history_feature.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/integration/test_real_command_execution.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/run_all.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/test_report.txt +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/__pycache__/test_cli.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/commands/test_compare_command.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/__pycache__/test_setup.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/test_assertions.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/test_history_store.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/core/test_setup.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/runners/test_json_yaml_runner.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/runners/test_test_case_filter.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/runners/test_test_case_tag_filter.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/test_binary_comparator.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/test_cli.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/test_config_io.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/test_h5_comparator.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/test_import_expander.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/test_result.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/test_run_all.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/__init__.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/conftest.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/test_app.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/test_case_controller.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/test_search_functions.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/tui/test_tui_run_test.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/utils/test_junit_xml_writer.py +0 -0
- {cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/tests/unit/utils/test_report_generator.py +0 -0
{cli_test_framework-1.0.1/src/cli_test_framework.egg-info → cli_test_framework-1.0.2}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cli-test-framework
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: A powerful command line testing framework in Python with setup modules, parallel execution, and file comparison capabilities.
|
|
5
5
|
Home-page: https://github.com/ozil111/cli-test-framework
|
|
6
6
|
Author: Xiaotong Wang
|
|
@@ -49,6 +49,7 @@ HDF5 文件比较依赖 `h5py`(已随框架安装)。如需在无 HDF5 环
|
|
|
49
49
|
"command": "echo",
|
|
50
50
|
"args": ["Hello"],
|
|
51
51
|
"timeout": 60,
|
|
52
|
+
"retry_count": 0,
|
|
52
53
|
"resources": {
|
|
53
54
|
"cpu_cores": 2,
|
|
54
55
|
"estimated_time": 300,
|
|
@@ -80,6 +81,7 @@ test_cases:
|
|
|
80
81
|
command: echo
|
|
81
82
|
args: ["Hello"]
|
|
82
83
|
timeout: 60
|
|
84
|
+
retry_count: 0
|
|
83
85
|
resources:
|
|
84
86
|
cpu_cores: 2
|
|
85
87
|
estimated_time: 300
|
|
@@ -105,6 +107,7 @@ test_cases:
|
|
|
105
107
|
| `args` | 否 | 命令参数列表 |
|
|
106
108
|
| `description` | 否 | 测试用例描述 |
|
|
107
109
|
| `timeout` | 否 | 超时秒数,默认 3600,设 `null` 无限制 |
|
|
110
|
+
| `retry_count` | 否 | 失败自动重试次数,默认 0(不重试)。单命令模式作用于整个 case,步骤模式可作用于每个 step |
|
|
108
111
|
| `tags` | 否 | 标签列表,用于批量过滤(如 `["smoke", "fast"]`) |
|
|
109
112
|
| `resources` | 否 | 资源配置,见[资源感知调度](#资源感知调度) |
|
|
110
113
|
| `expected.return_code` | 否 | 期望返回码 |
|
|
@@ -801,7 +804,8 @@ runner.run_tests_sequential()
|
|
|
801
804
|
{
|
|
802
805
|
"command": "echo",
|
|
803
806
|
"args": ["step2"],
|
|
804
|
-
"expected": { "return_code": 0 }
|
|
807
|
+
"expected": { "return_code": 0 },
|
|
808
|
+
"retry_count": 2
|
|
805
809
|
}
|
|
806
810
|
]
|
|
807
811
|
}
|
|
@@ -825,7 +829,7 @@ test_cases:
|
|
|
825
829
|
return_code: 0
|
|
826
830
|
```
|
|
827
831
|
|
|
828
|
-
每个 step 支持 `command`、`args`、`expected`、`timeout` 字段。失败时结果会标注失败步骤编号,如 "Failed at step 2/3"。
|
|
832
|
+
每个 step 支持 `command`、`args`、`expected`、`timeout`、`retry_count` 字段。失败时结果会标注失败步骤编号,如 "Failed at step 2/3"。
|
|
829
833
|
|
|
830
834
|
## 资源感知调度
|
|
831
835
|
|
|
@@ -8,7 +8,7 @@ with open(os.path.join(this_directory, 'README.md'), encoding='utf-8') as f:
|
|
|
8
8
|
|
|
9
9
|
setup(
|
|
10
10
|
name="cli-test-framework",
|
|
11
|
-
version="1.0.
|
|
11
|
+
version="1.0.2",
|
|
12
12
|
author="Xiaotong Wang",
|
|
13
13
|
author_email="xiaotongwang98@gmail.com",
|
|
14
14
|
description="A powerful command line testing framework in Python with setup modules, parallel execution, and file comparison capabilities.",
|
{cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/base_runner.py
RENAMED
|
@@ -129,11 +129,14 @@ class BaseRunner(ABC):
|
|
|
129
129
|
self.setup_manager.teardown_all()
|
|
130
130
|
|
|
131
131
|
def _update_history(self) -> None:
|
|
132
|
-
"""Update .symtest history with
|
|
132
|
+
"""Update .symtest history with successful run results and check for regressions."""
|
|
133
133
|
if not self.history_dir:
|
|
134
134
|
return
|
|
135
135
|
history = load_history(self.history_dir)
|
|
136
136
|
for result in self.results["details"]:
|
|
137
|
+
# Only record successful cases in history; skip failed ones
|
|
138
|
+
if result["status"] != "passed":
|
|
139
|
+
continue
|
|
137
140
|
duration = result.get("duration", 0)
|
|
138
141
|
# Check regression BEFORE updating (compare against old avg)
|
|
139
142
|
warning = check_regression(history, result["name"], duration, self.regression_threshold)
|
{cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/config_loader.py
RENAMED
|
@@ -115,6 +115,7 @@ def parse_test_cases(
|
|
|
115
115
|
args=resolved_args,
|
|
116
116
|
expected=step["expected"],
|
|
117
117
|
timeout=step.get("timeout"),
|
|
118
|
+
retry_count=step.get("retry_count", 0),
|
|
118
119
|
))
|
|
119
120
|
else:
|
|
120
121
|
steps.append(TestCaseStep(
|
|
@@ -122,6 +123,7 @@ def parse_test_cases(
|
|
|
122
123
|
args=step.get("args", []),
|
|
123
124
|
expected=step.get("expected", {}),
|
|
124
125
|
timeout=step.get("timeout"),
|
|
126
|
+
retry_count=step.get("retry_count", 0),
|
|
125
127
|
))
|
|
126
128
|
cases.append(TestCase(
|
|
127
129
|
name=case.get("name", ""),
|
|
@@ -151,6 +153,7 @@ def parse_test_cases(
|
|
|
151
153
|
timeout=case.get("timeout"),
|
|
152
154
|
resources=case.get("resources"),
|
|
153
155
|
tags=case.get("tags", []),
|
|
156
|
+
retry_count=case.get("retry_count", 0),
|
|
154
157
|
))
|
|
155
158
|
else:
|
|
156
159
|
cases.append(TestCase(
|
|
@@ -162,6 +165,7 @@ def parse_test_cases(
|
|
|
162
165
|
timeout=case.get("timeout"),
|
|
163
166
|
resources=case.get("resources"),
|
|
164
167
|
tags=case.get("tags", []),
|
|
168
|
+
retry_count=case.get("retry_count", 0),
|
|
165
169
|
))
|
|
166
170
|
|
|
167
171
|
return cases
|
|
@@ -236,6 +240,7 @@ def execute_sequence(
|
|
|
236
240
|
"description": None,
|
|
237
241
|
"timeout": _step_attr(step, "timeout"),
|
|
238
242
|
"resources": None,
|
|
243
|
+
"retry_count": _step_attr(step, "retry_count", 0),
|
|
239
244
|
}
|
|
240
245
|
|
|
241
246
|
command_preview = (
|
{cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/execution.py
RENAMED
|
@@ -3,11 +3,14 @@ import signal
|
|
|
3
3
|
import time
|
|
4
4
|
import os
|
|
5
5
|
import shlex
|
|
6
|
+
import logging
|
|
6
7
|
from typing import Any, List, Optional, Dict
|
|
7
8
|
|
|
8
9
|
from .assertions import Assertions
|
|
9
10
|
from .types import ExpectedResult, TestCaseData, TestResultData
|
|
10
11
|
|
|
12
|
+
logger = logging.getLogger("cli_test_framework.core.execution")
|
|
13
|
+
|
|
11
14
|
# Commands that are shell builtins (not real executables).
|
|
12
15
|
# With shell=False, these must be wrapped via the platform shell.
|
|
13
16
|
if os.name == 'nt':
|
|
@@ -80,15 +83,12 @@ def _dispatch_file_compare(
|
|
|
80
83
|
)
|
|
81
84
|
|
|
82
85
|
|
|
83
|
-
def
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
workspace: Working directory for test execution
|
|
90
|
-
env: Optional environment variables to inject/override (merged with os.environ)
|
|
91
|
-
"""
|
|
86
|
+
def _execute_command_once(
|
|
87
|
+
case: TestCaseData,
|
|
88
|
+
workspace: Optional[str] = None,
|
|
89
|
+
env: Optional[Dict[str, str]] = None,
|
|
90
|
+
) -> TestResultData:
|
|
91
|
+
"""Execute a single command once (no retry logic)."""
|
|
92
92
|
start_time = time.time()
|
|
93
93
|
cmd_list = _normalize_cmd_list(case["command"], [str(arg) for arg in case["args"]])
|
|
94
94
|
timeout_limit = case.get("timeout", 3600)
|
|
@@ -157,3 +157,43 @@ def execute_single_test_case(case: TestCaseData, workspace: Optional[str] = None
|
|
|
157
157
|
|
|
158
158
|
return result
|
|
159
159
|
|
|
160
|
+
|
|
161
|
+
def execute_single_test_case(
|
|
162
|
+
case: TestCaseData,
|
|
163
|
+
workspace: Optional[str] = None,
|
|
164
|
+
env: Optional[Dict[str, str]] = None,
|
|
165
|
+
) -> TestResultData:
|
|
166
|
+
"""
|
|
167
|
+
Stateless execution of a single test case with optional retry.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
case: Test case data (may include ``retry_count`` for automatic retries).
|
|
171
|
+
workspace: Working directory for test execution.
|
|
172
|
+
env: Optional environment variables to inject/override (merged with os.environ).
|
|
173
|
+
|
|
174
|
+
``retry_count`` (defaults to 0) controls how many additional times the
|
|
175
|
+
command is re-run after the first failure. ``retry_count=0`` means no
|
|
176
|
+
retry (behaviour identical to previous versions).
|
|
177
|
+
"""
|
|
178
|
+
retry_count: int = case.get("retry_count", 0)
|
|
179
|
+
max_attempts = retry_count + 1
|
|
180
|
+
total_duration = 0.0
|
|
181
|
+
last_result: Optional[TestResultData] = None
|
|
182
|
+
|
|
183
|
+
for attempt in range(1, max_attempts + 1):
|
|
184
|
+
result = _execute_command_once(case, workspace, env)
|
|
185
|
+
total_duration += result["duration"]
|
|
186
|
+
last_result = result
|
|
187
|
+
|
|
188
|
+
if result["status"] == "passed":
|
|
189
|
+
break
|
|
190
|
+
|
|
191
|
+
if attempt < max_attempts:
|
|
192
|
+
logger.info(
|
|
193
|
+
"Retrying '%s' (attempt %d/%d)...",
|
|
194
|
+
case["name"], attempt + 1, max_attempts,
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
last_result["duration"] = total_duration
|
|
198
|
+
return last_result
|
|
199
|
+
|
{cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/parallel_runner.py
RENAMED
|
@@ -138,12 +138,14 @@ class ParallelRunner(BaseRunner):
|
|
|
138
138
|
"expected": case.expected,
|
|
139
139
|
"timeout": case.timeout,
|
|
140
140
|
"resources": case.resources,
|
|
141
|
+
"retry_count": case.retry_count,
|
|
141
142
|
"steps": [
|
|
142
143
|
{
|
|
143
144
|
"command": s.command,
|
|
144
145
|
"args": s.args,
|
|
145
146
|
"expected": s.expected,
|
|
146
147
|
"timeout": s.timeout,
|
|
148
|
+
"retry_count": s.retry_count,
|
|
147
149
|
}
|
|
148
150
|
for s in case.steps
|
|
149
151
|
] if case.steps else None,
|
{cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/process_worker.py
RENAMED
|
@@ -46,6 +46,7 @@ def run_test_in_process(test_index: int, case_data: Dict[str, Any], workspace: s
|
|
|
46
46
|
"description": case_data.get("description"),
|
|
47
47
|
"timeout": case_data.get("timeout"),
|
|
48
48
|
"resources": case_data.get("resources"),
|
|
49
|
+
"retry_count": case_data.get("retry_count", 0),
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
command_preview = f"{case['command']} {' '.join(case['args'])}".strip()
|
{cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework/core/test_case.py
RENAMED
|
@@ -9,6 +9,7 @@ class TestCaseStep:
|
|
|
9
9
|
args: List[str]
|
|
10
10
|
expected: Dict[str, Any]
|
|
11
11
|
timeout: Optional[float] = None
|
|
12
|
+
retry_count: int = 0
|
|
12
13
|
|
|
13
14
|
@dataclass
|
|
14
15
|
class TestCase:
|
|
@@ -22,6 +23,7 @@ class TestCase:
|
|
|
22
23
|
resources: Optional[Dict[str, Any]] = None
|
|
23
24
|
steps: Optional[List[TestCaseStep]] = None
|
|
24
25
|
tags: List[str] = field(default_factory=list)
|
|
26
|
+
retry_count: int = 0
|
|
25
27
|
|
|
26
28
|
def to_dict(self) -> Dict[str, Any]:
|
|
27
29
|
"""Convert test case to dictionary format"""
|
|
@@ -33,6 +35,7 @@ class TestCase:
|
|
|
33
35
|
"timeout": self.timeout,
|
|
34
36
|
"resources": self.resources,
|
|
35
37
|
"tags": self.tags,
|
|
38
|
+
"retry_count": self.retry_count,
|
|
36
39
|
}
|
|
37
40
|
if self.steps is not None:
|
|
38
41
|
result["steps"] = [
|
|
@@ -41,6 +44,7 @@ class TestCase:
|
|
|
41
44
|
"args": s.args,
|
|
42
45
|
"expected": s.expected,
|
|
43
46
|
"timeout": s.timeout,
|
|
47
|
+
"retry_count": s.retry_count,
|
|
44
48
|
}
|
|
45
49
|
for s in self.steps
|
|
46
50
|
]
|
|
@@ -60,4 +64,5 @@ class TestCase:
|
|
|
60
64
|
"description": self.description or None,
|
|
61
65
|
"timeout": self.timeout,
|
|
62
66
|
"resources": self.resources,
|
|
67
|
+
"retry_count": self.retry_count,
|
|
63
68
|
}
|
|
@@ -90,6 +90,8 @@ class CaseEditorScreen(Screen):
|
|
|
90
90
|
TextArea("", id="case-description"),
|
|
91
91
|
Label("Timeout (seconds):", id="timeout-label"),
|
|
92
92
|
Input(placeholder="", id="case-timeout"),
|
|
93
|
+
Label("Retry count:", id="retry-label"),
|
|
94
|
+
Input(placeholder="0", id="case-retry-count"),
|
|
93
95
|
ExpectedEditor(id="expected-editor"),
|
|
94
96
|
StepsEditor(id="steps-editor"),
|
|
95
97
|
id="editor-fields",
|
|
@@ -127,6 +129,7 @@ class CaseEditorScreen(Screen):
|
|
|
127
129
|
self.query_one("#case-tags", Input).value = ",".join(tc.tags) if tc.tags else ""
|
|
128
130
|
self.query_one("#case-description", TextArea).text = tc.description or ""
|
|
129
131
|
self.query_one("#case-timeout", Input).value = str(tc.timeout) if tc.timeout else ""
|
|
132
|
+
self.query_one("#case-retry-count", Input).value = str(tc.retry_count) if tc.retry_count else ""
|
|
130
133
|
|
|
131
134
|
self.query_one("#expected-editor", ExpectedEditor).load(tc.expected or {})
|
|
132
135
|
|
|
@@ -147,6 +150,9 @@ class CaseEditorScreen(Screen):
|
|
|
147
150
|
timeout_text = self.query_one("#case-timeout", Input).value.strip()
|
|
148
151
|
timeout = float(timeout_text) if timeout_text else None
|
|
149
152
|
|
|
153
|
+
retry_text = self.query_one("#case-retry-count", Input).value.strip()
|
|
154
|
+
retry_count = int(retry_text) if retry_text else 0
|
|
155
|
+
|
|
150
156
|
description = self.query_one("#case-description", TextArea).text.strip()
|
|
151
157
|
|
|
152
158
|
if self._is_sequence:
|
|
@@ -157,6 +163,7 @@ class CaseEditorScreen(Screen):
|
|
|
157
163
|
description=description or "",
|
|
158
164
|
resources=self._case.resources if self._case else None,
|
|
159
165
|
tags=tags,
|
|
166
|
+
retry_count=retry_count,
|
|
160
167
|
)
|
|
161
168
|
else:
|
|
162
169
|
command = self.query_one("#case-command", Input).value.strip()
|
|
@@ -173,6 +180,7 @@ class CaseEditorScreen(Screen):
|
|
|
173
180
|
timeout=timeout,
|
|
174
181
|
resources=self._case.resources if self._case else None,
|
|
175
182
|
tags=tags,
|
|
183
|
+
retry_count=retry_count,
|
|
176
184
|
)
|
|
177
185
|
|
|
178
186
|
def _update_mode_visibility(self) -> None:
|
|
@@ -74,6 +74,8 @@ class StepsEditor(Vertical):
|
|
|
74
74
|
yield TextArea('{"return_code": 0}', id="step-expected")
|
|
75
75
|
yield Static("Timeout (seconds):", classes="label")
|
|
76
76
|
yield Input(placeholder="", id="step-timeout")
|
|
77
|
+
yield Static("Retry count:", classes="label")
|
|
78
|
+
yield Input(placeholder="0", id="step-retry-count")
|
|
77
79
|
yield Horizontal(
|
|
78
80
|
Button("Save Step", id="step-save", variant="primary"),
|
|
79
81
|
Button("Cancel", id="step-cancel"),
|
|
@@ -114,6 +116,7 @@ class StepsEditor(Vertical):
|
|
|
114
116
|
if len(exp_preview) > 40:
|
|
115
117
|
exp_preview = exp_preview[:37] + "..."
|
|
116
118
|
timeout_str = f", timeout={step.timeout}s" if step.timeout else ""
|
|
119
|
+
retry_str = f", retry={step.retry_count}" if step.retry_count else ""
|
|
117
120
|
|
|
118
121
|
row = Horizontal(
|
|
119
122
|
Static(f"[Step {i+1}/{len(self._steps)}]"),
|
|
@@ -136,6 +139,7 @@ class StepsEditor(Vertical):
|
|
|
136
139
|
self.query_one("#step-args", Input).value = ""
|
|
137
140
|
self.query_one("#step-expected", TextArea).text = '{"return_code": 0}'
|
|
138
141
|
self.query_one("#step-timeout", Input).value = ""
|
|
142
|
+
self.query_one("#step-retry-count", Input).value = ""
|
|
139
143
|
status = self.query_one("#step-editor-status", Static)
|
|
140
144
|
status.update("")
|
|
141
145
|
|
|
@@ -148,6 +152,7 @@ class StepsEditor(Vertical):
|
|
|
148
152
|
step.expected, ensure_ascii=False
|
|
149
153
|
)
|
|
150
154
|
self.query_one("#step-timeout", Input).value = str(step.timeout) if step.timeout else ""
|
|
155
|
+
self.query_one("#step-retry-count", Input).value = str(step.retry_count) if step.retry_count else ""
|
|
151
156
|
status = self.query_one("#step-editor-status", Static)
|
|
152
157
|
status.update(f"Editing Step {idx+1}")
|
|
153
158
|
|
|
@@ -169,7 +174,12 @@ class StepsEditor(Vertical):
|
|
|
169
174
|
timeout_text = self.query_one("#step-timeout", Input).value.strip()
|
|
170
175
|
timeout = float(timeout_text) if timeout_text else None
|
|
171
176
|
|
|
172
|
-
|
|
177
|
+
retry_text = self.query_one("#step-retry-count", Input).value.strip()
|
|
178
|
+
retry_count = int(retry_text) if retry_text else 0
|
|
179
|
+
|
|
180
|
+
new_step = TestCaseStep(
|
|
181
|
+
command=cmd, args=args, expected=expected, timeout=timeout, retry_count=retry_count,
|
|
182
|
+
)
|
|
173
183
|
|
|
174
184
|
if self._editing_idx >= 0:
|
|
175
185
|
self._steps[self._editing_idx] = new_step
|
{cli_test_framework-1.0.1 → cli_test_framework-1.0.2/src/cli_test_framework.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cli-test-framework
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: A powerful command line testing framework in Python with setup modules, parallel execution, and file comparison capabilities.
|
|
5
5
|
Home-page: https://github.com/ozil111/cli-test-framework
|
|
6
6
|
Author: Xiaotong Wang
|
{cli_test_framework-1.0.1 → cli_test_framework-1.0.2}/src/cli_test_framework.egg-info/SOURCES.txt
RENAMED
|
@@ -172,6 +172,7 @@ tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-7.4.4.pyc
|
|
|
172
172
|
tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-9.0.3.pyc
|
|
173
173
|
tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc
|
|
174
174
|
tests/unit/core/__pycache__/test_execution.cpython-312-pytest-9.0.3.pyc
|
|
175
|
+
tests/unit/core/__pycache__/test_execution.cpython-312.pyc
|
|
175
176
|
tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-7.4.4.pyc
|
|
176
177
|
tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-9.0.3.pyc
|
|
177
178
|
tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-7.4.4.pyc
|
|
Binary file
|
|
@@ -286,16 +286,21 @@ class TestTestCaseStepDataclass(unittest.TestCase):
|
|
|
286
286
|
def test_test_case_to_dict_with_steps(self):
|
|
287
287
|
steps = [
|
|
288
288
|
TestCaseStep(command="echo", args=["a"], expected={"return_code": 0}),
|
|
289
|
+
TestCaseStep(command="echo", args=["b"], expected={"return_code": 0}, retry_count=2),
|
|
289
290
|
]
|
|
290
|
-
case = TestCase(name="seq", steps=steps)
|
|
291
|
+
case = TestCase(name="seq", steps=steps, retry_count=3)
|
|
291
292
|
d = case.to_dict()
|
|
292
293
|
self.assertIn("steps", d)
|
|
293
294
|
self.assertEqual(d["steps"][0]["command"], "echo")
|
|
295
|
+
self.assertEqual(d["steps"][0]["retry_count"], 0)
|
|
296
|
+
self.assertEqual(d["steps"][1]["retry_count"], 2)
|
|
297
|
+
self.assertEqual(d["retry_count"], 3)
|
|
294
298
|
|
|
295
299
|
def test_test_case_to_dict_without_steps(self):
|
|
296
|
-
case = TestCase(name="s", command="echo", args=["x"], expected={"return_code": 0})
|
|
300
|
+
case = TestCase(name="s", command="echo", args=["x"], expected={"return_code": 0}, retry_count=5)
|
|
297
301
|
d = case.to_dict()
|
|
298
302
|
self.assertNotIn("steps", d)
|
|
303
|
+
self.assertEqual(d["retry_count"], 5)
|
|
299
304
|
|
|
300
305
|
|
|
301
306
|
if __name__ == "__main__":
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
cli_test_framework-1.0.2/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc
ADDED
|
Binary file
|
cli_test_framework-1.0.2/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-9.0.3.pyc
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"""Unit tests for cli_test_framework.core.config_loader — substitute_placeholders."""
|
|
1
|
+
"""Unit tests for cli_test_framework.core.config_loader — substitute_placeholders, parse_test_cases."""
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
|
|
5
|
-
from cli_test_framework.core.config_loader import substitute_placeholders
|
|
5
|
+
from cli_test_framework.core.config_loader import substitute_placeholders, parse_test_cases
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
# ---------------------------------------------------------------------------
|
|
@@ -134,3 +134,88 @@ class TestPlaceholderInTestCases:
|
|
|
134
134
|
assert steps[0]["args"] == ["--parse", "model.dat"]
|
|
135
135
|
assert steps[1]["command"] == "/opt/solver"
|
|
136
136
|
assert steps[1]["args"] == ["--solve", "model.dat"]
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# ---------------------------------------------------------------------------
|
|
140
|
+
# parse_test_cases — retry_count
|
|
141
|
+
# ---------------------------------------------------------------------------
|
|
142
|
+
|
|
143
|
+
class TestParseRetryCount:
|
|
144
|
+
"""Tests for ``retry_count`` parsing in ``parse_test_cases``."""
|
|
145
|
+
|
|
146
|
+
def test_single_command_retry_count(self):
|
|
147
|
+
config = {
|
|
148
|
+
"test_cases": [
|
|
149
|
+
{
|
|
150
|
+
"name": "retry-case",
|
|
151
|
+
"command": "echo",
|
|
152
|
+
"args": ["ok"],
|
|
153
|
+
"expected": {"return_code": 0},
|
|
154
|
+
"retry_count": 3,
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
cases = parse_test_cases(config)
|
|
159
|
+
assert len(cases) == 1
|
|
160
|
+
assert cases[0].retry_count == 3
|
|
161
|
+
|
|
162
|
+
def test_single_command_default_retry_count(self):
|
|
163
|
+
"""Without ``retry_count``, it defaults to 0."""
|
|
164
|
+
config = {
|
|
165
|
+
"test_cases": [
|
|
166
|
+
{
|
|
167
|
+
"name": "no-retry",
|
|
168
|
+
"command": "echo",
|
|
169
|
+
"args": ["ok"],
|
|
170
|
+
"expected": {"return_code": 0},
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
cases = parse_test_cases(config)
|
|
175
|
+
assert cases[0].retry_count == 0
|
|
176
|
+
|
|
177
|
+
def test_step_retry_count(self):
|
|
178
|
+
config = {
|
|
179
|
+
"test_cases": [
|
|
180
|
+
{
|
|
181
|
+
"name": "step-case",
|
|
182
|
+
"steps": [
|
|
183
|
+
{
|
|
184
|
+
"command": "echo",
|
|
185
|
+
"args": ["s1"],
|
|
186
|
+
"expected": {"return_code": 0},
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"command": "echo",
|
|
190
|
+
"args": ["s2"],
|
|
191
|
+
"expected": {"return_code": 0},
|
|
192
|
+
"retry_count": 2,
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
}
|
|
196
|
+
]
|
|
197
|
+
}
|
|
198
|
+
cases = parse_test_cases(config)
|
|
199
|
+
assert len(cases) == 1
|
|
200
|
+
steps = cases[0].steps
|
|
201
|
+
assert len(steps) == 2
|
|
202
|
+
assert steps[0].retry_count == 0 # default
|
|
203
|
+
assert steps[1].retry_count == 2
|
|
204
|
+
|
|
205
|
+
def test_step_default_retry_count(self):
|
|
206
|
+
config = {
|
|
207
|
+
"test_cases": [
|
|
208
|
+
{
|
|
209
|
+
"name": "step-no-retry",
|
|
210
|
+
"steps": [
|
|
211
|
+
{
|
|
212
|
+
"command": "echo",
|
|
213
|
+
"args": ["s1"],
|
|
214
|
+
"expected": {"return_code": 0},
|
|
215
|
+
}
|
|
216
|
+
],
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
cases = parse_test_cases(config)
|
|
221
|
+
assert cases[0].steps[0].retry_count == 0
|