cli-test-framework 0.8.0__tar.gz → 0.9.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.
Files changed (166) hide show
  1. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/PKG-INFO +20 -2
  2. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/README.md +19 -1
  3. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/docs/user_manual.md +363 -16
  4. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/setup.py +1 -1
  5. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/cli.py +6 -0
  6. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/core/base_runner.py +12 -4
  7. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/core/config_loader.py +2 -0
  8. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/core/execution.py +1 -0
  9. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/core/parallel_runner.py +4 -7
  10. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/core/test_case.py +2 -0
  11. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/runners/config_runner.py +3 -6
  12. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/runners/json_runner.py +2 -7
  13. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/runners/parallel_config_runner.py +3 -6
  14. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/runners/parallel_json_runner.py +2 -6
  15. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/runners/parallel_yaml_runner.py +2 -6
  16. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/runners/yaml_runner.py +2 -7
  17. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework.egg-info/PKG-INFO +20 -2
  18. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework.egg-info/SOURCES.txt +6 -0
  19. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-7.4.4.pyc +0 -0
  20. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-9.0.3.pyc +0 -0
  21. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-7.4.4.pyc +0 -0
  22. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-9.0.3.pyc +0 -0
  23. cli_test_framework-0.9.0/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  24. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  25. cli_test_framework-0.8.0/tests/unit/__pycache__/test_cli.cpython-312-pytest-9.0.3.pyc → cli_test_framework-0.9.0/tests/unit/__pycache__/test_cli.cpython-312-pytest-7.4.4.pyc +0 -0
  26. cli_test_framework-0.9.0/tests/unit/__pycache__/test_cli.cpython-312-pytest-9.0.3.pyc +0 -0
  27. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-7.4.4.pyc +0 -0
  28. cli_test_framework-0.9.0/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-7.4.4.pyc +0 -0
  29. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-9.0.3.pyc +0 -0
  30. cli_test_framework-0.9.0/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-9.0.3.pyc +0 -0
  31. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-7.4.4.pyc +0 -0
  32. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-9.0.3.pyc +0 -0
  33. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-7.4.4.pyc +0 -0
  34. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-9.0.3.pyc +0 -0
  35. cli_test_framework-0.9.0/tests/unit/core/test_execution.py +70 -0
  36. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  37. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-9.0.3.pyc +0 -0
  38. cli_test_framework-0.9.0/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-7.4.4.pyc +0 -0
  39. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-9.0.3.pyc +0 -0
  40. cli_test_framework-0.9.0/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-312-pytest-9.0.3.pyc +0 -0
  41. cli_test_framework-0.9.0/tests/unit/runners/test_test_case_tag_filter.py +254 -0
  42. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/test_cli.py +1 -0
  43. cli_test_framework-0.9.0/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-7.4.4.pyc +0 -0
  44. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-9.0.3.pyc +0 -0
  45. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-7.4.4.pyc +0 -0
  46. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-9.0.3.pyc +0 -0
  47. cli_test_framework-0.8.0/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  48. cli_test_framework-0.8.0/tests/unit/__pycache__/test_cli.cpython-312-pytest-7.4.4.pyc +0 -0
  49. cli_test_framework-0.8.0/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-7.4.4.pyc +0 -0
  50. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/MANIFEST.in +0 -0
  51. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/docs/design.md +0 -0
  52. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/docs/design_en.md +0 -0
  53. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/docs/user_manual_en.md +0 -0
  54. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/pyproject.toml +0 -0
  55. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/setup.cfg +0 -0
  56. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/__init__.py +0 -0
  57. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/commands/__init__.py +0 -0
  58. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/commands/compare.py +0 -0
  59. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/core/__init__.py +0 -0
  60. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/core/assertions.py +0 -0
  61. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/core/history_store.py +0 -0
  62. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/core/process_worker.py +0 -0
  63. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/core/setup.py +0 -0
  64. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/core/types.py +0 -0
  65. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/file_comparator/__init__.py +0 -0
  66. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/file_comparator/base_comparator.py +0 -0
  67. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/file_comparator/binary_comparator.py +0 -0
  68. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/file_comparator/csv_comparator.py +0 -0
  69. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/file_comparator/factory.py +0 -0
  70. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/file_comparator/h5_comparator.py +0 -0
  71. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/file_comparator/json_comparator.py +0 -0
  72. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/file_comparator/result.py +0 -0
  73. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/file_comparator/text_comparator.py +0 -0
  74. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/file_comparator/xml_comparator.py +0 -0
  75. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/logging_config.py +0 -0
  76. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/runners/__init__.py +0 -0
  77. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/utils/__init__.py +0 -0
  78. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/utils/junit_xml_writer.py +0 -0
  79. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/utils/path_resolver.py +0 -0
  80. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework/utils/report_generator.py +0 -0
  81. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework.egg-info/dependency_links.txt +0 -0
  82. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework.egg-info/entry_points.txt +0 -0
  83. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework.egg-info/requires.txt +0 -0
  84. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/src/cli_test_framework.egg-info/top_level.txt +0 -0
  85. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/README.md +0 -0
  86. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/__init__.py +0 -0
  87. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/__pycache__/__init__.cpython-312.pyc +0 -0
  88. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/__pycache__/__init__.cpython-39.pyc +0 -0
  89. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
  90. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
  91. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/__pycache__/conftest.cpython-39-pytest-8.3.4.pyc +0 -0
  92. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/__pycache__/run_all.cpython-312.pyc +0 -0
  93. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/__pycache__/run_all.cpython-39.pyc +0 -0
  94. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  95. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/__pycache__/test_setup_module.cpython-312-pytest-7.4.4.pyc +0 -0
  96. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/conftest.py +0 -0
  97. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/demos/h5_filter_demo.py +0 -0
  98. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/demos/manual_report_example.py +0 -0
  99. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/demos/perf_parallel.py +0 -0
  100. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/e2e/__init__.py +0 -0
  101. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/e2e/__pycache__/__init__.cpython-312.pyc +0 -0
  102. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/e2e/__pycache__/__init__.cpython-39.pyc +0 -0
  103. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-7.4.4.pyc +0 -0
  104. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-9.0.3.pyc +0 -0
  105. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/e2e/__pycache__/test_user_flows.cpython-39-pytest-8.3.4.pyc +0 -0
  106. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/e2e/test_user_flows.py +0 -0
  107. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/fixtures/test_cases.json +0 -0
  108. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/fixtures/test_cases.yaml +0 -0
  109. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/fixtures/test_cases1.json +0 -0
  110. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/fixtures/test_with_setup.json +0 -0
  111. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/fixtures/test_with_setup.yaml +0 -0
  112. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-7.4.4.pyc +0 -0
  113. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-9.0.3.pyc +0 -0
  114. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  115. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  116. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  117. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  118. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  119. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  120. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  121. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  122. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  123. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  124. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  125. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  126. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  127. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  128. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/test_binary_compare.py +0 -0
  129. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/test_csv_compare.py +0 -0
  130. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/test_h5_compare.py +0 -0
  131. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/test_json_compare.py +0 -0
  132. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/test_text_compare.py +0 -0
  133. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/file_compare/test_xml_compare.py +0 -0
  134. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  135. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-9.0.3.pyc +0 -0
  136. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-39-pytest-8.3.4.pyc +0 -0
  137. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/parallel/test_parallel_runner.py +0 -0
  138. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-7.4.4.pyc +0 -0
  139. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-9.0.3.pyc +0 -0
  140. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-39-pytest-8.3.4.pyc +0 -0
  141. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/path_handling/test_spaces_in_paths.py +0 -0
  142. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/test_history_feature.py +0 -0
  143. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/test_real_command_execution.py +0 -0
  144. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/integration/test_sequence.py +0 -0
  145. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/run_all.py +0 -0
  146. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/test_report.txt +0 -0
  147. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  148. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  149. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-9.0.3.pyc +0 -0
  150. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-7.4.4.pyc +0 -0
  151. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-9.0.3.pyc +0 -0
  152. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/commands/test_compare_command.py +0 -0
  153. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-7.4.4.pyc +0 -0
  154. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-9.0.3.pyc +0 -0
  155. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/core/__pycache__/test_setup.cpython-39-pytest-8.3.4.pyc +0 -0
  156. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/core/test_assertions.py +0 -0
  157. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/core/test_history_store.py +0 -0
  158. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/core/test_process_worker.py +0 -0
  159. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/core/test_setup.py +0 -0
  160. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-39-pytest-8.3.4.pyc +0 -0
  161. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/runners/test_json_yaml_runner.py +0 -0
  162. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/runners/test_test_case_filter.py +0 -0
  163. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/test_h5_comparator.py +0 -0
  164. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/test_run_all.py +0 -0
  165. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/utils/test_junit_xml_writer.py +0 -0
  166. {cli_test_framework-0.8.0 → cli_test_framework-0.9.0}/tests/unit/utils/test_report_generator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cli-test-framework
