symtest-cli 1.3.1__tar.gz → 1.3.2__tar.gz

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