symtest-cli 1.3.3__tar.gz → 1.4.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 (391) hide show
  1. {symtest_cli-1.3.3/src/symtest_cli.egg-info → symtest_cli-1.4.0}/PKG-INFO +1 -1
  2. symtest_cli-1.4.0/docs/design.md +388 -0
  3. symtest_cli-1.4.0/docs/design_1_4.md +305 -0
  4. symtest_cli-1.4.0/docs/design_en.md +414 -0
  5. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/docs/user_manual.md +179 -128
  6. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/docs/user_manual_en.md +179 -128
  7. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/__init__.py +2 -2
  8. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/cli.py +30 -0
  9. symtest_cli-1.4.0/src/symtest/commands/migrate.py +63 -0
  10. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/config/config_io.py +40 -16
  11. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/config/config_schema.py +92 -71
  12. symtest_cli-1.4.0/src/symtest/config/migrate.py +95 -0
  13. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/core/__init__.py +1 -1
  14. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/core/base_runner.py +2 -3
  15. symtest_cli-1.4.0/src/symtest/core/config_loader.py +204 -0
  16. symtest_cli-1.4.0/src/symtest/core/execution/__init__.py +16 -0
  17. symtest_cli-1.4.0/src/symtest/core/execution/executor.py +153 -0
  18. symtest_cli-1.4.0/src/symtest/core/execution/result.py +24 -0
  19. symtest_cli-1.4.0/src/symtest/core/orchestration/__init__.py +17 -0
  20. symtest_cli-1.4.0/src/symtest/core/orchestration/accept.py +91 -0
  21. symtest_cli-1.3.3/src/symtest/core/config_loader.py → symtest_cli-1.4.0/src/symtest/core/orchestration/sequence.py +91 -219
  22. symtest_cli-1.4.0/src/symtest/core/orchestration/single.py +187 -0
  23. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/core/parallel_runner.py +7 -42
  24. symtest_cli-1.4.0/src/symtest/core/process_worker.py +109 -0
  25. symtest_cli-1.4.0/src/symtest/core/result.py +68 -0
  26. symtest_cli-1.4.0/src/symtest/core/test_case.py +290 -0
  27. symtest_cli-1.4.0/src/symtest/core/validation/__init__.py +15 -0
  28. {symtest_cli-1.3.3/src/symtest/core → symtest_cli-1.4.0/src/symtest/core/validation}/assertions.py +18 -29
  29. symtest_cli-1.4.0/src/symtest/core/validation/result.py +19 -0
  30. symtest_cli-1.4.0/src/symtest/core/validation/validator.py +199 -0
  31. symtest_cli-1.4.0/src/symtest/reporting/__init__.py +10 -0
  32. symtest_cli-1.4.0/src/symtest/reporting/diagnosis.py +84 -0
  33. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/runners/config_runner.py +5 -4
  34. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/runners/parallel_config_runner.py +7 -5
  35. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/tui/controllers/case_controller.py +10 -6
  36. {symtest_cli-1.3.3 → symtest_cli-1.4.0/src/symtest_cli.egg-info}/PKG-INFO +1 -1
  37. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest_cli.egg-info/SOURCES.txt +41 -2
  38. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/e2e/test_user_flows.py +12 -6
  39. symtest_cli-1.4.0/tests/fixtures/inheritance_base.json +33 -0
  40. symtest_cli-1.4.0/tests/fixtures/inheritance_chain.json +41 -0
  41. symtest_cli-1.4.0/tests/fixtures/main_config.json +26 -0
  42. symtest_cli-1.4.0/tests/fixtures/migration/v1/circular_config_a.json +7 -0
  43. symtest_cli-1.4.0/tests/fixtures/migration/v1/circular_config_b.json +7 -0
  44. symtest_cli-1.4.0/tests/fixtures/migration/v1/inheritance_circular.json +16 -0
  45. symtest_cli-1.4.0/tests/fixtures/migration/v1/skill_test_cases_golden_file.json +33 -0
  46. symtest_cli-1.4.0/tests/fixtures/migration/v1/skill_test_cases_simple.json +16 -0
  47. symtest_cli-1.4.0/tests/fixtures/migration/v1/skill_test_cases_simple.yaml +11 -0
  48. symtest_cli-1.4.0/tests/fixtures/migration/v1/skill_test_cases_steps.json +29 -0
  49. symtest_cli-1.4.0/tests/fixtures/missing_fields.json +26 -0
  50. symtest_cli-1.4.0/tests/fixtures/setup_main.json +13 -0
  51. symtest_cli-1.4.0/tests/fixtures/setup_sub.json +20 -0
  52. symtest_cli-1.4.0/tests/fixtures/sub_json_tests.yaml +29 -0
  53. symtest_cli-1.4.0/tests/fixtures/sub_text_tests.json +26 -0
  54. symtest_cli-1.4.0/tests/fixtures/test_cases.json +69 -0
  55. symtest_cli-1.4.0/tests/fixtures/test_cases.yaml +11 -0
  56. symtest_cli-1.4.0/tests/fixtures/test_cases1.json +212 -0
  57. symtest_cli-1.4.0/tests/fixtures/test_with_setup.json +48 -0
  58. symtest_cli-1.4.0/tests/fixtures/test_with_setup.yaml +45 -0
  59. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/parallel/test_depends_on.py +41 -33
  60. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/parallel/test_parallel_runner.py +12 -12
  61. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/path_handling/test_spaces_in_paths.py +19 -14
  62. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/test_history_feature.py +8 -10
  63. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/test_new_cli_features.py +28 -10
  64. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/test_real_command_execution.py +17 -9
  65. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/test_sequence.py +56 -42
  66. symtest_cli-1.4.0/tests/unit/core/test_architecture_guard.py +106 -0
  67. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/test_assertions.py +45 -40
  68. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/test_case_env.py +68 -51
  69. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/test_config_loader.py +134 -78
  70. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/test_config_loader_new_features.py +53 -50
  71. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/test_execution.py +22 -26
  72. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/test_execution_new_features.py +61 -77
  73. symtest_cli-1.4.0/tests/unit/core/test_model_v2.py +310 -0
  74. symtest_cli-1.4.0/tests/unit/core/test_orchestration_accept.py +183 -0
  75. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/test_process_worker.py +45 -45
  76. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/test_setup.py +6 -6
  77. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/test_validation_error.py +74 -63
  78. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/test_json_yaml_runner.py +6 -6
  79. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/test_test_case_filter.py +6 -6
  80. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/test_test_case_tag_filter.py +9 -9
  81. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/test_config_io.py +36 -21
  82. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/test_import_expander.py +2 -2
  83. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/test_inheritance_expander.py +4 -4
  84. symtest_cli-1.4.0/tests/unit/test_migrate.py +295 -0
  85. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/conftest.py +8 -8
  86. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/test_case_controller.py +27 -19
  87. symtest_cli-1.3.3/docs/design.md +0 -840
  88. symtest_cli-1.3.3/docs/design_en.md +0 -838
  89. symtest_cli-1.3.3/src/symtest/core/execution.py +0 -508
  90. symtest_cli-1.3.3/src/symtest/core/process_worker.py +0 -95
  91. symtest_cli-1.3.3/src/symtest/core/test_case.py +0 -121
  92. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/LICENSE +0 -0
  93. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/MANIFEST.in +0 -0
  94. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/README.md +0 -0
  95. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/docs/tui_and_config_split_design.md +0 -0
  96. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/pyproject.toml +0 -0
  97. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/setup.cfg +0 -0
  98. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/setup.py +0 -0
  99. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/commands/__init__.py +0 -0
  100. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/commands/compare.py +0 -0
  101. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/config/__init__.py +0 -0
  102. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/config/import_expander.py +0 -0
  103. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/config/inheritance_expander.py +0 -0
  104. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/core/history_store.py +0 -0
  105. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/core/last_run_store.py +0 -0
  106. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/core/sequence_state.py +0 -0
  107. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/core/setup.py +0 -0
  108. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/core/types.py +0 -0
  109. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/file_comparator/__init__.py +0 -0
  110. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/file_comparator/base_comparator.py +0 -0
  111. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/file_comparator/binary_comparator.py +0 -0
  112. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/file_comparator/csv_comparator.py +0 -0
  113. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/file_comparator/factory.py +0 -0
  114. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/file_comparator/h5_comparator.py +0 -0
  115. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/file_comparator/json_comparator.py +0 -0
  116. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/file_comparator/numeric_compare.py +0 -0
  117. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/file_comparator/result.py +0 -0
  118. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/file_comparator/script_comparator.py +0 -0
  119. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/file_comparator/text_comparator.py +0 -0
  120. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/file_comparator/xml_comparator.py +0 -0
  121. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/logging_config.py +0 -0
  122. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/runners/__init__.py +0 -0
  123. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/runners/json_runner.py +0 -0
  124. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/runners/parallel_json_runner.py +0 -0
  125. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/runners/parallel_yaml_runner.py +0 -0
  126. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/runners/yaml_runner.py +0 -0
  127. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/tui/__init__.py +0 -0
  128. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/tui/app.py +0 -0
  129. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/tui/controllers/__init__.py +0 -0
  130. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/tui/screens/__init__.py +0 -0
  131. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/tui/screens/case_editor.py +0 -0
  132. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/tui/screens/case_list.py +0 -0
  133. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/tui/widgets/__init__.py +0 -0
  134. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/tui/widgets/case_table.py +0 -0
  135. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/tui/widgets/expected_editor.py +0 -0
  136. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/tui/widgets/search_bar.py +0 -0
  137. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/tui/widgets/steps_editor.py +0 -0
  138. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/utils/__init__.py +0 -0
  139. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/utils/junit_xml_writer.py +0 -0
  140. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/utils/path_resolver.py +0 -0
  141. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest/utils/report_generator.py +0 -0
  142. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest_cli.egg-info/dependency_links.txt +0 -0
  143. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest_cli.egg-info/entry_points.txt +0 -0
  144. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest_cli.egg-info/requires.txt +0 -0
  145. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/src/symtest_cli.egg-info/top_level.txt +0 -0
  146. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/README.md +0 -0
  147. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/__init__.py +0 -0
  148. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/__pycache__/__init__.cpython-312.pyc +0 -0
  149. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/__pycache__/__init__.cpython-313.pyc +0 -0
  150. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/__pycache__/__init__.cpython-39.pyc +0 -0
  151. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
  152. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
  153. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc +0 -0
  154. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/__pycache__/conftest.cpython-39-pytest-8.3.4.pyc +0 -0
  155. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/__pycache__/run_all.cpython-312.pyc +0 -0
  156. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/__pycache__/run_all.cpython-313.pyc +0 -0
  157. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/__pycache__/run_all.cpython-39.pyc +0 -0
  158. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/__pycache__/test_setup_module.cpython-312-pytest-7.4.4.pyc +0 -0
  159. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/conftest.py +0 -0
  160. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/demos/h5_filter_demo.py +0 -0
  161. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/demos/manual_report_example.py +0 -0
  162. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/demos/perf_parallel.py +0 -0
  163. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/e2e/__init__.py +0 -0
  164. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/e2e/__pycache__/__init__.cpython-312.pyc +0 -0
  165. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/e2e/__pycache__/__init__.cpython-313.pyc +0 -0
  166. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/e2e/__pycache__/__init__.cpython-39.pyc +0 -0
  167. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-7.4.4.pyc +0 -0
  168. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-9.0.3.pyc +0 -0
  169. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/e2e/__pycache__/test_user_flows.cpython-313-pytest-9.0.2.pyc +0 -0
  170. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/e2e/__pycache__/test_user_flows.cpython-39-pytest-8.3.4.pyc +0 -0
  171. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/fixtures/circular_config_a.json +0 -0
  172. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/fixtures/circular_config_b.json +0 -0
  173. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/fixtures/hourglass_stdout_mismatch.txt +0 -0
  174. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/fixtures/hourglass_stdout_sample.txt +0 -0
  175. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/fixtures/inheritance_circular.json +0 -0
  176. {symtest_cli-1.3.3/tests/fixtures → symtest_cli-1.4.0/tests/fixtures/migration/v1}/inheritance_base.json +0 -0
  177. {symtest_cli-1.3.3/tests/fixtures → symtest_cli-1.4.0/tests/fixtures/migration/v1}/inheritance_chain.json +0 -0
  178. {symtest_cli-1.3.3/tests/fixtures → symtest_cli-1.4.0/tests/fixtures/migration/v1}/main_config.json +0 -0
  179. {symtest_cli-1.3.3/tests/fixtures → symtest_cli-1.4.0/tests/fixtures/migration/v1}/missing_fields.json +0 -0
  180. {symtest_cli-1.3.3/tests/fixtures → symtest_cli-1.4.0/tests/fixtures/migration/v1}/setup_main.json +0 -0
  181. {symtest_cli-1.3.3/tests/fixtures → symtest_cli-1.4.0/tests/fixtures/migration/v1}/setup_sub.json +0 -0
  182. {symtest_cli-1.3.3/tests/fixtures → symtest_cli-1.4.0/tests/fixtures/migration/v1}/sub_json_tests.yaml +0 -0
  183. {symtest_cli-1.3.3/tests/fixtures → symtest_cli-1.4.0/tests/fixtures/migration/v1}/sub_text_tests.json +0 -0
  184. {symtest_cli-1.3.3/tests/fixtures → symtest_cli-1.4.0/tests/fixtures/migration/v1}/test_cases.json +0 -0
  185. {symtest_cli-1.3.3/tests/fixtures → symtest_cli-1.4.0/tests/fixtures/migration/v1}/test_cases.yaml +0 -0
  186. {symtest_cli-1.3.3/tests/fixtures → symtest_cli-1.4.0/tests/fixtures/migration/v1}/test_cases1.json +0 -0
  187. {symtest_cli-1.3.3/tests/fixtures → symtest_cli-1.4.0/tests/fixtures/migration/v1}/test_with_setup.json +0 -0
  188. {symtest_cli-1.3.3/tests/fixtures → symtest_cli-1.4.0/tests/fixtures/migration/v1}/test_with_setup.yaml +0 -0
  189. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/fixtures/mock_fail_script.py +0 -0
  190. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/fixtures/mock_pass_script.py +0 -0
  191. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-7.4.4.pyc +0 -0
  192. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-9.0.3.pyc +0 -0
  193. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/__pycache__/test_history_feature.cpython-313-pytest-9.0.2.pyc +0 -0
  194. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/__pycache__/test_new_cli_features.cpython-312-pytest-7.4.4.pyc +0 -0
  195. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/__pycache__/test_new_cli_features.cpython-312-pytest-9.0.3.pyc +0 -0
  196. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/__pycache__/test_new_cli_features.cpython-313-pytest-9.0.2.pyc +0 -0
  197. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-7.4.4.pyc +0 -0
  198. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-9.0.3.pyc +0 -0
  199. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/__pycache__/test_real_command_execution.cpython-313-pytest-9.0.2.pyc +0 -0
  200. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-7.4.4.pyc +0 -0
  201. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-9.0.3.pyc +0 -0
  202. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/__pycache__/test_sequence.cpython-313-pytest-9.0.2.pyc +0 -0
  203. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  204. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  205. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  206. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  207. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  208. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  209. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  210. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  211. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  212. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  213. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  214. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  215. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  216. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  217. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  218. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  219. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  220. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  221. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  222. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  223. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  224. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  225. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/test_binary_compare.py +0 -0
  226. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/test_csv_compare.py +0 -0
  227. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/test_h5_compare.py +0 -0
  228. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/test_json_compare.py +0 -0
  229. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/test_text_compare.py +0 -0
  230. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/file_compare/test_xml_compare.py +0 -0
  231. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/parallel/__pycache__/test_depends_on.cpython-312-pytest-7.4.4.pyc +0 -0
  232. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/parallel/__pycache__/test_depends_on.cpython-312-pytest-9.0.3.pyc +0 -0
  233. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  234. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-9.0.3.pyc +0 -0
  235. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-313-pytest-9.0.2.pyc +0 -0
  236. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-39-pytest-8.3.4.pyc +0 -0
  237. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-7.4.4.pyc +0 -0
  238. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-9.0.3.pyc +0 -0
  239. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-313-pytest-9.0.2.pyc +0 -0
  240. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-39-pytest-8.3.4.pyc +0 -0
  241. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/run_all.py +0 -0
  242. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_binary_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  243. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_binary_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  244. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_binary_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
  245. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_cli.cpython-312-pytest-7.4.4.pyc +0 -0
  246. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_cli.cpython-312-pytest-9.0.3.pyc +0 -0
  247. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_cli.cpython-313-pytest-9.0.2.pyc +0 -0
  248. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_config_io.cpython-312-pytest-7.4.4.pyc +0 -0
  249. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_config_io.cpython-312-pytest-9.0.3.pyc +0 -0
  250. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_config_io.cpython-313-pytest-9.0.2.pyc +0 -0
  251. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  252. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  253. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_h5_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
  254. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-7.4.4.pyc +0 -0
  255. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-9.0.3.pyc +0 -0
  256. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_import_expander.cpython-313-pytest-9.0.2.pyc +0 -0
  257. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_inheritance_expander.cpython-312-pytest-7.4.4.pyc +0 -0
  258. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_inheritance_expander.cpython-312-pytest-9.0.3.pyc +0 -0
  259. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_inheritance_expander.cpython-313-pytest-9.0.2.pyc +0 -0
  260. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_migrate.cpython-312-pytest-7.4.4.pyc +0 -0
  261. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_result.cpython-312-pytest-7.4.4.pyc +0 -0
  262. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_result.cpython-312-pytest-9.0.3.pyc +0 -0
  263. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_result.cpython-313-pytest-9.0.2.pyc +0 -0
  264. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-7.4.4.pyc +0 -0
  265. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-9.0.3.pyc +0 -0
  266. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/__pycache__/test_run_all.cpython-313-pytest-9.0.2.pyc +0 -0
  267. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-7.4.4.pyc +0 -0
  268. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-9.0.3.pyc +0 -0
  269. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/commands/__pycache__/test_compare_command.cpython-313-pytest-9.0.2.pyc +0 -0
  270. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/commands/test_compare_command.py +0 -0
  271. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_architecture_guard.cpython-312-pytest-7.4.4.pyc +0 -0
  272. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_architecture_guard.cpython-312-pytest-9.0.3.pyc +0 -0
  273. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-7.4.4.pyc +0 -0
  274. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-9.0.3.pyc +0 -0
  275. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_assertions.cpython-313-pytest-9.0.2.pyc +0 -0
  276. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_case_env.cpython-312-pytest-7.4.4.pyc +0 -0
  277. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_case_env.cpython-312-pytest-9.0.3.pyc +0 -0
  278. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-7.4.4.pyc +0 -0
  279. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc +0 -0
  280. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_config_loader.cpython-313-pytest-9.0.2.pyc +0 -0
  281. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-312-pytest-7.4.4.pyc +0 -0
  282. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-312-pytest-9.0.3.pyc +0 -0
  283. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-313-pytest-9.0.2.pyc +0 -0
  284. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-7.4.4.pyc +0 -0
  285. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-9.0.3.pyc +0 -0
  286. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_execution.cpython-312.pyc +0 -0
  287. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_execution.cpython-313-pytest-9.0.2.pyc +0 -0
  288. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_execution_new_features.cpython-312-pytest-7.4.4.pyc +0 -0
  289. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_execution_new_features.cpython-312-pytest-9.0.3.pyc +0 -0
  290. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_execution_new_features.cpython-313-pytest-9.0.2.pyc +0 -0
  291. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-7.4.4.pyc +0 -0
  292. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-9.0.3.pyc +0 -0
  293. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_history_store.cpython-313-pytest-9.0.2.pyc +0 -0
  294. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_last_run_store.cpython-312-pytest-7.4.4.pyc +0 -0
  295. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_last_run_store.cpython-312-pytest-9.0.3.pyc +0 -0
  296. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_last_run_store.cpython-313-pytest-9.0.2.pyc +0 -0
  297. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_model_v2.cpython-312-pytest-7.4.4.pyc +0 -0
  298. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_model_v2.cpython-312-pytest-9.0.3.pyc +0 -0
  299. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_orchestration_accept.cpython-312-pytest-7.4.4.pyc +0 -0
  300. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_orchestration_accept.cpython-312-pytest-9.0.3.pyc +0 -0
  301. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-7.4.4.pyc +0 -0
  302. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-9.0.3.pyc +0 -0
  303. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_process_worker.cpython-313-pytest-9.0.2.pyc +0 -0
  304. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_sequence_state.cpython-312-pytest-7.4.4.pyc +0 -0
  305. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_sequence_state.cpython-312-pytest-9.0.3.pyc +0 -0
  306. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-7.4.4.pyc +0 -0
  307. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-9.0.3.pyc +0 -0
  308. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_setup.cpython-313-pytest-9.0.2.pyc +0 -0
  309. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_setup.cpython-39-pytest-8.3.4.pyc +0 -0
  310. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_validation_error.cpython-312-pytest-7.4.4.pyc +0 -0
  311. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_validation_error.cpython-312-pytest-9.0.3.pyc +0 -0
  312. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_validation_error.cpython-313-pytest-9.0.2.pyc +0 -0
  313. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_xfail.cpython-312-pytest-7.4.4.pyc +0 -0
  314. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_xfail.cpython-312-pytest-9.0.3.pyc +0 -0
  315. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/__pycache__/test_xfail.cpython-313-pytest-9.0.2.pyc +0 -0
  316. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/test_history_store.py +0 -0
  317. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/test_last_run_store.py +0 -0
  318. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/test_sequence_state.py +0 -0
  319. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/core/test_xfail.py +0 -0
  320. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/__init__.cpython-312.pyc +0 -0
  321. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-312-pytest-7.4.4.pyc +0 -0
  322. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-312-pytest-9.0.3.pyc +0 -0
  323. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-313-pytest-9.0.2.pyc +0 -0
  324. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  325. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  326. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
  327. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_numeric_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  328. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_numeric_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  329. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_numeric_parity.cpython-312-pytest-7.4.4.pyc +0 -0
  330. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_numeric_parity.cpython-312-pytest-9.0.3.pyc +0 -0
  331. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  332. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  333. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
  334. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-312-pytest-7.4.4.pyc +0 -0
  335. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-312-pytest-9.0.3.pyc +0 -0
  336. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-313-pytest-9.0.2.pyc +0 -0
  337. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/test_error_analysis.py +0 -0
  338. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/test_hourglass_tangent_comparator.py +0 -0
  339. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/test_numeric_compare.py +0 -0
  340. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/test_numeric_parity.py +0 -0
  341. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/test_script_comparator.py +0 -0
  342. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/file_comparator/test_workspace_plugins.py +0 -0
  343. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  344. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-9.0.3.pyc +0 -0
  345. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312.pyc +0 -0
  346. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-313-pytest-9.0.2.pyc +0 -0
  347. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-39-pytest-8.3.4.pyc +0 -0
  348. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-7.4.4.pyc +0 -0
  349. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-9.0.3.pyc +0 -0
  350. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-313-pytest-9.0.2.pyc +0 -0
  351. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-312-pytest-7.4.4.pyc +0 -0
  352. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-312-pytest-9.0.3.pyc +0 -0
  353. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-313-pytest-9.0.2.pyc +0 -0
  354. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/test_binary_comparator.py +0 -0
  355. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/test_cli.py +0 -0
  356. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/test_h5_comparator.py +0 -0
  357. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/test_result.py +0 -0
  358. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/test_run_all.py +0 -0
  359. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__init__.py +0 -0
  360. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/__init__.cpython-312.pyc +0 -0
  361. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/__init__.cpython-313.pyc +0 -0
  362. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
  363. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
  364. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc +0 -0
  365. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-7.4.4.pyc +0 -0
  366. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-9.0.3.pyc +0 -0
  367. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_app.cpython-313-pytest-9.0.2.pyc +0 -0
  368. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-7.4.4.pyc +0 -0
  369. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-9.0.3.pyc +0 -0
  370. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_case_controller.cpython-313-pytest-9.0.2.pyc +0 -0
  371. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-7.4.4.pyc +0 -0
  372. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-9.0.3.pyc +0 -0
  373. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_search_functions.cpython-313-pytest-9.0.2.pyc +0 -0
  374. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_tui_run_test.cpython-312-pytest-7.4.4.pyc +0 -0
  375. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_tui_run_test.cpython-312-pytest-9.0.3.pyc +0 -0
  376. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_tui_run_test.cpython-313-pytest-9.0.2.pyc +0 -0
  377. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-7.4.4.pyc +0 -0
  378. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-9.0.3.pyc +0 -0
  379. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/__pycache__/test_widgets_data.cpython-313-pytest-9.0.2.pyc +0 -0
  380. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/test_app.py +0 -0
  381. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/test_search_functions.py +0 -0
  382. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/test_tui_run_test.py +0 -0
  383. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/tui/test_widgets_data.py +0 -0
  384. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-7.4.4.pyc +0 -0
  385. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-9.0.3.pyc +0 -0
  386. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-313-pytest-9.0.2.pyc +0 -0
  387. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-7.4.4.pyc +0 -0
  388. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-9.0.3.pyc +0 -0
  389. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/utils/__pycache__/test_report_generator.cpython-313-pytest-9.0.2.pyc +0 -0
  390. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/utils/test_junit_xml_writer.py +0 -0
  391. {symtest_cli-1.3.3 → symtest_cli-1.4.0}/tests/unit/utils/test_report_generator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: symtest-cli
