cli-test-framework 0.5.2__tar.gz → 0.5.3__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 (137) hide show
  1. {cli_test_framework-0.5.2/src/cli_test_framework.egg-info → cli_test_framework-0.5.3}/PKG-INFO +1 -1
  2. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/setup.py +1 -1
  3. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/commands/compare.py +17 -0
  4. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/core/base_runner.py +4 -1
  5. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/file_comparator/csv_comparator.py +16 -1
  6. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/file_comparator/factory.py +5 -0
  7. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3/src/cli_test_framework.egg-info}/PKG-INFO +1 -1
  8. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/__pycache__/run_all.cpython-312.pyc +0 -0
  9. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-9.0.3.pyc +0 -0
  10. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-9.0.3.pyc +0 -0
  11. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-9.0.3.pyc +0 -0
  12. cli_test_framework-0.5.3/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  13. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  14. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/test_csv_compare.py +46 -0
  15. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-9.0.3.pyc +0 -0
  16. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-9.0.3.pyc +0 -0
  17. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/__pycache__/test_cli.cpython-312-pytest-9.0.3.pyc +0 -0
  18. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  19. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-9.0.3.pyc +0 -0
  20. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-9.0.3.pyc +0 -0
  21. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-9.0.3.pyc +0 -0
  22. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-9.0.3.pyc +0 -0
  23. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-9.0.3.pyc +0 -0
  24. cli_test_framework-0.5.2/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  25. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/MANIFEST.in +0 -0
  26. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/README.md +0 -0
  27. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/docs/design.md +0 -0
  28. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/docs/design_en.md +0 -0
  29. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/docs/user_manual.md +0 -0
  30. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/docs/user_manual_en.md +0 -0
  31. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/pyproject.toml +0 -0
  32. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/setup.cfg +0 -0
  33. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/__init__.py +0 -0
  34. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/cli.py +0 -0
  35. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/commands/__init__.py +0 -0
  36. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/core/__init__.py +0 -0
  37. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/core/assertions.py +0 -0
  38. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/core/execution.py +0 -0
  39. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/core/history_store.py +0 -0
  40. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/core/parallel_runner.py +0 -0
  41. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/core/process_worker.py +0 -0
  42. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/core/setup.py +0 -0
  43. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/core/test_case.py +0 -0
  44. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/core/types.py +0 -0
  45. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/file_comparator/__init__.py +0 -0
  46. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/file_comparator/base_comparator.py +0 -0
  47. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/file_comparator/binary_comparator.py +0 -0
  48. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/file_comparator/h5_comparator.py +0 -0
  49. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/file_comparator/json_comparator.py +0 -0
  50. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/file_comparator/result.py +0 -0
  51. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/file_comparator/text_comparator.py +0 -0
  52. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/file_comparator/xml_comparator.py +0 -0
  53. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/runners/__init__.py +0 -0
  54. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/runners/json_runner.py +0 -0
  55. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/runners/parallel_json_runner.py +0 -0
  56. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/runners/yaml_runner.py +0 -0
  57. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/utils/__init__.py +0 -0
  58. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/utils/path_resolver.py +0 -0
  59. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework/utils/report_generator.py +0 -0
  60. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework.egg-info/SOURCES.txt +0 -0
  61. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework.egg-info/dependency_links.txt +0 -0
  62. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework.egg-info/entry_points.txt +0 -0
  63. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework.egg-info/requires.txt +0 -0
  64. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/src/cli_test_framework.egg-info/top_level.txt +0 -0
  65. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/README.md +0 -0
  66. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/__init__.py +0 -0
  67. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/__pycache__/__init__.cpython-312.pyc +0 -0
  68. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/__pycache__/__init__.cpython-39.pyc +0 -0
  69. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
  70. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
  71. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/__pycache__/conftest.cpython-39-pytest-8.3.4.pyc +0 -0
  72. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/__pycache__/run_all.cpython-39.pyc +0 -0
  73. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  74. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/__pycache__/test_setup_module.cpython-312-pytest-7.4.4.pyc +0 -0
  75. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/conftest.py +0 -0
  76. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/demos/h5_filter_demo.py +0 -0
  77. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/demos/manual_report_example.py +0 -0
  78. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/demos/perf_parallel.py +0 -0
  79. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/e2e/__init__.py +0 -0
  80. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/e2e/__pycache__/__init__.cpython-312.pyc +0 -0
  81. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/e2e/__pycache__/__init__.cpython-39.pyc +0 -0
  82. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-7.4.4.pyc +0 -0
  83. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/e2e/__pycache__/test_user_flows.cpython-39-pytest-8.3.4.pyc +0 -0
  84. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/e2e/test_user_flows.py +0 -0
  85. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/fixtures/test_cases.json +0 -0
  86. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/fixtures/test_cases.yaml +0 -0
  87. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/fixtures/test_cases1.json +0 -0
  88. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/fixtures/test_with_setup.json +0 -0
  89. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/fixtures/test_with_setup.yaml +0 -0
  90. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-7.4.4.pyc +0 -0
  91. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-9.0.3.pyc +0 -0
  92. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  93. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  94. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  95. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  96. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  97. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  98. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  99. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  100. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  101. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  102. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  103. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  104. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/test_binary_compare.py +0 -0
  105. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/test_h5_compare.py +0 -0
  106. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/test_json_compare.py +0 -0
  107. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/test_text_compare.py +0 -0
  108. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/file_compare/test_xml_compare.py +0 -0
  109. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  110. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-39-pytest-8.3.4.pyc +0 -0
  111. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/parallel/test_parallel_runner.py +0 -0
  112. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-7.4.4.pyc +0 -0
  113. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-39-pytest-8.3.4.pyc +0 -0
  114. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/path_handling/test_spaces_in_paths.py +0 -0
  115. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/test_history_feature.py +0 -0
  116. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/test_real_command_execution.py +0 -0
  117. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/integration/test_sequence.py +0 -0
  118. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/run_all.py +0 -0
  119. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/test_report.txt +0 -0
  120. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/commands/test_compare_command.py +0 -0
  121. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-7.4.4.pyc +0 -0
  122. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-9.0.3.pyc +0 -0
  123. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/core/__pycache__/test_setup.cpython-39-pytest-8.3.4.pyc +0 -0
  124. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/core/test_history_store.py +0 -0
  125. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/core/test_process_worker.py +0 -0
  126. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/core/test_setup.py +0 -0
  127. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  128. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-9.0.3.pyc +0 -0
  129. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-39-pytest-8.3.4.pyc +0 -0
  130. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-7.4.4.pyc +0 -0
  131. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-9.0.3.pyc +0 -0
  132. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/runners/test_json_yaml_runner.py +0 -0
  133. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/runners/test_test_case_filter.py +0 -0
  134. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/test_cli.py +0 -0
  135. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/test_h5_comparator.py +0 -0
  136. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/test_run_all.py +0 -0
  137. {cli_test_framework-0.5.2 → cli_test_framework-0.5.3}/tests/unit/utils/test_report_generator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cli-test-framework