3
- Version: 0.8.0
3
+ Version: 0.9.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
@@ -56,7 +56,7 @@ CLI Test Framework was built for that workflow.
56
56
  - **Sequence Steps** — Multi-step execution within a single test case, fail-fast
57
57
  - **Setup Module** — Auto-configure environment variables before tests, auto-cleanup after
58
58
  - **File Comparison** — Text / JSON / CSV / XML / HDF5 / Binary, with CLI and embedded assertion support
59
- - **Filtered Execution** — Run specific test cases by name
59
+ - **Filtered Execution** — Run specific test cases by name or tag
60
60
  - **JUnit XML Output** — `--junit-xml` for GitLab CI / Jenkins / CircleCI test report panels
61
61
 
62
62
  ## Quick Start
@@ -76,6 +76,7 @@ pip install cli-test-framework
76
76
  "name": "hello",
77
77
  "command": "echo",
78
78
  "args": ["Hello World"],
79
+ "tags": ["smoke"],
79
80
  "expected": {
80
81
  "return_code": 0,
81
82
  "output_contains": ["Hello World"]
@@ -145,6 +146,19 @@ Multiple files and mixed assertion types coexist naturally:
145
146
  cli-test run test_cases.json --parallel --workers 4
146
147
  ```
147
148
 
149
+ ### Run Specific Cases
150
+
151
+ ```bash
152
+ # By name
153
+ cli-test run test_cases.json -t test_1 -t test_2
154
+
155
+ # By tag
156
+ cli-test run test_cases.json --tag smoke
157
+
158
+ # Combine name and tag (AND logic)
159
+ cli-test run test_cases.json -t test_1 --tag smoke
160
+ ```
161
+
148
162
  ### JUnit XML (CI Integration)
149
163
 
150
164
  ```bash
@@ -184,6 +198,10 @@ compare-files result1.h5 result2.h5 --h5-table-regex "output_.*" --h5-rtol 1e-5
184
198
 
185
199
  ## Changelog
186
200
 
201
+ ### 0.9.0
202
+
203
+ - **Tag filtering**: New `tags` field in test case definitions for categorization. Use `--tag` CLI option or `test_case_tag_filter` Python API to batch-filter test cases. Acts as OR within tags, AND with name filtering.
204
+
187
205
  ### 0.8.0
188
206
 
189
207
  - **JUnit XML output**: New `--junit-xml <filepath>` CLI option writes JUnit-format XML reports that integrate directly with GitLab CI, Jenkins, CircleCI, and other CI tools. Supports `passed` / `failed` / `timeout` / `error` status mapping. Zero extra dependencies — built with `xml.etree.ElementTree`.
@@ -20,7 +20,7 @@ CLI Test Framework was built for that workflow.
20
20
  - **Sequence Steps** — Multi-step execution within a single test case, fail-fast
21
21
  - **Setup Module** — Auto-configure environment variables before tests, auto-cleanup after
22
22
  - **File Comparison** — Text / JSON / CSV / XML / HDF5 / Binary, with CLI and embedded assertion support
23
- - **Filtered Execution** — Run specific test cases by name
23
+ - **Filtered Execution** — Run specific test cases by name or tag
24
24
  - **JUnit XML Output** — `--junit-xml` for GitLab CI / Jenkins / CircleCI test report panels
25
25
 
26
26
  ## Quick Start
@@ -40,6 +40,7 @@ pip install cli-test-framework
40
40
  "name": "hello",
41
41
  "command": "echo",
42
42
  "args": ["Hello World"],
43
+ "tags": ["smoke"],
43
44
  "expected": {
44
45
  "return_code": 0,
45
46
  "output_contains": ["Hello World"]
@@ -109,6 +110,19 @@ Multiple files and mixed assertion types coexist naturally:
109
110
  cli-test run test_cases.json --parallel --workers 4
110
111
  ```
111
112
 
113
+ ### Run Specific Cases
114
+
115
+ ```bash
116
+ # By name
117
+ cli-test run test_cases.json -t test_1 -t test_2
118
+
119
+ # By tag
120
+ cli-test run test_cases.json --tag smoke
121
+
122
+ # Combine name and tag (AND logic)
123
+ cli-test run test_cases.json -t test_1 --tag smoke
124
+ ```
125
+
112
126
  ### JUnit XML (CI Integration)
113
127
 
114
128
  ```bash
@@ -148,6 +162,10 @@ compare-files result1.h5 result2.h5 --h5-table-regex "output_.*" --h5-rtol 1e-5
148
162
 
149
163
  ## Changelog
150
164
 
165
+ ### 0.9.0
166
+
167
+ - **Tag filtering**: New `tags` field in test case definitions for categorization. Use `--tag` CLI option or `test_case_tag_filter` Python API to batch-filter test cases. Acts as OR within tags, AND with name filtering.
168
+
151
169
  ### 0.8.0
152
170
 
153
171
  - **JUnit XML output**: New `--junit-xml <filepath>` CLI option writes JUnit-format XML reports that integrate directly with GitLab CI, Jenkins, CircleCI, and other CI tools. Supports `passed` / `failed` / `timeout` / `error` status mapping. Zero extra dependencies — built with `xml.etree.ElementTree`.
@@ -5,13 +5,17 @@
5
5
  - [安装](#安装)
6
6
  - [测试用例定义](#测试用例定义)
7
7
  - [运行测试](#运行测试)
8
+ - [标签过滤](#标签过滤)
8
9
  - [Setup 模块](#setup-模块)
9
10
  - [并行测试](#并行测试)
10
11
  - [顺序步骤测试](#顺序步骤测试)
11
12
  - [资源感知调度](#资源感知调度)
12
13
  - [历史记录与回归检测](#历史记录与回归检测)
14
+ - [JUnit XML 报告](#junit-xml-报告)
15
+ - [日志配置](#日志配置)
13
16
  - [文件比较](#文件比较)
14
17
  - [扩展开发](#扩展开发)
18
+ - [运行框架自带测试](#运行框架自带测试)
15
19
 
16
20
  ## 安装
17
21
 
@@ -27,6 +31,8 @@ YAML 支持需额外安装:
27
31
  pip install pyyaml
28
32
  ```
29
33
 
34
+ HDF5 文件比较依赖 `h5py`(已随框架安装)。如需在无 HDF5 环境下使用其他比较功能,可单独卸载,但 HDF5 比较将不可用。
35
+
30
36
  ## 测试用例定义
31
37
 
32
38
  ### JSON 格式
@@ -48,7 +54,14 @@ pip install pyyaml
48
54
  "expected": {
49
55
  "return_code": 0,
50
56
  "output_contains": ["Hello"],
51
- "output_matches": [".*regex.*"]
57
+ "output_matches": ".*regex.*",
58
+ "compare_files": [
59
+ {
60
+ "actual": "output.txt",
61
+ "baseline": "baseline.txt",
62
+ "type": "text"
63
+ }
64
+ ]
52
65
  }
53
66
  }
54
67
  ]
@@ -72,8 +85,11 @@ test_cases:
72
85
  return_code: 0
73
86
  output_contains:
74
87
  - "Hello"
75
- output_matches:
76
- - ".*regex.*"
88
+ output_matches: ".*regex.*"
89
+ compare_files:
90
+ - actual: output.txt
91
+ baseline: baseline.txt
92
+ type: text
77
93
  ```
78
94
 
79
95
  ### 字段说明
@@ -81,13 +97,49 @@ test_cases:
81
97
  | 字段 | 必填 | 说明 |
82
98
  |---|---|---|
83
99
  | `name` | 是 | 测试用例名称 |
84
- | `command` | 是 | 要执行的命令 |
100
+ | `command` | 是 | 要执行的命令(支持带参数的命令字符串,如 `python ./run.py`,框架会自动拆分并解析路径) |
85
101
  | `args` | 否 | 命令参数列表 |
102
+ | `description` | 否 | 测试用例描述 |
86
103
  | `timeout` | 否 | 超时秒数,默认 3600,设 `null` 无限制 |
104
+ | `tags` | 否 | 标签列表,用于批量过滤(如 `["smoke", "fast"]`) |
87
105
  | `resources` | 否 | 资源配置,见[资源感知调度](#资源感知调度) |
88
106
  | `expected.return_code` | 否 | 期望返回码 |
89
107
  | `expected.output_contains` | 否 | 输出需包含的字符串列表 |
90
- | `expected.output_matches` | 否 | 输出需匹配的正则列表 |
108
+ | `expected.output_matches` | 否 | 输出需匹配的正则表达式(单个字符串) |
109
+ | `expected.compare_files` | 否 | 文件比较断言列表,见下文 |
110
+
111
+ ### 文件比较断言(compare_files)
112
+
113
+ 在 `expected` 中通过 `compare_files` 可声明一条或多条文件比较规则,框架会在命令执行后自动用对应的比较器对比实际产出文件与基线文件。所有比较通过才算用例通过,可与 `return_code`、`output_contains` 等断言共存。
114
+
115
+ 每个比较规则的字段:
116
+
117
+ | 字段 | 必填 | 说明 |
118
+ |---|---|---|
119
+ | `actual` | 是 | 测试命令产出的文件路径(相对路径按 workspace 解析) |
120
+ | `baseline` | 是 | 基线/参考文件路径(相对路径按 workspace 解析) |
121
+ | `type` | 否 | 比较器类型:`text`、`json`、`csv`、`xml`、`h5`、`binary`;省略时按扩展名自动识别 |
122
+ | 其他 | 否 | 透传给对应比较器的参数,如 `rtol`、`atol`、`encoding`、`tables`、`data_filter` 等 |
123
+
124
+ ```json
125
+ "expected": {
126
+ "return_code": 0,
127
+ "compare_files": [
128
+ {
129
+ "actual": "result.h5",
130
+ "baseline": "baseline/result.h5",
131
+ "type": "h5",
132
+ "rtol": 1e-5,
133
+ "atol": 1e-8,
134
+ "tables": ["/stress", "/displacement"]
135
+ },
136
+ {
137
+ "actual": "summary.csv",
138
+ "baseline": "baseline/summary.csv"
139
+ }
140
+ ]
141
+ }
142
+ ```
91
143
 
92
144
  ## 运行测试
93
145
 
@@ -112,6 +164,13 @@ cli-test run test_cases.json --parallel --execution-mode process
112
164
  # 只运行指定用例
113
165
  cli-test run test_cases.json -t test_name_1 -t test_name_2
114
166
 
167
+ # 按标签过滤
168
+ cli-test run test_cases.json --tag smoke
169
+ cli-test run test_cases.json --tag smoke --tag regression
170
+
171
+ # 同时按名称和标签过滤(AND 关系)
172
+ cli-test run test_cases.json -t test_name_1 --tag smoke
173
+
115
174
  # 详细输出
116
175
  cli-test run test_cases.json --verbose
117
176
 
@@ -126,6 +185,9 @@ cli-test run test_cases.json --history-dir ./hist
126
185
 
127
186
  # 自定义回归检测阈值(默认 1.5 倍)
128
187
  cli-test run test_cases.json --history-dir ./hist --regression-threshold 2.0
188
+
189
+ # 输出 JUnit XML 报告(可供 Jenkins/GitLab CI 等工具解析)
190
+ cli-test run test_cases.json --junit-xml report.xml
129
191
  ```
130
192
 
131
193
  ### Python API
@@ -138,6 +200,7 @@ runner = JSONRunner(
138
200
  config_file="test_cases.json",
139
201
  workspace="/path/to/project", # 可选,默认项目根目录
140
202
  test_case_filter=["test_1"], # 可选,只运行指定用例
203
+ test_case_tag_filter=["smoke"], # 可选,只运行包含指定标签的用例
141
204
  history_dir="./hist", # 可选,启用历史记录与回归检测
142
205
  regression_threshold=2.0, # 可选,回归阈值倍数,默认 1.5
143
206
  )
@@ -146,7 +209,7 @@ success = runner.run_tests()
146
209
  # YAML 格式
147
210
  runner = YAMLRunner(config_file="test_cases.yaml")
148
211
 
149
- # 并行运行
212
+ # 并行运行(JSON)
150
213
  runner = ParallelJSONRunner(
151
214
  config_file="test_cases.json",
152
215
  max_workers=4, # 可选,默认 CPU 核心数
@@ -156,6 +219,15 @@ runner = ParallelJSONRunner(
156
219
  regression_threshold=2.0, # 可选,回归阈值倍数,默认 1.5
157
220
  )
158
221
  success = runner.run_tests()
222
+
223
+ # 并行运行(YAML)
224
+ from cli_test_framework.runners import ParallelYAMLRunner
225
+ runner = ParallelYAMLRunner(
226
+ config_file="test_cases.yaml",
227
+ max_workers=4,
228
+ execution_mode="thread",
229
+ )
230
+ success = runner.run_tests()
159
231
  ```
160
232
 
161
233
  ### 获取结果
@@ -164,7 +236,7 @@ success = runner.run_tests()
164
236
  runner.run_tests()
165
237
 
166
238
  # 汇总
167
- runner.results["total_tests"]
239
+ runner.results["total"]
168
240
  runner.results["passed"]
169
241
  runner.results["failed"]
170
242
 
@@ -173,6 +245,80 @@ for detail in runner.results["details"]:
173
245
  print(detail["name"], detail["status"], detail.get("message", ""))
174
246
  ```
175
247
 
248
+ ## 标签过滤
249
+
250
+ 通过标签(tags)可以对测试用例进行分类,并在运行时按标签批量过滤。标签过滤与名称过滤可同时使用,满足 AND 关系(两个条件都必须满足)。
251
+
252
+ ### 在测试用例中定义标签
253
+
254
+ JSON:
255
+
256
+ ```json
257
+ {
258
+ "test_cases": [
259
+ {
260
+ "name": "快速测试",
261
+ "command": "echo",
262
+ "args": ["hello"],
263
+ "tags": ["smoke", "fast"],
264
+ "expected": { "return_code": 0 }
265
+ },
266
+ {
267
+ "name": "完整回归测试",
268
+ "command": "python",
269
+ "args": ["long_test.py"],
270
+ "tags": ["regression", "slow"],
271
+ "expected": { "return_code": 0 }
272
+ }
273
+ ]
274
+ }
275
+ ```
276
+
277
+ YAML:
278
+
279
+ ```yaml
280
+ test_cases:
281
+ - name: 快速测试
282
+ command: echo
283
+ args: ["hello"]
284
+ tags: ["smoke", "fast"]
285
+ expected:
286
+ return_code: 0
287
+ ```
288
+
289
+ `tags` 是可选字段,不指定则默认为空列表。每个用例可以有多个标签。
290
+
291
+ ### 运行时过滤
292
+
293
+ ```bash
294
+ # 只运行带 "smoke" 标签的用例
295
+ cli-test run test_cases.json --tag smoke
296
+
297
+ # 运行带 "smoke" 或 "regression" 标签的用例(OR 关系)
298
+ cli-test run test_cases.json --tag smoke --tag regression
299
+
300
+ # 同时按名称和标签过滤(AND 关系)
301
+ cli-test run test_cases.json -t alpha --tag fast
302
+ ```
303
+
304
+ ### Python API
305
+
306
+ ```python
307
+ runner = JSONRunner(
308
+ config_file="test_cases.json",
309
+ test_case_tag_filter=["smoke"], # 只运行含 smoke 标签的用例
310
+ )
311
+ success = runner.run_tests()
312
+
313
+ # 结合名称过滤
314
+ runner = JSONRunner(
315
+ config_file="test_cases.json",
316
+ test_case_filter=["alpha", "beta"],
317
+ test_case_tag_filter=["fast"],
318
+ )
319
+ success = runner.run_tests()
320
+ ```
321
+
176
322
  ## Setup 模块
177
323
 
178
324
  Setup 模块在测试前执行初始化、测试后执行清理。
@@ -405,17 +551,108 @@ success = runner.run_tests()
405
551
 
406
552
  不传 `--history-dir` 时行为与之前完全一致,不创建任何额外文件。
407
553
 
408
- ### 命令行工具 `compare-files`
554
+ ## JUnit XML 报告
555
+
556
+ 通过 `--junit-xml` 可在运行测试的同时输出 JUnit 格式的 XML 报告,兼容 Jenkins、GitLab CI、CircleCI 等 CI 工具。
557
+
558
+ ### CLI 用法
409
559
 
410
560
  ```bash
561
+ cli-test run test_cases.json --junit-xml report.xml
562
+ ```
563
+
564
+ `--junit-xml` 是补充输出,与 `--output-format`(text/json/html)并存,不影响控制台报告。
565
+
566
+ ### Python API
567
+
568
+ ```python
569
+ from cli_test_framework import write_junit_xml
570
+
571
+ runner.run_tests()
572
+ write_junit_xml(runner.results, "report.xml", suite_name="my_suite")
573
+ ```
574
+
575
+ 状态映射:`passed` 记为通过;`failed`(断言失败)记为 failure;`timeout` 与执行错误记为 error。每个 testcase 元素附带命令输出与失败原因。
576
+
577
+ ## 日志配置
578
+
579
+ 框架所有诊断与状态信息都通过 Python 标准 `logging` 模块输出,统一挂在 `cli_test_framework` 命名空间下。日志默认写入 **stderr**,因此 `stdout` 始终保持干净,可安全配合 `--output-format json` 做机器可读输出。
580
+
581
+ ### 命令行控制日志级别
582
+
583
+ `run` 与 `compare` 子命令均支持:
584
+
585
+ | 选项 | 说明 |
586
+ |---|---|
587
+ | `--verbose` / `-v` | 详细输出,日志级别提升至 DEBUG |
588
+ | `--debug` | 调试模式,同样提升至 DEBUG,并在出错时打印完整堆栈 |
589
+
590
+ 默认级别为 INFO,仅显示关键进度与错误;加 `--verbose` 或 `--debug` 后会输出命令输出、调度细节等 DEBUG 级信息。
591
+
592
+ ```bash
593
+ # 详细模式(含命令输出等 DEBUG 信息)
594
+ cli-test run test_cases.json --verbose
595
+
596
+ # 调试模式(出错时打印堆栈)
597
+ cli-test run test_cases.json --debug
598
+ ```
599
+
600
+ ### 库使用方式
601
+
602
+ 作为库被 import 时,框架默认只挂载 `NullHandler`,不产生任何输出(符合库的礼貌日志规范)。需要看到日志时,调用 `setup_console_logging()` 启用控制台输出:
603
+
604
+ ```python
605
+ import logging
606
+ from cli_test_framework.logging_config import setup_console_logging, get_logger
607
+
608
+ # 启用控制台日志(stderr),可指定级别
609
+ setup_console_logging(level=logging.DEBUG)
610
+
611
+ logger = get_logger(__name__) # 自动归入 cli_test_framework 命名空间
612
+ logger.info("自定义日志信息")
613
+ ```
614
+
615
+ ### 输出到日志文件
616
+
617
+ 框架未内置 `--log-file` 选项,但可借助 Python 标准 `logging` 自行为 `cli_test_framework` logger 添加文件处理器:
618
+
619
+ ```python
620
+ import logging
621
+ from cli_test_framework.logging_config import get_logger
622
+
623
+ file_handler = logging.FileHandler("run.log", encoding="utf-8")
624
+ file_handler.setLevel(logging.DEBUG)
625
+ file_handler.setFormatter(
626
+ logging.Formatter("%(asctime)s %(levelname)-7s %(name)s %(message)s")
627
+ )
628
+
629
+ # 给框架根 logger 加文件处理器,所有子 logger 都会继承
630
+ logging.getLogger("cli_test_framework").addHandler(file_handler)
631
+ ```
632
+
633
+ 上述代码既适用于库调用,也可放在脚本中配合 `cli-test` 一起使用。控制台与文件处理器可并存。
634
+
635
+ ## 文件比较
636
+
637
+ 框架提供独立的文件比较能力,支持文本、JSON、CSV、XML、HDF5、二进制等多种格式。既可通过命令行工具使用,也可在测试用例的 `expected.compare_files` 中自动调用(见[文件比较断言](#文件比较断言compare_files))。
638
+
639
+ ### 命令行工具
640
+
641
+ 有两种等价的调用方式,参数完全一致:
642
+
643
+ ```bash
644
+ # 独立命令
411
645
  compare-files <file1> <file2> [选项]
646
+
647
+ # cli-test 子命令
648
+ cli-test compare <file1> <file2> [选项]
412
649
  ```
413
650
 
414
651
  ### 通用选项
415
652
 
416
653
  | 选项 | 说明 |
417
654
  |---|---|
418
- | `--file-type` | 文件类型:`auto`(默认)、`text`、`json`、`h5`、`binary` |
655
+ | `--file-type` | 文件类型:`auto`(默认)、`text`、`json`、`csv`、`xml`、`h5`、`binary` |
419
656
  | `--start-line` | 起始行号(1-based),默认 1 |
420
657
  | `--end-line` | 结束行号(1-based) |
421
658
  | `--start-column` | 起始列号(1-based),默认 1 |
@@ -447,6 +684,40 @@ compare-files data1.json data2.json --json-compare-mode key-based --json-key-fie
447
684
  | `--json-compare-mode` | `exact`(默认)或 `key-based` |
448
685
  | `--json-key-field` | key-based 模式的匹配字段,支持逗号分隔多字段 |
449
686
 
687
+ ### CSV 文件比较
688
+
689
+ ```bash
690
+ # 基本比较
691
+ compare-files data1.csv data2.csv
692
+
693
+ # 自定义分隔符与数值容差
694
+ compare-files data1.csv data2.csv --csv-delimiter ';' --csv-rtol 1e-4 --csv-atol 1e-6
695
+
696
+ # TSV 文件(自动识别为 csv 类型)
697
+ compare-files data1.tsv data2.tsv
698
+ ```
699
+
700
+ | 选项 | 说明 |
701
+ |---|---|
702
+ | `--csv-rtol` | 数值相对容差,默认 1e-5 |
703
+ | `--csv-atol` | 数值绝对容差,默认 1e-8 |
704
+ | `--csv-delimiter` | 字段分隔符,默认 `,` |
705
+ | `--csv-quotechar` | 引用字符,默认 `"` |
706
+
707
+ CSV 比较按行列结构逐单元格比对;数值单元格在容差范围内视为相等。差异报告包含行数、列数不匹配与单元格不一致,最多列出 10 条。
708
+
709
+ ### XML 文件比较
710
+
711
+ ```bash
712
+ # 结构化比较(标签、属性、文本、子元素)
713
+ compare-files config1.xml config2.xml
714
+
715
+ # HTML 文件(自动识别为 xml 类型)
716
+ compare-files page1.html page2.html
717
+ ```
718
+
719
+ XML 比较按 DOM 结构递归比对标签、属性、文本内容与子元素数量。差异报告定位到具体路径(如 `/root/item[0]/@id`),最多列出 10 条。
720
+
450
721
  ### HDF5 文件比较
451
722
 
452
723
  ```bash
@@ -506,6 +777,14 @@ result = comparator.compare_files("file1.txt", "file2.txt")
506
777
  comparator = ComparatorFactory.create_comparator("json", compare_mode="key-based", key_field="id")
507
778
  result = comparator.compare_files("data1.json", "data2.json")
508
779
 
780
+ # CSV 比较
781
+ comparator = ComparatorFactory.create_comparator("csv", rtol=1e-5, atol=1e-8, delimiter=",")
782
+ result = comparator.compare_files("data1.csv", "data2.csv")
783
+
784
+ # XML 比较
785
+ comparator = ComparatorFactory.create_comparator("xml", encoding="utf-8")
786
+ result = comparator.compare_files("config1.xml", "config2.xml")
787
+
509
788
  # HDF5 比较
510
789
  comparator = ComparatorFactory.create_comparator("h5", tables=["table1"], rtol=1e-5)
511
790
  result = comparator.compare_files("data1.h5", "data2.h5")
@@ -520,7 +799,7 @@ result.differences # list
520
799
  ### 自定义 Runner
521
800
 
522
801
  ```python
523
- from cli_test_framework.runners import BaseRunner
802
+ from cli_test_framework.core.base_runner import BaseRunner
524
803
 
525
804
  class CustomRunner(BaseRunner):
526
805
  def load_test_cases(self):
@@ -546,13 +825,81 @@ class MySetup(BaseSetup):
546
825
  pass
547
826
  ```
548
827
 
549
- ### 自定义断言
828
+ ### 自定义文件比较器
829
+
830
+ `ComparatorFactory` 会在首次使用时自动扫描 `file_comparator` 包内所有 `*_comparator.py` 模块并注册其中的 `*Comparator` 类。如需注册自定义比较器,调用 `register_comparator` 即可:
550
831
 
551
832
  ```python
552
- from cli_test_framework.assertions import BaseAssertion
833
+ from cli_test_framework.file_comparator import ComparatorFactory
834
+ from cli_test_framework.file_comparator.base_comparator import BaseComparator
835
+
836
+ class FooComparator(BaseComparator):
837
+ # 实现 read_content / compare_content 等方法
838
+ pass
839
+
840
+ ComparatorFactory.register_comparator("foo", FooComparator)
841
+
842
+ # 之后即可在 compare_files 断言或命令行 --file-type foo 中使用
843
+ comparator = ComparatorFactory.create_comparator("foo")
844
+ ```
553
845
 
554
- class CustomAssertion(BaseAssertion):
555
- def assert_custom_condition(self, actual, expected):
556
- if not self._check(actual, expected):
557
- raise AssertionError("Condition not met")
846
+ ### 断言与文件比较
847
+
848
+ `Assertions` 类提供静态断言方法,`expected` 中的校验均由其完成:
849
+
850
+ ```python
851
+ from cli_test_framework.core.assertions import Assertions
852
+
853
+ Assertions.return_code_equals(actual_code, 0)
854
+ Assertions.contains(output, "expected text")
855
+ Assertions.matches(output, r".*regex.*")
856
+ Assertions.compare_files("actual.txt", "baseline.txt", file_type="text", workspace="/ws")
857
+ ```
858
+
859
+ `compare_files` 会自动按扩展名识别类型(`.h5/.hdf5/.hdf`→h5、`.json`→json、`.csv/.tsv`→csv、`.xml/.html/.htm`→xml、`.txt/.log/.out/.py`→text、其余→binary),相对路径按 `workspace` 解析,额外参数透传给比较器。
860
+
861
+ ## 运行框架自带测试
862
+
863
+ 项目自带统一测试入口 `tests/run_all.py`,通过 `--scope` 选择测试范围(test target),并可用 `--extra` 透传任意 pytest 参数。
864
+
865
+ ### 测试范围
866
+
867
+ | scope | 说明 | 对应目录 |
868
+ |---|---|---|
869
+ | `unit` | 单元测试(core、runners 等) | `tests/unit` |
870
+ | `integration` | 集成测试(文件比较、并行、路径处理等) | `tests/integration` |
871
+ | `e2e` | 端到端测试(用户流程) | `tests/e2e` |
872
+ | `all` | 运行上述全部范围(默认) | 三者合集 |
873
+
874
+ > 注:`tests/demos/` 下的脚本为手动/交互演示,不纳入 scope 运行,需单独执行。
875
+
876
+ ### 用法
877
+
878
+ ```bash
879
+ # 运行全部测试(默认)
880
+ python tests/run_all.py
881
+
882
+ # 只运行单元测试
883
+ python tests/run_all.py --scope unit
884
+
885
+ # 只运行集成测试
886
+ python tests/run_all.py --scope integration
887
+
888
+ # 只运行端到端测试
889
+ python tests/run_all.py --scope e2e
890
+
891
+ # 透传 pytest 参数,例如按关键字过滤
892
+ python tests/run_all.py --scope integration --extra "-k h5"
893
+
894
+ # 透传多个 pytest 参数
895
+ python tests/run_all.py --scope unit --extra "-v -k assertions"
896
+ ```
897
+
898
+ `--extra` 接收的字符串会经 `shlex` 拆分后追加到 pytest 命令行。脚本通过当前解释器(`sys.executable -m pytest`)调用 pytest,确保使用激活的环境而非 PATH 中首个 `pytest`。
899
+
900
+ 测试环境需先激活 conda 环境:
901
+
902
+ ```bash
903
+ conda activate xiaotong
904
+ python tests/run_all.py
558
905
  ```
@@ -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.8.0",
11
+ version="0.9.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.",
@@ -51,6 +51,8 @@ Examples:
51
51
  help='Output format for test results')
52
52
  run_parser.add_argument('--test-case', '-t', action='append', default=None,
53
53
  help='Run only specified test case(s) by name (can be used multiple times)')
54
+ run_parser.add_argument('--tag', action='append', default=None,
55
+ help='Run only test cases with matching tag(s) (can be used multiple times)')
54
56
  run_parser.add_argument('--history-dir',
55
57
  help='Directory for .symtest runtime history (enables smart scheduling & regression detection)')
56
58
  run_parser.add_argument('--regression-threshold', type=float, default=1.5,
@@ -145,6 +147,7 @@ def run_tests(args):
145
147
  max_workers=args.workers,
146
148
  execution_mode=args.execution_mode,
147
149
  test_case_filter=args.test_case,
150
+ test_case_tag_filter=args.tag,
148
151
  history_dir=history_dir,
149
152
  regression_threshold=regression_threshold,
150
153
  )
@@ -155,6 +158,7 @@ def run_tests(args):
155
158
  max_workers=args.workers,
156
159
  execution_mode=args.execution_mode,
157
160
  test_case_filter=args.test_case,
161
+ test_case_tag_filter=args.tag,
158
162
  history_dir=history_dir,
159
163
  regression_threshold=regression_threshold,
160
164
  )
@@ -168,6 +172,7 @@ def run_tests(args):
168
172
  config_file=str(config_file),
169
173
  workspace=args.workspace,
170
174
  test_case_filter=args.test_case,
175
+ test_case_tag_filter=args.tag,
171
176
  history_dir=history_dir,
172
177
  regression_threshold=regression_threshold,
173
178
  )
@@ -176,6 +181,7 @@ def run_tests(args):
176
181
  config_file=str(config_file),
177
182
  workspace=args.workspace,
178
183
  test_case_filter=args.test_case,
184
+ test_case_tag_filter=args.tag,
179
185
  history_dir=history_dir,
180
186
  regression_threshold=regression_threshold,
181
187
  )