cli-test-framework 0.9.3__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cli_test_framework-0.9.3/src/cli_test_framework.egg-info → cli_test_framework-1.0.0}/PKG-INFO +4 -1
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/docs/user_manual.md +123 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/setup.py +4 -1
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/cli.py +21 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/core/config_loader.py +63 -38
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/core/test_case.py +17 -1
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/runners/config_runner.py +1 -9
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/runners/parallel_config_runner.py +1 -9
- cli_test_framework-1.0.0/src/cli_test_framework/tui/__init__.py +11 -0
- cli_test_framework-1.0.0/src/cli_test_framework/tui/app.py +77 -0
- cli_test_framework-1.0.0/src/cli_test_framework/tui/controllers/__init__.py +0 -0
- cli_test_framework-1.0.0/src/cli_test_framework/tui/controllers/case_controller.py +270 -0
- cli_test_framework-1.0.0/src/cli_test_framework/tui/screens/__init__.py +0 -0
- cli_test_framework-1.0.0/src/cli_test_framework/tui/screens/case_editor.py +233 -0
- cli_test_framework-1.0.0/src/cli_test_framework/tui/screens/case_list.py +233 -0
- cli_test_framework-1.0.0/src/cli_test_framework/tui/widgets/__init__.py +0 -0
- cli_test_framework-1.0.0/src/cli_test_framework/tui/widgets/case_table.py +113 -0
- cli_test_framework-1.0.0/src/cli_test_framework/tui/widgets/expected_editor.py +159 -0
- cli_test_framework-1.0.0/src/cli_test_framework/tui/widgets/search_bar.py +160 -0
- cli_test_framework-1.0.0/src/cli_test_framework/tui/widgets/steps_editor.py +233 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0/src/cli_test_framework.egg-info}/PKG-INFO +4 -1
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework.egg-info/SOURCES.txt +34 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework.egg-info/requires.txt +3 -0
- cli_test_framework-1.0.0/tests/README.md +25 -0
- cli_test_framework-1.0.0/tests/unit/__pycache__/test_binary_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/__pycache__/test_cli.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/__pycache__/test_result.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/test_binary_comparator.py +426 -0
- cli_test_framework-1.0.0/tests/unit/test_cli.py +693 -0
- cli_test_framework-1.0.0/tests/unit/test_result.py +405 -0
- cli_test_framework-1.0.0/tests/unit/tui/__init__.py +0 -0
- cli_test_framework-1.0.0/tests/unit/tui/__pycache__/__init__.cpython-312.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/tui/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-7.4.4.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-7.4.4.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-7.4.4.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/tui/__pycache__/test_tui_run_test.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-7.4.4.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-1.0.0/tests/unit/tui/conftest.py +73 -0
- cli_test_framework-1.0.0/tests/unit/tui/test_app.py +106 -0
- cli_test_framework-1.0.0/tests/unit/tui/test_case_controller.py +425 -0
- cli_test_framework-1.0.0/tests/unit/tui/test_search_functions.py +187 -0
- cli_test_framework-1.0.0/tests/unit/tui/test_tui_run_test.py +384 -0
- cli_test_framework-1.0.0/tests/unit/tui/test_widgets_data.py +175 -0
- cli_test_framework-0.9.3/tests/README.md +0 -15
- cli_test_framework-0.9.3/tests/unit/__pycache__/test_cli.cpython-312-pytest-9.0.3.pyc +0 -0
- cli_test_framework-0.9.3/tests/unit/test_cli.py +0 -157
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/MANIFEST.in +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/README.md +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/docs/design.md +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/docs/design_en.md +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/docs/tui_and_config_split_design.md +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/docs/user_manual_en.md +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/pyproject.toml +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/setup.cfg +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/__init__.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/commands/__init__.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/commands/compare.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/config/__init__.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/config/config_io.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/config/import_expander.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/core/__init__.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/core/assertions.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/core/base_runner.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/core/execution.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/core/history_store.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/core/parallel_runner.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/core/process_worker.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/core/setup.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/core/types.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/file_comparator/__init__.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/file_comparator/base_comparator.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/file_comparator/binary_comparator.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/file_comparator/csv_comparator.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/file_comparator/factory.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/file_comparator/h5_comparator.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/file_comparator/json_comparator.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/file_comparator/result.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/file_comparator/text_comparator.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/file_comparator/xml_comparator.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/logging_config.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/runners/__init__.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/runners/json_runner.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/runners/parallel_json_runner.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/runners/parallel_yaml_runner.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/runners/yaml_runner.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/utils/__init__.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/utils/junit_xml_writer.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/utils/path_resolver.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/utils/report_generator.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework.egg-info/dependency_links.txt +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework.egg-info/entry_points.txt +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework.egg-info/top_level.txt +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/__init__.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/__pycache__/__init__.cpython-312.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/__pycache__/__init__.cpython-39.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/__pycache__/conftest.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/__pycache__/run_all.cpython-312.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/__pycache__/run_all.cpython-39.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/__pycache__/test_setup_module.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/conftest.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/demos/h5_filter_demo.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/demos/manual_report_example.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/demos/perf_parallel.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/e2e/__init__.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/e2e/__pycache__/__init__.cpython-312.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/e2e/__pycache__/__init__.cpython-39.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/e2e/__pycache__/test_user_flows.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/e2e/test_user_flows.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/fixtures/circular_config_a.json +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/fixtures/circular_config_b.json +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/fixtures/main_config.json +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/fixtures/missing_fields.json +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/fixtures/setup_main.json +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/fixtures/setup_sub.json +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/fixtures/sub_json_tests.yaml +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/fixtures/sub_text_tests.json +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/fixtures/test_cases.json +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/fixtures/test_cases.yaml +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/fixtures/test_cases1.json +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/fixtures/test_with_setup.json +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/fixtures/test_with_setup.yaml +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/test_binary_compare.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/test_csv_compare.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/test_h5_compare.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/test_json_compare.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/test_text_compare.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/file_compare/test_xml_compare.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/parallel/test_parallel_runner.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/path_handling/test_spaces_in_paths.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/test_history_feature.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/test_real_command_execution.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/integration/test_sequence.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/run_all.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/test_report.txt +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/__pycache__/test_cli.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/__pycache__/test_config_io.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/commands/test_compare_command.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/__pycache__/test_setup.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/test_assertions.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/test_config_loader.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/test_execution.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/test_history_store.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/test_process_worker.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/core/test_setup.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-39-pytest-8.3.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/runners/test_json_yaml_runner.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/runners/test_test_case_filter.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/runners/test_test_case_tag_filter.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/test_config_io.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/test_h5_comparator.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/test_import_expander.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/test_run_all.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-7.4.4.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-9.0.3.pyc +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/utils/test_junit_xml_writer.py +0 -0
- {cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/tests/unit/utils/test_report_generator.py +0 -0
{cli_test_framework-0.9.3/src/cli_test_framework.egg-info → cli_test_framework-1.0.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cli-test-framework
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
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
|
|
@@ -23,6 +23,8 @@ Requires-Dist: numpy>=1.21.0; python_version < "3.12"
|
|
|
23
23
|
Requires-Dist: numpy>=1.26.0; python_version >= "3.12"
|
|
24
24
|
Requires-Dist: setuptools>=75.8.0
|
|
25
25
|
Requires-Dist: wheel>=0.45.1
|
|
26
|
+
Provides-Extra: tui
|
|
27
|
+
Requires-Dist: textual>=0.40.0; extra == "tui"
|
|
26
28
|
Dynamic: author
|
|
27
29
|
Dynamic: author-email
|
|
28
30
|
Dynamic: classifier
|
|
@@ -30,6 +32,7 @@ Dynamic: description
|
|
|
30
32
|
Dynamic: description-content-type
|
|
31
33
|
Dynamic: home-page
|
|
32
34
|
Dynamic: project-url
|
|
35
|
+
Dynamic: provides-extra
|
|
33
36
|
Dynamic: requires-dist
|
|
34
37
|
Dynamic: requires-python
|
|
35
38
|
Dynamic: summary
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
- [测试用例定义](#测试用例定义)
|
|
7
7
|
- [配置拆分机制](#配置拆分机制)
|
|
8
8
|
- [配置校验](#配置校验)
|
|
9
|
+
- [TUI 交互式管理器](#tui-交互式管理器)
|
|
9
10
|
- [运行测试](#运行测试)
|
|
10
11
|
- [占位符(变量替换)](#占位符变量替换)
|
|
11
12
|
- [标签过滤](#标签过滤)
|
|
@@ -304,6 +305,128 @@ cli-test validate test_cases.json --workspace /path/to/project
|
|
|
304
305
|
[FAIL] Import target not found: /project/cases/nonexistent.json
|
|
305
306
|
```
|
|
306
307
|
|
|
308
|
+
## TUI 交互式管理器
|
|
309
|
+
|
|
310
|
+
当测试用例数量增长到几十甚至上百条时,纯手工编辑 JSON/YAML 配置文件容易出错且效率低下。TUI(Terminal User Interface)交互式管理器提供了一个终端内的可视化界面,支持浏览、搜索、编辑、运行测试用例,所有操作通过键盘快捷键完成,无需切换窗口或打开编辑器。
|
|
311
|
+
|
|
312
|
+
### 安装
|
|
313
|
+
|
|
314
|
+
TUI 依赖 `textual` 库,作为可选依赖提供,不影响核心框架的安装体积:
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
# 安装时附带 TUI 支持
|
|
318
|
+
pip install cli-test-framework[tui]
|
|
319
|
+
|
|
320
|
+
# 或者在已有框架上单独安装 textual
|
|
321
|
+
pip install textual
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
如果未安装 `textual` 就直接执行 `cli-test tui`,框架会给出友好的安装提示。
|
|
325
|
+
|
|
326
|
+
### 启动
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
# 打开 TUI 编辑测试用例
|
|
330
|
+
cli-test tui test_cases.json
|
|
331
|
+
|
|
332
|
+
# YAML 文件同样支持
|
|
333
|
+
cli-test tui test_cases.yaml
|
|
334
|
+
|
|
335
|
+
# 指定工作目录
|
|
336
|
+
cli-test tui test_cases.json --workspace /path/to/project
|
|
337
|
+
|
|
338
|
+
# 打开带 import 的主配置文件(自动展开子文件中的所有用例)
|
|
339
|
+
cli-test tui main_config.json
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
TUI 启动时会自动通过[配置拆分机制](#配置拆分机制)展开 `import` 引用,将所有用例加载到界面中统一管理。
|
|
343
|
+
|
|
344
|
+
### 界面概览
|
|
345
|
+
|
|
346
|
+
TUI 启动后显示**用例列表主界面**:
|
|
347
|
+
|
|
348
|
+
- **顶部状态栏**:当前文件名、用例总数
|
|
349
|
+
- **搜索栏**:`/` 键聚焦搜索框,支持子串/模糊/正则三种模式
|
|
350
|
+
- **用例表格**:六列(序号、名称、命令、标签、超时、模式),支持键盘导航
|
|
351
|
+
- **底部快捷键栏**:显示所有可用操作
|
|
352
|
+
|
|
353
|
+
### 快捷键
|
|
354
|
+
|
|
355
|
+
| 快捷键 | 功能 |
|
|
356
|
+
|---|---|
|
|
357
|
+
| `a` | 新增用例 |
|
|
358
|
+
| `e` | 编辑选中的用例 |
|
|
359
|
+
| `d` | 删除选中的用例 |
|
|
360
|
+
| `u` | 复制选中的用例(名称追加 `_copy` 后缀) |
|
|
361
|
+
| `r` | 运行选中的用例,显示执行结果 |
|
|
362
|
+
| `F6` / `Ctrl+S` | 保存修改到文件 |
|
|
363
|
+
| `/` | 聚焦搜索框 |
|
|
364
|
+
| `Esc` | 清除搜索,恢复完整列表 |
|
|
365
|
+
| `Alt+S` | 切换子串搜索模式(大小写不敏感) |
|
|
366
|
+
| `Alt+F` | 切换模糊搜索模式(容忍拼写差异和缩写) |
|
|
367
|
+
| `Alt+R` | 切换正则搜索模式 |
|
|
368
|
+
| `Ctrl+Q` | 退出 |
|
|
369
|
+
| `↑` / `↓` / `j` / `k` | 上下移动光标 |
|
|
370
|
+
|
|
371
|
+
搜索时会同时匹配 `name`、`command`、`args`、`tags`、`description` 等字段,匹配结果在表格中高亮显示。
|
|
372
|
+
|
|
373
|
+
### 编辑用例
|
|
374
|
+
|
|
375
|
+
选中用例后按 `e` 进入编辑界面。编辑界面根据用例类型有两种模式:
|
|
376
|
+
|
|
377
|
+
#### 单命令模式
|
|
378
|
+
|
|
379
|
+
编辑表单包含以下字段:
|
|
380
|
+
|
|
381
|
+
| 字段 | 说明 |
|
|
382
|
+
|---|---|
|
|
383
|
+
| `Name` | 用例名称(必填) |
|
|
384
|
+
| `Command` | 要执行的命令 |
|
|
385
|
+
| `Args` | 命令参数,每行一个 |
|
|
386
|
+
| `Tags` | 标签列表,每行一个 |
|
|
387
|
+
| `Description` | 用例描述 |
|
|
388
|
+
| `Timeout` | 超时秒数 |
|
|
389
|
+
| Expected | 期望断言的嵌套子表单(见下文) |
|
|
390
|
+
|
|
391
|
+
#### 步骤序列模式
|
|
392
|
+
|
|
393
|
+
当用例包含多个有序步骤时,切换到此模式。每个步骤有独立的 `Command`、`Args`、`Expected` 和 `Timeout`,支持添加、删除、编辑和上下移动步骤。
|
|
394
|
+
|
|
395
|
+
两种模式可通过编辑界面内的快捷键切换,切换时会提示确认以免丢失数据。
|
|
396
|
+
|
|
397
|
+
### `expected` 字段编辑
|
|
398
|
+
|
|
399
|
+
`expected` 字段是一个嵌套字典,编辑器提供结构化输入:
|
|
400
|
+
|
|
401
|
+
| 字段 | 输入方式 |
|
|
402
|
+
|---|---|
|
|
403
|
+
| `return_code` | 数字输入框 |
|
|
404
|
+
| `output_contains` | 多行文本输入,一行一个匹配字符串 |
|
|
405
|
+
| `output_matches` | 正则表达式文本输入 |
|
|
406
|
+
| `compare_files` | 每行一个 JSON 对象,如 `{"actual":"out.txt","baseline":"base.txt","type":"text"}` |
|
|
407
|
+
|
|
408
|
+
除上述已知字段外,还支持通过 `+ Add` 按钮添加自定义 key=value 对,value 为字符串或 JSON 文本。更多含义见[测试用例定义](#测试用例定义)。
|
|
409
|
+
|
|
410
|
+
### 运行用例
|
|
411
|
+
|
|
412
|
+
在列表中选中某条用例,按 `r` 即可实时调用框架执行引擎运行该用例。运行结束后弹出结果面板,显示:
|
|
413
|
+
|
|
414
|
+
- 通过/失败状态
|
|
415
|
+
- 返回码
|
|
416
|
+
- 耗时
|
|
417
|
+
- 命令输出(stdout/stderr)
|
|
418
|
+
|
|
419
|
+
结果面板仅展示、不修改配置文件。
|
|
420
|
+
|
|
421
|
+
### 保存
|
|
422
|
+
|
|
423
|
+
对用例的任何增删改操作都在**内存中**进行,不会立即写入磁盘。
|
|
424
|
+
|
|
425
|
+
- 按 `F6` 或 `Ctrl+S` **保存**:将当前全部用例写回原配置文件。
|
|
426
|
+
- 通过 `save_as` 可**另存为**新文件(通过界面菜单操作)。
|
|
427
|
+
|
|
428
|
+
退出 TUI 时如有未保存的修改,会弹出确认提示。
|
|
429
|
+
|
|
307
430
|
## 运行测试
|
|
308
431
|
|
|
309
432
|
### 命令行
|
|
@@ -8,7 +8,7 @@ with open(os.path.join(this_directory, 'README.md'), encoding='utf-8') as f:
|
|
|
8
8
|
|
|
9
9
|
setup(
|
|
10
10
|
name="cli-test-framework",
|
|
11
|
-
version="0.
|
|
11
|
+
version="1.0.0",
|
|
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.",
|
|
@@ -25,6 +25,9 @@ setup(
|
|
|
25
25
|
"setuptools>=75.8.0",
|
|
26
26
|
"wheel>=0.45.1"
|
|
27
27
|
],
|
|
28
|
+
extras_require={
|
|
29
|
+
"tui": ["textual>=0.40.0"],
|
|
30
|
+
},
|
|
28
31
|
entry_points={
|
|
29
32
|
'console_scripts': [
|
|
30
33
|
'cli-test=cli_test_framework.cli:main',
|
|
@@ -44,6 +44,7 @@ Examples:
|
|
|
44
44
|
cli-test run test_cases.json
|
|
45
45
|
cli-test run test_cases.json --parallel --workers 4
|
|
46
46
|
cli-test run test_cases.yaml --workspace /path/to/project
|
|
47
|
+
cli-test tui test_cases.json
|
|
47
48
|
cli-test validate main_config.json
|
|
48
49
|
cli-test compare file1.json file2.json
|
|
49
50
|
cli-test compare file1.txt file2.txt --output-format json
|
|
@@ -80,6 +81,17 @@ Examples:
|
|
|
80
81
|
'e.g. --var solver=/path/to/solver '
|
|
81
82
|
'(can be used multiple times)')
|
|
82
83
|
|
|
84
|
+
# ---- TUI command ----
|
|
85
|
+
tui_parser = subparsers.add_parser(
|
|
86
|
+
'tui', help='Launch interactive TUI for managing test cases'
|
|
87
|
+
)
|
|
88
|
+
tui_parser.add_argument(
|
|
89
|
+
'config_file', help='Path to the test configuration file (JSON or YAML)'
|
|
90
|
+
)
|
|
91
|
+
tui_parser.add_argument(
|
|
92
|
+
'--workspace', '-w', help='Working directory'
|
|
93
|
+
)
|
|
94
|
+
|
|
83
95
|
# ---- Validate command ----
|
|
84
96
|
validate_parser = subparsers.add_parser(
|
|
85
97
|
'validate', help='Validate test configuration without running tests'
|
|
@@ -299,6 +311,13 @@ def run_compare(args):
|
|
|
299
311
|
return bool(exit_code == 0)
|
|
300
312
|
|
|
301
313
|
|
|
314
|
+
def run_tui(args):
|
|
315
|
+
"""Launch the TUI manager."""
|
|
316
|
+
from .tui.app import run_tui as _run_tui
|
|
317
|
+
|
|
318
|
+
_run_tui(args.config_file, args.workspace)
|
|
319
|
+
|
|
320
|
+
|
|
302
321
|
def run_validate(args):
|
|
303
322
|
"""Validate test configuration without running tests."""
|
|
304
323
|
from .config.config_io import validate_config
|
|
@@ -348,6 +367,8 @@ def main():
|
|
|
348
367
|
if args.command == 'run':
|
|
349
368
|
success = run_tests(args)
|
|
350
369
|
sys.exit(0 if success else 1)
|
|
370
|
+
elif args.command == 'tui':
|
|
371
|
+
run_tui(args)
|
|
351
372
|
elif args.command == 'validate':
|
|
352
373
|
success = run_validate(args)
|
|
353
374
|
sys.exit(0 if success else 1)
|
{cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/core/config_loader.py
RENAMED
|
@@ -80,37 +80,51 @@ def _split_and_resolve(
|
|
|
80
80
|
|
|
81
81
|
def parse_test_cases(
|
|
82
82
|
config: Dict[str, Any],
|
|
83
|
-
workspace: Path,
|
|
84
|
-
path_resolver: Any,
|
|
83
|
+
workspace: Optional[Path] = None,
|
|
84
|
+
path_resolver: Any = None,
|
|
85
85
|
) -> List[TestCase]:
|
|
86
86
|
"""Parse ``config['test_cases']`` into a list of ``TestCase`` objects.
|
|
87
87
|
|
|
88
88
|
Supports both single-command mode and sequence (``steps``) mode.
|
|
89
|
+
|
|
90
|
+
When *workspace* and *path_resolver* are provided (Runner mode),
|
|
91
|
+
required fields are validated and command/args paths are resolved.
|
|
92
|
+
When omitted (TUI mode), missing fields get sensible defaults and
|
|
93
|
+
raw values are kept as-is for display purposes.
|
|
89
94
|
"""
|
|
90
95
|
cases: List[TestCase] = []
|
|
96
|
+
resolve = workspace is not None and path_resolver is not None
|
|
91
97
|
|
|
92
|
-
for case in config
|
|
98
|
+
for case in config.get("test_cases", []):
|
|
93
99
|
if "steps" in case:
|
|
94
100
|
# ── Sequence mode ──
|
|
95
101
|
steps: List[TestCaseStep] = []
|
|
96
|
-
for step in case
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
for step in case.get("steps", []):
|
|
103
|
+
if resolve:
|
|
104
|
+
step_required = ["command", "args", "expected"]
|
|
105
|
+
if not all(field in step for field in step_required):
|
|
106
|
+
raise ValueError(
|
|
107
|
+
f"Step in test case '{case.get('name', 'unnamed')}' "
|
|
108
|
+
f"is missing required fields"
|
|
109
|
+
)
|
|
110
|
+
executable, resolved_args = _split_and_resolve(
|
|
111
|
+
step["command"], step["args"], workspace, path_resolver
|
|
102
112
|
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
steps.append(TestCaseStep(
|
|
114
|
+
command=executable,
|
|
115
|
+
args=resolved_args,
|
|
116
|
+
expected=step["expected"],
|
|
117
|
+
timeout=step.get("timeout"),
|
|
118
|
+
))
|
|
119
|
+
else:
|
|
120
|
+
steps.append(TestCaseStep(
|
|
121
|
+
command=step.get("command", ""),
|
|
122
|
+
args=step.get("args", []),
|
|
123
|
+
expected=step.get("expected", {}),
|
|
124
|
+
timeout=step.get("timeout"),
|
|
125
|
+
))
|
|
112
126
|
cases.append(TestCase(
|
|
113
|
-
name=case
|
|
127
|
+
name=case.get("name", ""),
|
|
114
128
|
steps=steps,
|
|
115
129
|
description=case.get("description", ""),
|
|
116
130
|
resources=case.get("resources"),
|
|
@@ -118,26 +132,37 @@ def parse_test_cases(
|
|
|
118
132
|
))
|
|
119
133
|
else:
|
|
120
134
|
# ── Single-command mode (backward-compatible) ──
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
135
|
+
if resolve:
|
|
136
|
+
required_fields = ["name", "command", "args", "expected"]
|
|
137
|
+
if not all(field in case for field in required_fields):
|
|
138
|
+
raise ValueError(
|
|
139
|
+
f"Test case {case.get('name', 'unnamed')} "
|
|
140
|
+
f"is missing required fields"
|
|
141
|
+
)
|
|
142
|
+
executable, resolved_args = _split_and_resolve(
|
|
143
|
+
case["command"], case["args"], workspace, path_resolver
|
|
126
144
|
)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
145
|
+
cases.append(TestCase(
|
|
146
|
+
name=case["name"],
|
|
147
|
+
command=executable,
|
|
148
|
+
args=resolved_args,
|
|
149
|
+
expected=case["expected"],
|
|
150
|
+
description=case.get("description", ""),
|
|
151
|
+
timeout=case.get("timeout"),
|
|
152
|
+
resources=case.get("resources"),
|
|
153
|
+
tags=case.get("tags", []),
|
|
154
|
+
))
|
|
155
|
+
else:
|
|
156
|
+
cases.append(TestCase(
|
|
157
|
+
name=case.get("name", ""),
|
|
158
|
+
command=case.get("command", ""),
|
|
159
|
+
args=case.get("args", []),
|
|
160
|
+
expected=case.get("expected", {}),
|
|
161
|
+
description=case.get("description", ""),
|
|
162
|
+
timeout=case.get("timeout"),
|
|
163
|
+
resources=case.get("resources"),
|
|
164
|
+
tags=case.get("tags", []),
|
|
165
|
+
))
|
|
141
166
|
|
|
142
167
|
return cases
|
|
143
168
|
|
{cli_test_framework-0.9.3 → cli_test_framework-1.0.0}/src/cli_test_framework/core/test_case.py
RENAMED
|
@@ -44,4 +44,20 @@ class TestCase:
|
|
|
44
44
|
}
|
|
45
45
|
for s in self.steps
|
|
46
46
|
]
|
|
47
|
-
return result
|
|
47
|
+
return result
|
|
48
|
+
|
|
49
|
+
def to_execution_dict(self) -> Dict[str, Any]:
|
|
50
|
+
"""Convert to the dict format expected by ``execute_single_test_case``.
|
|
51
|
+
|
|
52
|
+
Only for single-command mode; sequence cases should use
|
|
53
|
+
``execute_sequence()`` instead.
|
|
54
|
+
"""
|
|
55
|
+
return {
|
|
56
|
+
"name": self.name,
|
|
57
|
+
"command": self.command,
|
|
58
|
+
"args": self.args,
|
|
59
|
+
"expected": self.expected,
|
|
60
|
+
"description": self.description or None,
|
|
61
|
+
"timeout": self.timeout,
|
|
62
|
+
"resources": self.resources,
|
|
63
|
+
}
|
|
@@ -67,15 +67,7 @@ class ConfigRunner(BaseRunner):
|
|
|
67
67
|
if case.steps:
|
|
68
68
|
return self._run_sequence(case)
|
|
69
69
|
|
|
70
|
-
case_data
|
|
71
|
-
"name": case.name,
|
|
72
|
-
"command": case.command,
|
|
73
|
-
"args": case.args,
|
|
74
|
-
"expected": case.expected,
|
|
75
|
-
"description": case.description or None,
|
|
76
|
-
"timeout": case.timeout,
|
|
77
|
-
"resources": case.resources,
|
|
78
|
-
}
|
|
70
|
+
case_data = case.to_execution_dict()
|
|
79
71
|
|
|
80
72
|
command_preview = (
|
|
81
73
|
f"{case_data['command']} {' '.join(case_data['args'])}".strip()
|
|
@@ -226,15 +226,7 @@ class ParallelConfigRunner(ParallelRunner):
|
|
|
226
226
|
if case.steps:
|
|
227
227
|
result = self._run_sequence(case)
|
|
228
228
|
else:
|
|
229
|
-
case_data
|
|
230
|
-
"name": case.name,
|
|
231
|
-
"command": case.command,
|
|
232
|
-
"args": case.args,
|
|
233
|
-
"expected": case.expected,
|
|
234
|
-
"description": case.description or None,
|
|
235
|
-
"timeout": case.timeout,
|
|
236
|
-
"resources": case.resources,
|
|
237
|
-
}
|
|
229
|
+
case_data = case.to_execution_dict()
|
|
238
230
|
|
|
239
231
|
command_preview = (
|
|
240
232
|
f"{case_data['command']} {' '.join(case_data['args'])}".strip()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TUI Manager for interactive test case CRUD.
|
|
3
|
+
|
|
4
|
+
Provides a Textual-based terminal UI for browsing, editing and running
|
|
5
|
+
test cases. Relies on :mod:`cli_test_framework.config.config_io` for
|
|
6
|
+
configuration I/O and :mod:`cli_test_framework.core` for execution.
|
|
7
|
+
|
|
8
|
+
Usage::
|
|
9
|
+
|
|
10
|
+
cli-test tui test_cases.json
|
|
11
|
+
"""
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Textual App entry point for the TUI manager.
|
|
2
|
+
|
|
3
|
+
Usage::
|
|
4
|
+
|
|
5
|
+
from cli_test_framework.tui.app import run_tui
|
|
6
|
+
run_tui("test_cases.json", workspace="/path/to/project")
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Optional
|
|
13
|
+
|
|
14
|
+
from textual.app import App, ComposeResult
|
|
15
|
+
from textual.binding import Binding
|
|
16
|
+
|
|
17
|
+
from .controllers.case_controller import CaseController
|
|
18
|
+
from .screens.case_list import CaseListScreen
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CaseManagerApp(App):
|
|
22
|
+
"""Terminal UI for browsing / editing / running test cases."""
|
|
23
|
+
|
|
24
|
+
TITLE = "CLI Test Framework - Case Manager"
|
|
25
|
+
|
|
26
|
+
BINDINGS = [
|
|
27
|
+
Binding("ctrl+q", "quit", "Quit", show=True, priority=True),
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
CSS = """
|
|
31
|
+
Screen {
|
|
32
|
+
background: $surface;
|
|
33
|
+
}
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, config_file: str, workspace: Optional[str] = None):
|
|
37
|
+
super().__init__()
|
|
38
|
+
self._config_file = config_file
|
|
39
|
+
self._workspace = workspace
|
|
40
|
+
self._controller = CaseController()
|
|
41
|
+
|
|
42
|
+
def on_mount(self) -> None:
|
|
43
|
+
try:
|
|
44
|
+
count = self._controller.load(self._config_file, self._workspace)
|
|
45
|
+
self.notify(f"Loaded {count} test cases from {Path(self._config_file).name}")
|
|
46
|
+
except Exception as e:
|
|
47
|
+
self.notify(f"Failed to load config: {e}", severity="error")
|
|
48
|
+
|
|
49
|
+
self.push_screen(CaseListScreen(self._controller))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# ---------------------------------------------------------------------------
|
|
53
|
+
# Public entry point
|
|
54
|
+
# ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def run_tui(config_file: str, workspace: Optional[str] = None) -> None:
|
|
58
|
+
"""Launch the TUI manager.
|
|
59
|
+
|
|
60
|
+
Safe to call without installing textual — raises :exc:`ImportError`
|
|
61
|
+
with a friendly message if textual is not available.
|
|
62
|
+
"""
|
|
63
|
+
try:
|
|
64
|
+
import textual # noqa: F401 — verify textual is importable
|
|
65
|
+
except ImportError:
|
|
66
|
+
import sys
|
|
67
|
+
|
|
68
|
+
print(
|
|
69
|
+
"TUI 功能需要安装 textual。请运行:\n"
|
|
70
|
+
" pip install cli-test-framework[tui]\n"
|
|
71
|
+
"或:\n"
|
|
72
|
+
" pip install textual"
|
|
73
|
+
)
|
|
74
|
+
sys.exit(1)
|
|
75
|
+
|
|
76
|
+
app = CaseManagerApp(config_file, workspace)
|
|
77
|
+
app.run()
|
|
File without changes
|