3
- Version: 0.5.2
3
+ Version: 0.5.3
4
4
  Summary: A powerful command line testing framework in Python with setup modules, parallel execution, and file comparison capabilities.
5
5
  Home-page: https://github.com/ozil111/cli-test-framework
6
6
  Author: Xiaotong Wang
@@ -8,7 +8,7 @@ with open(os.path.join(this_directory, 'README.md'), encoding='utf-8') as f:
8
8
 
9
9
  setup(
10
10
  name="cli-test-framework",
11
- version="0.5.2",
11
+ version="0.5.3",
12
12
  author="Xiaotong Wang",
13
13
  author_email="xiaotongwang98@gmail.com",
14
14
  description="A powerful command line testing framework in Python with setup modules, parallel execution, and file comparison capabilities.",
@@ -49,6 +49,17 @@ def parse_arguments():
49
49
  help="When comparing binary files, compute and show similarity index")
50
50
  parser.add_argument("--num-threads", type=int, default=4, help="Number of threads for parallel processing")
51
51
 
52
+ # CSV comparison options
53
+ csv_group = parser.add_argument_group('CSV comparison options')
54
+ csv_group.add_argument("--csv-rtol", type=float, default=1e-5,
55
+ help="Relative tolerance for numerical comparison in CSV files")
56
+ csv_group.add_argument("--csv-atol", type=float, default=1e-8,
57
+ help="Absolute tolerance for numerical comparison in CSV files")
58
+ csv_group.add_argument("--csv-delimiter", default=",",
59
+ help="CSV field delimiter (default: comma)")
60
+ csv_group.add_argument("--csv-quotechar", default='"',
61
+ help="Character used for quoting fields in CSV (default: double quote)")
62
+
52
63
  # JSON comparison options