3
- Version: 1.3.3
3
+ Version: 1.4.0
4
4
  Summary: Regression testing for CLI applications, with multi-step workflows and numerical file comparison.
5
5
  Home-page: https://github.com/ozil111/symtest-cli
6
6
  Author: Xiaotong Wang
@@ -0,0 +1,388 @@
1
+ # CLI Test Framework 设计文档
2
+
3
+ > **维护原则(单一事实来源)**:本文档不镜像代码结构——不再维护目录树、类签名、
4
+ > 函数清单、dataclass 字段定义等会随代码漂移的内容。目录结构与 API 以
5
+ > `src/symtest/` 源码及其 docstring 为准,用法示例见 `examples/`。
6
+ > 本文档只承载代码里读不出来的设计信息:架构分层、职责边界、关键流程语义、
7
+ > 扩展契约、设计决策与核心架构宪法。
8
+
9
+ ## 1. 架构总览
10
+
11
+ ```
12
+ ┌─────────────────────────────────────────────────────────────┐
13
+ │ CLI 入口层 symtest run / tui / validate / schema / │
14
+ │ compare-files(+ TUI 交互界面) │
15
+ └───────────────────────────┬─────────────────────────────────┘
16
+ ▼
17
+ ┌─────────────────────────────────────────────────────────────┐
18
+ │ 业务层 Runners(顺序 / 并行 / DAG / 资源感知) │
19
+ │ File Comparators(多类型 + 插件) │
20
+ └───────────────────────────┬─────────────────────────────────┘
21
+ ▼
22
+ ┌─────────────────────────────────────────────────────────────┐
23
+ │ 配置管线 raw JSON/YAML → expand_imports │
24
+ │ → resolve_inheritance → apply_variables │
25
+ │ → substitute_placeholders → parse_test_cases │
26
+ └───────────────────────────┬─────────────────────────────────┘
27
+ ▼
28
+ ┌─────────────────────────────────────────────────────────────┐
29
+ │ Core 层 TestCase 模型 · 断言引擎 · 单测试执行 │
30
+ │ Runner 基类 · Setup 插件 · .symtest 状态存储 │
31
+ │ 路径解析 · 报告生成 · JUnit XML │
32
+ └─────────────────────────────────────────────────────────────┘
33
+ ```
34
+
35
+ 框架分为四层:**CLI 入口层**(含 TUI)、**Runner / Comparator 业务层**、**Config 管线层**、**Core 基础层**。
36
+
37
+ 层与层不是自由组合:跨层数据流与依赖方向受 §10「核心架构宪法」约束,
38
+ 新增 feature 请先对照宪法确定归属。
39
+
40
+ ## 2. 模块地图
41
+
42
+ 以包为单位的职责划分(文件级明细与公开 API 以源码为准):
43
+
44
+ | 包 | 职责 |
45
+ |---|---|
46
+ | `cli.py` / `commands/` | 子命令入口、参数装配与日志激活 |
47
+ | `core/` | TestCase 数据模型、断言引擎、单测试执行、Runner 基类(顺序 / 并行 / DAG)、`.symtest` 状态存储、Setup 插件体系 |
48
+ | `config/` | 配置 IO、JSON Schema 校验(draft 2020-12)、import 展开、extends 继承、变量与占位符替换 |
49
+ | `runners/` | Config/JSON/YAML × 顺序/并行 的薄封装运行器 |
50
+ | `file_comparator/` | 比较器家族 + 工厂 + workspace 插件发现(详见 §6) |
51
+ | `utils/` | 路径解析、报告生成、JUnit XML 输出 |
52
+ | `tui/` | Textual 交互式用例管理(详见 §7) |
53
+
54
+ ### 2.1 入口点
55
+
56
+ | 命令 | 映射 |
57
+ |---|---|
58
+ | `symtest run` | `symtest.cli:run_tests` |
59
+ | `symtest tui` | `symtest.tui.app:run_tui` |
60
+ | `symtest validate` | `symtest.cli:run_validate` |
61
+ | `symtest schema` | `symtest.cli:run_schema` |
62
+ | `symtest compare` | `symtest.cli:run_compare` |
63
+
64
+ ## 3. 配置管线
65
+
66
+ 配置文件在加载时经过五步管线处理:
67
+
68
+ ```
69
+ raw JSON/YAML 文件
70
+ │
71
+ ▼
72
+ expand_imports() # 递归展开 import 引用(合并 setup、注入 tags)
73
+ │
74
+ ▼
75
+ resolve_inheritance() # 解析 extends 继承链(deep-merge、去重 abstract)
76
+ │
77
+ ▼
78
+ apply_variables() # 注入 --var 全局变量 + case-level variables
79
+ │
80
+ ▼
81
+ substitute_placeholders() # 递归替换 {placeholder} 占位符
82
+ │
83
+ ▼
84
+ parse_test_cases() # 转换为 List[TestCase](命令路径解析)
85
+ ```
86
+
87
+ ### 3.1 Import 展开 (`import_expander.py`)
88
+
89
+ 主配置文件通过 `"import"` 引用子配置文件:
90
+
91
+ - 递归展开所有 import,内联到主配置中
92
+ - import 级 tags 注入到被引文件的每个 case
93
+ - setup 深度合并
94
+ - 循环引用检测
95
+
96
+ 配置形态与用法示例见 `examples/`。
97
+
98
+ ### 3.2 继承展开 (`inheritance_expander.py`)
99
+
100
+ `extends` 字段实现用例模板继承:
101
+
102
+ - 深度合并(dict)/ 整体替换(list)策略
103
+ - `abstract: true` 的模板不参与执行
104
+ - extends 链上的 `variables` 收集后统一替换
105
+ - 循环继承检测
106
+
107
+ ### 3.3 配置验证 (`config_io.py`)
108
+
109
+ `symtest validate` 子命令在不执行测试的情况下校验配置:
110
+
111
+ - Error 级(影响 valid):JSON/YAML 语法、必填字段、import 目标存在性、循环引用、extends 目标存在性、循环继承
112
+ - Warning 级(不影响 valid):命令可执行性(PATH 查找)、`compare_files` baseline 文件存在性
113
+
114
+ ## 4. 执行语义
115
+
116
+ > 本章只记载跨模块的行为语义约定;类属性、方法签名与默认值以源码为准。
117
+
118
+ ### 4.1 Runner 模板与状态映射
119
+
120
+ - 模板流程固定:`load_test_cases()` → 过滤(名称精确 / tags 交集 / `--last-failed`)→ `setup_all()` → 逐 case 执行 → xfail 状态映射 → 历史与 last-run 更新 → `teardown_all()`(逆序,保证出错也继续清理)
121
+ - JSON/YAML Runner 仅注入不同的 config_loader,通用逻辑统一在顺序 / 并行通用运行器中
122
+ - xfail:`expected_failure=True` 时 `passed → xpassed`(意外通过,计入失败);任意非 passed → `xfailed`(预期失败,不计入失败)
123
+ - JUnit XML 状态映射:`xfailed → <skipped>`、`xpassed → <failure>`、`timeout → <error>`、`failed` 按消息类型分 `<failure>` / `<error>`
124
+ - 历史:累计平均更新;写入前先按 `regression_threshold` 与旧均值做回归检测;`--update-history` 清除后重记
125
+ - `--last-failed`:每次运行只覆写本次参与执行的用例状态,子集运行不丢失其余用例状态
126
+
127
+ ### 4.2 测试双模式
128
+
129
+ 单命令模式(`command + args + expected`)与 steps 序列模式二选一;每个 step 是
130
+ "执行 + 判定"的原子对(command / args / timeout / retry_count / expected)。
131
+ 字段全集见 `core/test_case.py` 与 JSON Schema,本文不复述。
132
+
133
+ ### 4.3 并行与资源调度
134
+
135
+ - LPT 策略:长任务先行;启用 history 时优先用 `.symtest` 历史 `avg_duration` 排序,其次才看声明的 `estimated_time`
136
+ - `AtomicSemaphore` 资源池:`safe_capacity = max(1, cpu_count − 2)`;每个 case 按 `cpu_cores` acquire/release
137
+ - 按权重比例分配相对 CPU 核数,并自动注入 `OMP_NUM_THREADS` / `MKL_NUM_THREADS` / `NPROC`
138
+ - 环境变量优先级:`os.environ` < 调度器注入 < case 级 env(经 subprocess 注入,不改进程全局环境)
139
+ - 线程模式共享内存 + 结果/打印锁;进程模式经 process worker 隔离;可回退顺序执行
140
+
141
+ ### 4.4 DAG 依赖调度语义
142
+
143
+ - `depends_on` 非空自动切换拓扑模式;无依赖时走零开销 fast path
144
+ - Kahn 入度表 + 就绪队列,依赖满足后立即提交后继
145
+ - 依赖"满足" = `passed` 或 `xfailed`;`failed` / `xpassed` 触发 BFS 级联 skip 全部下游
146
+ - `skipped` 不计入 `failed` 计数,报告中单独列出
147
+ - 顺序 runner 同样按拓扑序执行,依赖失效时跳过下游
148
+
149
+ ### 4.5 单测试执行
150
+
151
+ PathResolver 解析(系统命令直通、shell builtin 平台包装、复合命令拆分解析)
152
+ → subprocess 隔离执行(捕获 stdout / stderr / returncode / duration)
153
+ → 断言校验(return_code / contains / matches / compare_files)
154
+ → 失败按 `retry_count` 重试
155
+ → 超时 kill 整个进程组
156
+ → 返回附带 `next_action_hint` 的结构化结果。
157
+
158
+ 当前实现的上述行为仍聚合在一处;1.4 将按 §10 宪法重排为
159
+ Executor / Validator / Orchestration 三段(迁移明细见 docs/design_1_4.md)。
160
+
161
+ ### 4.6 断言与文件比较集成
162
+
163
+ - `compare_files` 是一等断言,经 ComparatorFactory 按类型分发(详见 §6)
164
+ - 所有断言可选;未声明的字段不做校验
165
+ - `--error-analysis` 为 CSV/H5 数值比较提供流式误差统计:`total_numeric_cells` / `mismatched_cells` / `max_abs_error` / `max_rel_error` / `mean_abs_error` / `rms_abs_error`
166
+
167
+ ## 5. 运行时状态持久化(`.symtest/`)
168
+
169
+ | 状态 | 内容 | 更新时机 / 语义 |
170
+ |---|---|---|
171
+ | 历史记录 | per-case `avg_duration` / `last_duration` / `run_count` | 运行后累计平均更新;先回归检测后写入 |
172
+ | `last_run.json` | case → 上次状态 | 覆写参与执行的用例;未执行的保留旧状态 |
173
+ | `sequence_state/<case>.json` | steps + case expected 的 SHA-256 配置哈希、已通过的 step 集 | 每步 pass 后保存;全部通过后清理 |
174
+ | `sequence_state/cache/*.log` | 步骤输出缓存 | 与上同步;供 resume 拼接复现 |
175
+
176
+ **resume 语义**:`--resume` 比对配置哈希——匹配则跳过已过步骤并拼接缓存输出,
177
+ 失配即全量重跑。纯信任模型:不验证 workspace 产物,由用户保证未被修改。
178
+
179
+ ## 6. 文件比较子系统
180
+
181
+ ### 6.1 比较器分层
182
+
183
+ - 文本系比较器共享 difflib 行级基底,json / csv / xml 为其结构化特化(键对齐 / 列结构 / DOM 对齐)
184
+ - h5 面向科学数据集;binary 流式分块 + LCS 相似度;script 委托外部脚本
185
+ - 统一返回 ComparisonResult(identical / differences / error / script command_output),支持 text / json / html 渲染;支持行列窗口范围参数截取后比较
186
+
187
+ ### 6.2 工厂与插件发现
188
+
189
+ - `file_type` 取值:`text` / `json` / `csv` / `xml` / `h5` / `binary` / `script`;工厂按类型分发,支持动态注册与全局 reset(测试用)
190
+ - 插件发现四处来源:内置 `*_comparator.py` 自动发现、`workspace/comparators/` 自动扫描、`--plugin-dir` CLI 参数、`CLITEST_PLUGIN_DIRS` 环境变量(供进程模式 worker 使用)
191
+ - 命名约定:`*_comparator.py` + `*Comparator` 类名
192
+
193
+ ### 6.3 script 比较协议(对外契约)
194
+
195
+ - 子进程方式执行 `<interpreter> <script> <actual> <baseline>`
196
+ - 默认 exit code 0 → 通过;可选 `pass_pattern` / `fail_pattern` 正则匹配 stdout 细化判定
197
+ - 超时可配
198
+
199
+ ## 7. TUI 子系统
200
+
201
+ 基于 Textual 的终端交互界面:App + Controller(load / create / update /
202
+ delete / run_single / save 业务动作)+ 列表 / 编辑两屏 + 表格封装、多模式搜索条
203
+ (名称 / 命令 / 标签)、expected 编辑器、steps 编辑器。
204
+
205
+ 快捷键:`q` / Ctrl+Q 退出、`r` 刷新、`e` 编辑、`f` 单跑、`/` 搜索、`a` 新增、`d` 删除、`s` 保存。
206
+
207
+ TUI 与 runner 共用同一解析器;宽松的展示形态在 TUI 侧自行处理(§10 原则 6)。
208
+
209
+ ## 8. 扩展点
210
+
211
+ | 扩展点 | 基类 | 用途 |
212
+ |---|---|---|
213
+ | 新配置格式 | `BaseRunner` | 支持新的测试定义格式(如 XML、TOML) |
214
+ | 自定义 Setup | `BaseSetup` | 数据库初始化、服务启停等 |
215
+ | 自定义断言 | 扩展 `Assertions` | 特定业务校验逻辑 |
216
+ | 新比较器 | `BaseComparator` | 支持新的文件格式比较,放入 `comparators/` 目录自动发现 |
217
+ | 新 Runner | `ParallelRunner` / `BaseRunner` | 自定义并行调度策略 |
218
+ | TUI 扩展 | `CaseController` / Widgets | 扩展终端管理界面 |
219
+
220
+ ## 9. 设计决策
221
+
222
+ | 决策 | 原因 |
223
+ |---|---|
224
+ | Runner 用模板方法模式 | 统一执行流程(load → filter → setup → run → history → last-run → teardown),子类只需实现配置解析和单测试执行 |
225
+ | Config 管线化处理 | import/extends/variables 正交分解,每步职责单一,可独立测试和组合 |
226
+ | JSON/YAML Runner 统一为 ConfigRunner | 消除代码重复,通过注入 config_loader 适配不同格式 |
227
+ | Setup 逆序 teardown | 类似栈语义,后初始化的依赖先清理 |
228
+ | 信号量管理 CPU 核心 | 比线程池 worker 数更精细,允许不同 case 声明不同核心需求 |
229
+ | LPT 调度策略 | 长任务先启动,减少尾延迟;优先使用 `.symtest` 历史数据 |
230
+ | 累计平均更新历史 | 直觉简单,随运行次数增多单次异常自然稀释 |
231
+ | 回归检测在更新前执行 | 先与旧均值比较再更新,确保对比的是"历史基线" |
232
+ | `.symtest/` 目录 | 不干扰用户目录视图,JSON 格式便于调试;状态文件统一管理 |
233
+ | 环境变量注入 | 科学计算求解器常忽略 Python 级线程控制 |
234
+ | case 级 env 通过 subprocess 注入 | 不改进程全局 `os.environ`,进程隔离、并行线程安全;优先级 `os.environ` < 调度器 < case env |
235
+ | Comparator 工厂 + 插件发现 | 按文件类型创建比较器,workspace `comparators/` 目录自动发现插件 |
236
+ | subprocess 隔离执行 | 每个 test case 独立子进程,保证测试间互不影响 |
237
+ | xfail 机制 | 支持预期失败的测试(CI 中不阻塞流水线),意外通过时告警 |
238
+ | --last-failed 覆写策略 | 只覆写本次执行的用例状态,避免子集运行时丢失未执行用例的状态 |
239
+ | --resume 纯信任模型 | 不验证 artifact,由用户保证 workspace 未被修改,简化实现 |
240
+ | retry_count 重试机制 | 应对偶发性网络抖动或竞态条件,首次失败后自动重试 |
241
+ | DAG 依赖调度 | 基于 Kahn 拓扑 + 就绪队列,依赖满足后立即提交;依赖失败级联 skip 下游;无依赖时走 fast path 零开销 |
242
+ | --update-baseline | 比较失败时自动将实际输出覆盖 baseline,适合批量更新基准 |
243
+ | next_action_hint 结构化建议 | 失败结果附带下一步操作建议(update_baseline / update_expected / increase_timeout / investigate),便于 AI 消费 |
244
+ | TUI 基于 Textual | 利用成熟的终端 UI 框架,提供交互式用例管理 |
245
+ | JUnit XML 输出 | 兼容 GitLab CI / Jenkins / CircleCI 等主流 CI 系统的测试报告格式 |
246
+ | Logging 统一化 | 通过 `logging` 模块集中管理,CLI 入口激活控制台输出,库用户按需启用 |
247
+
248
+ ---
249
+
250
+ ## 10. 核心架构宪法
251
+
252
+ > **地位与效力**:本节自 Symtest 1.4 Phase 0 评审定稿,是本项目的核心架构契约,
253
+ > 对所有后续 feature 具有最高约束力——任何功能需求先对照本宪法确定归属,再写代码。
254
+ > 修订宪法必须在变更说明中显式指出所放宽/违反的条款及理由。
255
+ > 定稿前的演进推导见开发阶段文档 docs/design_1_4.md。
256
+
257
+ ### 10.1 数据流主线
258
+
259
+ ```
260
+ TestCase(specification,永不执行)
261
+ ├── ExecutionSpec ──▶ Executor.execute() ──▶ ExecutionResult
262
+ ├── ExpectationSpec ─┐
263
+ └── SchedulingSpec ──▶ Orchestration(何时跑、跑哪个、组合与重试)
264
+ │
265
+ Validator.validate(ExpectationSpec, ExecutionResult)
266
+ ▼
267
+ ValidationResult ──▶ TestResult ──▶ Reporter
268
+ console / JSON / JUnit / AI diagnosis
269
+ ```
270
+
271
+ 一次 attempt = `Executor.execute → Validator.validate`;verdict 由编排层聚合为 TestResult。
272
+
273
+ ### 10.2 六条原则
274
+
275
+ #### 原则 1 — TestCase 是声明,不执行任何事情
276
+
277
+ `TestCase = specification`。禁止出现 `test_case.run()` / `test_case.validate()` /
278
+ `test_case.update_baseline()` 这类方法;TestCase 只描述**执行什么**
279
+ (ExecutionSpec)、**如何判定**(ExpectationSpec)、**调度约束**
280
+ (SchedulingSpec)与元数据。
281
+
282
+ 概念模型分层 ≠ 配置 DSL 必须机械映射类层次:`name/tags/description` 允许保留
283
+ 顶层以避免啰嗦;真正必须拆出去的是执行语义、验证语义、调度语义。
284
+
285
+ #### 原则 2 — Execution 不知道"通过/失败"
286
+
287
+ ```
288
+ Executor: ExecutionSpec ──execute──▶ ExecutionResult
289
+ ```
290
+
291
+ ExecutionResult 只承载执行事实:`return_code / stdout / stderr / duration /
292
+ timed_out / error / artifacts`。
293
+
294
+ Executor 禁止感知:`expected_return_code / output_contains / baseline / rtol /
295
+ file comparison / xfail / next_action_hint`。超时只报告 `timed_out=True`,
296
+ "timeout 是否算失败"由 Validator 判定。
297
+
298
+ #### 原则 3 — Validation 不执行被测程序,且永远只读
299
+
300
+ ```
301
+ Validator: ExpectationSpec + ExecutionResult ──validate──▶ ValidationResult
302
+ ```
303
+
304
+ Validator 禁止 `subprocess.Popen` 被测进程、kill 进程、retry。
305
+
306
+ **例外条款(受控豁免)**:comparator 是验证的内部工具,`script` comparator
307
+ 执行的是"比较工具"而非"被测程序",属本条明确豁免范围。
308
+
309
+ **baseline 语义**:Validator 永远只读文件。`--update-baseline` 由 runner 在拿到
310
+ ValidationResult 后执行独立的 accept 步骤(复制 actual → baseline)再判定。
311
+
312
+ #### 原则 4 — Orchestration 组合,而不实现底层语义
313
+
314
+ Runner / Scheduler / DAG / ParallelRunner 负责:什么时候执行、执行哪个 case、
315
+ 顺序、依赖、并发、**retry policy**(一次 attempt =
316
+ `Executor.execute → Validator.validate`,runner 拿 verdict 决定是否重跑,
317
+ flaky 判定也在编排层);但不自己实现 subprocess 管理、float 比较、stdout 判断。
318
+
319
+ #### 原则 5 — Reporting 只能消费 Result
320
+
321
+ ```
322
+ TestResult ──▶ Reporter ──┬── console
323
+ ├── JSON
324
+ ├── JUnit
325
+ └── AI diagnosis
326
+ ```
327
+
328
+ Reporter 的合法输入只能是 Result 类型;`next_action_hint` 属于 result consumer
329
+ (diagnosis),不得存在于 execution 层。
330
+
331
+ #### 原则 6 — 核心模型不依赖表现层
332
+
333
+ `core` 绝对不能 import:`cli` / `tui` / `reporter` / AI-specific adapter。
334
+
335
+ 解析器全系统唯一:TUI 与 runner 使用同一 parser,不允许存在 "TUI mode 后门"
336
+ (如 workspace=None 时放宽校验);宽松形态由 TUI 侧自行处理。
337
+
338
+ ### 10.3 模块依赖方向
339
+
340
+ 允许:
341
+
342
+ - `orchestration` import `execution` / `validation`(它是唯一组合者);
343
+ - `reporting` 仅 import result 类型
344
+ (ExecutionResult / ValidationResult / TestResult)。
345
+
346
+ 禁止:
347
+
348
+ - `execution` 与 `validation` 互不 import;
349
+ - `executor` 不得 import `assertions` / validation 侧模块;
350
+ - `validator` 不得启动被测进程(见原则 3);
351
+ - `core` 不得 import `cli` / `tui` / `reporter`。
352
+
353
+ ### 10.4 违宪归属速查
354
+
355
+ 任何新需求先问归属:
356
+
357
+ | 提问 | 归属 |
358
+ |---|---|
359
+ | 增加 GPU resource requirement? | SchedulingSpec |
360
+ | 增加 stderr regex assertion? | ExpectationSpec / Validator |
361
+ | 支持 Docker command execution? | Executor |
362
+ | AI 告诉我下一步该干嘛? | Result consumer / diagnosis |
363
+
364
+ 判据:若仍经常出现"这个功能到底放 execution、runner 还是 testcase?"的争论,
365
+ 说明宪法没有被正确适用,应回到 10.2 逐条对照。
366
+
367
+ ### 10.5 宪法可执行化
368
+
369
+ 宪法不是纯文档约定,配套 architecture guard 测试并由 CI 强制:
370
+
371
+ - 断言 import 图:如 `execution/executor.py` 的 import 不得出现
372
+ `assertions` / `validation`;`core/**` 不得 import `cli` / `tui` /
373
+ `reporter`;
374
+ - guard 测试纳入常规回归套件(`python tests\run_all.py`),违规即失败;
375
+ - 冲突裁决次序:guard 测试 > 本节文字 > 个人偏好。
376
+
377
+ ### 10.6 现状差距与收敛路径
378
+
379
+ 定稿时刻(1.4 Phase 0)现行实现与本宪法的已知偏差如下,将在 1.4 对应 Phase 内
380
+ 逐项收敛(迁移明细见 docs/design_1_4.md):
381
+
382
+ | 现状 | 违反 | 收敛 |
383
+ |---|---|---|
384
+ | `execution.py::validate_result` 住在执行层 | 原则 2 | Phase 2 迁入 `validation/validator.py` |
385
+ | `next_action_hint` 在 execution 层构造 | 原则 5 | Phase 2 迁入 `reporting/diagnosis.py` |
386
+ | retry 循环在 executor 内部 | 原则 2 / 4 | Phase 2 上移编排层 |
387
+ | Validator 侧 update_baseline 写文件 | 原则 3 | Phase 2 改为 runner 独立 accept 步骤 |
388
+ | `parse_test_cases` TUI mode 后门 | 原则 6 | Phase 2 拆除,单一解析器 |