53
64
  json_group = parser.add_argument_group('JSON comparison options')
54
65
  json_group.add_argument("--json-compare-mode", choices=["exact", "key-based"], default="exact",
@@ -148,6 +159,12 @@ def main():
148
159
  key_fields = [field.strip() for field in args.json_key_field.split(',')]
149
160
  comparator_kwargs["key_field"] = key_fields[0] if len(key_fields) == 1 else key_fields
150
161
 
162
+ if file_type == "csv":
163
+ comparator_kwargs["rtol"] = args.csv_rtol
164
+ comparator_kwargs["atol"] = args.csv_atol
165
+ comparator_kwargs["delimiter"] = args.csv_delimiter
166
+ comparator_kwargs["quotechar"] = args.csv_quotechar
167
+
151
168
  if file_type == "h5":
152
169
  if args.h5_table:
153
170
  tables = [table.strip() for table in args.h5_table.split(',')]
@@ -20,7 +20,10 @@ class BaseRunner(ABC):
20
20
  self.config_path = self.workspace / config_file
21
21
  self.test_cases: List[TestCase] = []
22
22
  self.test_case_filter: Optional[List[str]] = test_case_filter
23
- self.history_dir = history_dir
23
+ if history_dir:
24
+ self.history_dir = str((self.workspace / history_dir).resolve())
25
+ else:
26
+ self.history_dir = None
24
27
  self.regression_threshold = regression_threshold
25
28
  self.results: Dict[str, Any] = {
26
29
  "total": 0,
@@ -10,6 +10,7 @@
10
10
 
11
11
  import csv
12
12
  import io
13
+ import math
13
14
  from .text_comparator import TextComparator
14
15
  from .result import Difference
15
16
 
@@ -24,7 +25,7 @@ class CsvComparator(TextComparator):
24
25
  - Configurable delimiter and quote character
25
26
  """
26
27
 
27
- def __init__(self, encoding="utf-8", delimiter=",", quotechar='"', chunk_size=8192, verbose=False):
28
+ def __init__(self, encoding="utf-8", delimiter=",", quotechar='"', chunk_size=8192, verbose=False, rtol=1e-5, atol=1e-8):
28
29
  """
29
30
  @brief Initialize CSV comparator with configuration
30
31
  @param encoding str: File encoding (default: utf-8)
@@ -32,10 +33,14 @@ class CsvComparator(TextComparator):
32
33
  @param quotechar str: Character used for quoting fields (default: double quote)
33
34
  @param chunk_size int: Size of chunks for reading large files
34
35
  @param verbose bool: Enable verbose output
36
+ @param rtol float: Relative tolerance for numerical comparison (default: 1e-5)
37
+ @param atol float: Absolute tolerance for numerical comparison (default: 1e-8)
35
38
  """
36
39
  super().__init__(encoding, chunk_size, verbose)
37
40
  self.delimiter = delimiter
38
41
  self.quotechar = quotechar
42
+ self.rtol = rtol
43
+ self.atol = atol
39
44
 
40
45
  def read_content(self, file_path, start_line=0, end_line=None, start_column=0, end_column=None):
41
46
  """
@@ -116,6 +121,14 @@ class CsvComparator(TextComparator):
116
121
  # Compare column values
117
122
  for j, (cell1, cell2) in enumerate(zip(row1, row2)):
118
123
  if cell1 != cell2:
124
+ # Try numeric tolerance comparison
125
+ try:
126
+ num1 = float(cell1)
127
+ num2 = float(cell2)
128
+ if math.isclose(num1, num2, rel_tol=self.rtol, abs_tol=self.atol):
129
+ continue # Within tolerance, treat as equal
130
+ except (ValueError, TypeError):
131
+ pass # Non-numeric, fall through to string mismatch
119
132
  differences.append(Difference(
120
133
  position=f"row {i+1}, column {j+1}",
121
134
  expected=cell1,
@@ -137,4 +150,6 @@ class CsvComparator(TextComparator):
137
150
  diff_type=f"more differences not shown"
138
151
  ))
139
152
 
153
+ if not differences:
154
+ return True, []
140
155
  return False, differences
@@ -77,6 +77,11 @@ class ComparatorFactory:
77
77
  json_kwargs = {k: v for k, v in kwargs.items()
78
78
  if k in ['encoding', 'chunk_size', 'verbose', 'compare_mode', 'key_field']}
79
79
  return comparator_class(**json_kwargs)
80
+ elif file_type.lower() == 'csv':
81
+ # CSV comparator accepts specific parameters
82
+ csv_kwargs = {k: v for k, v in kwargs.items()
83
+ if k in ['encoding', 'delimiter', 'quotechar', 'chunk_size', 'verbose', 'rtol', 'atol']}
84
+ return comparator_class(**csv_kwargs)
80
85
  else:
81
86
  # Other comparators only accept basic parameters
82
87
  basic_kwargs = {k: v for k, v in kwargs.items()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cli-test-framework
3
- Version: 0.5.2
3
+ Version: 0.5.3
4
4
  Summary: A powerful command line testing framework in Python with setup modules, parallel execution, and file comparison capabilities.
5
5
  Home-page: https://github.com/ozil111/cli-test-framework
6
6
  Author: Xiaotong Wang
@@ -63,3 +63,49 @@ def test_csv_column_range_limits_scope(tmp_path):
63
63
  result = compare_csv(file1, file2, start_column=0, end_column=1)
64
64
 
65
65
  assert result.identical
66
+
67
+
68
+ def test_csv_numeric_tolerance_within_range(tmp_path):
69
+ """Numeric cells within tolerance should be treated as equal"""
70
+ file1 = tmp_path / "a.csv"
71
+ file2 = tmp_path / "b.csv"
72
+ file1.write_text("id,value\n1,1.000001\n2,3.0\n", encoding="utf-8")
73
+ file2.write_text("id,value\n1,1.0\n2,3.00001\n", encoding="utf-8")
74
+
75
+ result = compare_csv(file1, file2, rtol=1e-5, atol=1e-5)
76
+
77
+ assert result.identical
78
+ assert result.differences == []
79
+
80
+
81
+ def test_csv_numeric_tolerance_exceeded(tmp_path):
82
+ """Numeric cells exceeding tolerance should be reported as mismatch"""
83
+ file1 = tmp_path / "a.csv"
84
+ file2 = tmp_path / "b.csv"
85
+ file1.write_text("id,value\n1,1.0\n", encoding="utf-8")
86
+ file2.write_text("id,value\n1,2.0\n", encoding="utf-8")
87
+
88
+ result = compare_csv(file1, file2, rtol=1e-5, atol=1e-8)
89
+
90
+ assert not result.identical
91
+ diff = result.differences[0]
92
+ assert diff.diff_type == "cell_mismatch"
93
+ assert diff.expected == "1.0"
94
+ assert diff.actual == "2.0"
95
+
96
+
97
+ def test_csv_numeric_tolerance_mixed_with_string(tmp_path):
98
+ """Non-numeric cells should still use string comparison even with tolerance enabled"""
99
+ file1 = tmp_path / "a.csv"
100
+ file2 = tmp_path / "b.csv"
101
+ file1.write_text("id,name,value\n1,Ada,1.0\n", encoding="utf-8")
102
+ file2.write_text("id,name,value\n1,Grace,1.000001\n", encoding="utf-8")
103
+
104
+ result = compare_csv(file1, file2, rtol=1e-5, atol=1e-5)
105
+
106
+ assert not result.identical
107
+ # Only the string mismatch should be reported; numeric value is within tolerance
108
+ diff_types = [d.diff_type for d in result.differences]
109
+ assert "cell_mismatch" in diff_types
110
+ string_diffs = [d for d in result.differences if d.diff_type == "cell_mismatch"]
111
+ assert any(d.expected == "Ada" and d.actual == "Grace" for d in string_diffs)