orionis 0.432.0__py3-none-any.whl → 0.435.0__py3-none-any.whl

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 (76) hide show
  1. orionis/app.py +17 -0
  2. orionis/metadata/framework.py +1 -1
  3. orionis/support/entities/base.py +18 -37
  4. orionis/support/facades/console.py +3 -9
  5. orionis/support/facades/dumper.py +3 -9
  6. orionis/support/facades/logger.py +3 -9
  7. orionis/support/facades/path_resolver.py +3 -10
  8. orionis/support/facades/progress_bar.py +3 -10
  9. orionis/support/facades/testing.py +4 -10
  10. orionis/support/facades/workers.py +4 -9
  11. orionis/support/formatter/exceptions/contracts/parser.py +10 -7
  12. orionis/support/formatter/exceptions/parser.py +28 -26
  13. orionis/support/formatter/serializer.py +12 -5
  14. orionis/support/patterns/singleton/meta.py +17 -21
  15. orionis/support/standard/contracts/std.py +25 -24
  16. orionis/support/standard/exceptions/value.py +2 -2
  17. orionis/support/standard/std.py +26 -24
  18. orionis/support/wrapper/dot_dict.py +16 -51
  19. orionis/test/cases/asynchronous.py +17 -81
  20. orionis/test/cases/synchronous.py +17 -73
  21. orionis/test/contracts/dumper.py +17 -21
  22. orionis/test/contracts/kernel.py +5 -12
  23. orionis/test/contracts/logs.py +16 -21
  24. orionis/test/contracts/printer.py +70 -8
  25. orionis/test/contracts/render.py +7 -13
  26. orionis/test/contracts/test_result.py +58 -27
  27. orionis/test/contracts/unit_test.py +18 -18
  28. orionis/test/core/unit_test.py +325 -445
  29. orionis/test/entities/result.py +49 -21
  30. orionis/test/enums/status.py +11 -17
  31. orionis/test/exceptions/config.py +4 -8
  32. orionis/test/exceptions/failure.py +2 -18
  33. orionis/test/exceptions/persistence.py +4 -8
  34. orionis/test/exceptions/runtime.py +4 -8
  35. orionis/test/exceptions/value.py +5 -13
  36. orionis/test/kernel.py +14 -42
  37. orionis/test/output/dumper.py +21 -43
  38. orionis/test/output/printer.py +6 -146
  39. orionis/test/records/logs.py +57 -121
  40. orionis/test/validators/base_path.py +8 -6
  41. orionis/test/validators/execution_mode.py +2 -3
  42. orionis/test/validators/fail_fast.py +4 -8
  43. orionis/test/validators/folder_path.py +5 -7
  44. orionis/test/validators/module_name.py +3 -3
  45. orionis/test/validators/name_pattern.py +4 -9
  46. orionis/test/validators/pattern.py +4 -9
  47. orionis/test/validators/persistent.py +4 -14
  48. orionis/test/validators/persistent_driver.py +7 -12
  49. orionis/test/validators/print_result.py +4 -9
  50. orionis/test/validators/tags.py +6 -7
  51. orionis/test/validators/throw_exception.py +7 -14
  52. orionis/test/validators/verbosity.py +15 -5
  53. orionis/test/validators/web_report.py +6 -10
  54. orionis/test/validators/workers.py +9 -4
  55. orionis/test/view/render.py +9 -26
  56. {orionis-0.432.0.dist-info → orionis-0.435.0.dist-info}/METADATA +1 -1
  57. {orionis-0.432.0.dist-info → orionis-0.435.0.dist-info}/RECORD +76 -75
  58. tests/support/entities/mock_dataclass.py +16 -10
  59. tests/support/entities/test_base.py +6 -14
  60. tests/support/patterns/singleton/test_patterns_singleton.py +7 -8
  61. tests/support/standard/test_services_std.py +113 -37
  62. tests/support/wrapper/test_services_wrapper_docdict.py +25 -40
  63. tests/testing/cases/test_testing_asynchronous.py +14 -14
  64. tests/testing/cases/test_testing_synchronous.py +12 -14
  65. tests/testing/entities/test_testing_result.py +12 -51
  66. tests/testing/enums/test_testing_status.py +8 -13
  67. tests/testing/output/test_testing_dumper.py +3 -6
  68. tests/testing/output/test_testing_printer.py +5 -5
  69. tests/testing/records/test_testing_records.py +16 -26
  70. tests/testing/test_testing_unit.py +8 -94
  71. tests/testing/validators/test_testing_validators.py +55 -112
  72. tests/testing/view/test_render.py +4 -5
  73. {orionis-0.432.0.dist-info → orionis-0.435.0.dist-info}/WHEEL +0 -0
  74. {orionis-0.432.0.dist-info → orionis-0.435.0.dist-info}/licenses/LICENCE +0 -0
  75. {orionis-0.432.0.dist-info → orionis-0.435.0.dist-info}/top_level.txt +0 -0
  76. {orionis-0.432.0.dist-info → orionis-0.435.0.dist-info}/zip-safe +0 -0
@@ -51,81 +51,68 @@ class UnitTest(IUnitTest):
51
51
 
52
52
  Advanced unit testing manager for the Orionis framework.
53
53
 
54
- This class offers a robust and extensible solution for discovering, executing, and reporting unit tests with high configurability. It supports both sequential and parallel execution modes, filtering by test name or tags, and provides detailed result tracking including execution times, error messages, and tracebacks.
55
-
56
- Key features:
57
- - Flexible test discovery from folders or modules, with pattern and tag filtering.
58
- - Rich result reporting: console output, persistent storage (SQLite or JSON), and web-based reports.
59
- - Dependency injection for test methods via the application context.
60
- - Customizable verbosity, fail-fast, and exception handling options.
61
- - Designed for easy integration into CI/CD pipelines and adaptable to diverse project requirements.
62
-
63
- Orionis UnitTest is ideal for teams seeking enhanced traceability, reliability, and visibility in automated testing, with capabilities that go beyond standard unittest frameworks.
54
+ This class provides mechanisms for discovering, executing, and reporting unit tests with extensive configurability. It supports sequential and parallel execution, test filtering by name or tags, and detailed result tracking including execution times, error messages, and tracebacks.
55
+
56
+ Attributes
57
+ ----------
58
+ __app : Optional[IApplication]
59
+ Application instance for dependency injection.
60
+ __verbosity : Optional[int]
61
+ Verbosity level for test output.
62
+ __execution_mode : Optional[str]
63
+ Execution mode for tests ('SEQUENTIAL' or 'PARALLEL').
64
+ __max_workers : Optional[int]
65
+ Maximum number of workers for parallel execution.
66
+ __fail_fast : Optional[bool]
67
+ Whether to stop on first failure.
68
+ __throw_exception : Optional[bool]
69
+ Whether to raise exceptions on test failures.
70
+ __persistent : Optional[bool]
71
+ Whether to persist test results.
72
+ __persistent_driver : Optional[str]
73
+ Persistence driver ('sqlite' or 'json').
74
+ __web_report : Optional[bool]
75
+ Whether to generate a web report.
76
+ __folder_path : Optional[str]
77
+ Folder path for test discovery.
78
+ __base_path : Optional[str]
79
+ Base directory for test discovery.
80
+ __pattern : Optional[str]
81
+ File name pattern for test discovery.
82
+ __test_name_pattern : Optional[str]
83
+ Pattern for filtering test names.
84
+ __tags : Optional[List[str]]
85
+ Tags for filtering tests.
86
+ __module_name : Optional[str]
87
+ Module name for test discovery.
88
+ __loader : unittest.TestLoader
89
+ Loader for discovering tests.
90
+ __suite : unittest.TestSuite
91
+ Test suite containing discovered tests.
92
+ __discovered_tests : List
93
+ List of discovered test metadata.
94
+ __printer : Optional[TestPrinter]
95
+ Utility for printing test results.
96
+ __output_buffer : Optional[str]
97
+ Buffer for capturing standard output.
98
+ __error_buffer : Optional[str]
99
+ Buffer for capturing error output.
100
+ __result : Optional[dict]
101
+ Result summary of the test execution.
64
102
  """
65
103
 
66
104
  def __init__(
67
105
  self
68
106
  ) -> None:
69
107
  """
70
- Initialize a new UnitTest instance with default configuration and internal state.
108
+ Initialize a UnitTest instance with default configuration and internal state.
71
109
 
72
- This constructor sets up all internal attributes required for test discovery, execution,
73
- result reporting, and configuration management. It prepares the instance for further
74
- configuration and use, but does not perform any test discovery or execution itself.
75
-
76
- Attributes
77
- ----------
78
- __app : Optional[IApplication]
79
- The application instance used for dependency injection in test cases.
80
- __verbosity : Optional[int]
81
- Verbosity level for test output (None until configured).
82
- __execution_mode : Optional[str]
83
- Test execution mode, e.g., 'SEQUENTIAL' or 'PARALLEL' (None until configured).
84
- __max_workers : Optional[int]
85
- Maximum number of worker threads/processes for parallel execution (None until configured).
86
- __fail_fast : Optional[bool]
87
- If True, stops execution upon the first test failure (None until configured).
88
- __throw_exception : Optional[bool]
89
- If True, raises exceptions on test failures (None until configured).
90
- __persistent : Optional[bool]
91
- If True, enables persistent storage for test results (None until configured).
92
- __persistent_driver : Optional[str]
93
- The driver to use for persistence, e.g., 'sqlite' or 'json' (None until configured).
94
- __web_report : Optional[bool]
95
- If True, enables web-based reporting of test results (None until configured).
96
- __folder_path : Optional[str]
97
- Relative folder path for test discovery (None until set).
98
- __base_path : Optional[str]
99
- Base directory for test discovery (None until set).
100
- __pattern : Optional[str]
101
- File name pattern to match test files (None until set).
102
- __test_name_pattern : Optional[str]
103
- Pattern to filter test names (None until set).
104
- __tags : Optional[List[str]]
105
- List of tags to filter tests (None until set).
106
- __module_name : Optional[str]
107
- Name of the module for test discovery (None until set).
108
- __loader : unittest.TestLoader
109
- Loader for discovering tests.
110
- __suite : unittest.TestSuite
111
- Test suite containing discovered tests.
112
- __discovered_tests : List
113
- List of discovered test metadata.
114
- __printer : Optional[TestPrinter]
115
- Utility for printing test results to the console.
116
- __output_buffer : Optional[str]
117
- Buffer for capturing standard output during tests.
118
- __error_buffer : Optional[str]
119
- Buffer for capturing error output during tests.
120
- __result : Optional[dict]
121
- Result summary of the test execution.
110
+ Sets up all internal attributes required for test discovery, execution, result reporting, and configuration management. Does not perform test discovery or execution.
122
111
 
123
112
  Returns
124
113
  -------
125
114
  None
126
- This constructor does not return a value.
127
115
  """
128
-
129
116
  # Application instance for dependency injection (set via __setApp)
130
117
  self.__app: Optional[IApplication] = None
131
118
 
@@ -181,42 +168,38 @@ class UnitTest(IUnitTest):
181
168
  web_report: bool
182
169
  ) -> 'UnitTest':
183
170
  """
184
- Configures the UnitTest instance with the main execution and reporting parameters.
185
-
186
- This method sets all relevant options for running unit tests in Orionis, including execution mode
187
- (sequential or parallel), verbosity level, maximum number of workers, result persistence, exception
188
- handling, and web report generation.
171
+ Configure the UnitTest instance with execution and reporting parameters.
189
172
 
190
173
  Parameters
191
174
  ----------
192
- verbosity : int | VerbosityMode
193
- Verbosity level for test output. Can be an integer or a VerbosityMode enum member.
194
- execution_mode : str | ExecutionMode
195
- Test execution mode ('SEQUENTIAL' or 'PARALLEL'), as a string or ExecutionMode enum.
175
+ verbosity : int or VerbosityMode
176
+ Verbosity level for test output.
177
+ execution_mode : str or ExecutionMode
178
+ Execution mode ('SEQUENTIAL' or 'PARALLEL').
196
179
  max_workers : int
197
- Maximum number of threads/processes for parallel execution. Must be between 1 and the maximum allowed by Workers.
180
+ Maximum number of workers for parallel execution.
198
181
  fail_fast : bool
199
- If True, stops execution on the first failure.
182
+ Whether to stop on the first failure.
200
183
  print_result : bool
201
- If True, prints results to the console.
184
+ Whether to print results to the console.
202
185
  throw_exception : bool
203
- If True, raises exceptions on test failures.
186
+ Whether to raise exceptions on test failures.
204
187
  persistent : bool
205
- If True, enables result persistence.
188
+ Whether to enable result persistence.
206
189
  persistent_driver : str or PersistentDrivers
207
- Persistence driver to use ('sqlite' or 'json').
190
+ Persistence driver ('sqlite' or 'json').
208
191
  web_report : bool
209
- If True, enables web report generation.
192
+ Whether to enable web report generation.
210
193
 
211
194
  Returns
212
195
  -------
213
196
  UnitTest
214
- The configured UnitTest instance, allowing method chaining.
197
+ The configured UnitTest instance.
215
198
 
216
199
  Raises
217
200
  ------
218
201
  OrionisTestValueError
219
- If any parameter is invalid or does not meet the expected requirements.
202
+ If any parameter is invalid.
220
203
  """
221
204
 
222
205
  # Validate and assign parameters using specialized validators
@@ -249,48 +232,29 @@ class UnitTest(IUnitTest):
249
232
  """
250
233
  Discover and add unit tests from a specified folder to the test suite.
251
234
 
252
- This method searches for test files within a given folder, using a file name pattern,
253
- and optionally filters discovered tests by test name pattern and tags. All matching
254
- tests are added to the internal test suite. The method also records metadata about
255
- the discovery process, such as the folder path and the number of tests found.
256
-
257
235
  Parameters
258
236
  ----------
259
237
  base_path : str or Path
260
- The base directory from which the folder path is resolved.
238
+ Base directory for resolving the folder path.
261
239
  folder_path : str
262
- The relative path to the folder containing test files, relative to `base_path`.
240
+ Relative path to the folder containing test files.
263
241
  pattern : str
264
- The file name pattern to match test files (e.g., 'test_*.py').
242
+ File name pattern to match test files.
265
243
  test_name_pattern : str, optional
266
- A regular expression pattern to filter test names. Only tests whose names match
267
- this pattern will be included. If None, all test names are included.
244
+ Regular expression pattern to filter test names.
268
245
  tags : list of str, optional
269
- A list of tags to filter tests. Only tests decorated or marked with any of these
270
- tags will be included. If None, no tag filtering is applied.
246
+ Tags to filter tests.
271
247
 
272
248
  Returns
273
249
  -------
274
250
  UnitTest
275
- The current instance with the discovered tests added to the suite.
251
+ The current instance with discovered tests added.
276
252
 
277
253
  Raises
278
254
  ------
279
255
  OrionisTestValueError
280
- If any argument is invalid, the folder does not exist, no tests are found,
281
- or if there are import or discovery errors.
282
-
283
- Notes
284
- -----
285
- - The method validates all input parameters using Orionis validators.
286
- - The folder path is resolved relative to the provided base path.
287
- - Test discovery uses Python's unittest loader.
288
- - If `test_name_pattern` is provided, only tests whose names match the pattern are included.
289
- - If `tags` are provided, only tests with matching tags are included.
290
- - If no tests are found after filtering, an exception is raised.
291
- - Metadata about the discovery (folder and test count) is appended to the internal record.
256
+ If arguments are invalid, folder does not exist, no tests are found, or import/discovery errors occur.
292
257
  """
293
-
294
258
  # Validate Parameters
295
259
  self.__base_path = ValidBasePath(base_path)
296
260
  self.__folder_path = ValidFolderPath(folder_path)
@@ -321,15 +285,17 @@ class UnitTest(IUnitTest):
321
285
  # Check for failed test imports (unittest.loader._FailedTest)
322
286
  for test in self.__flattenTestSuite(tests):
323
287
  if test.__class__.__name__ == "_FailedTest":
288
+
324
289
  # Extract the error message from the test's traceback
325
290
  error_message = ""
326
291
  if hasattr(test, "_exception"):
327
292
  error_message = str(test._exception)
328
293
  elif hasattr(test, "_outcome") and hasattr(test._outcome, "errors"):
329
294
  error_message = str(test._outcome.errors)
295
+ # Try to get error from test id or str(test)
330
296
  else:
331
- # Try to get error from test id or str(test)
332
297
  error_message = str(test)
298
+
333
299
  raise OrionisTestValueError(
334
300
  f"Failed to import test module: {test.id()}.\n"
335
301
  f"Error details: {error_message}\n"
@@ -400,38 +366,22 @@ class UnitTest(IUnitTest):
400
366
  """
401
367
  Discover and add unit tests from a specified Python module to the test suite.
402
368
 
403
- This method loads all unit tests defined within the given module and adds them to the internal test suite.
404
- Optionally, it can filter discovered tests by a regular expression pattern applied to test names.
405
-
406
369
  Parameters
407
370
  ----------
408
371
  module_name : str
409
- The fully qualified name of the module from which to discover tests (e.g., 'myproject.tests.test_example').
410
- Must be a non-empty string and importable from the current environment.
411
- test_name_pattern : str or None, optional
412
- A regular expression pattern to filter test names. Only tests whose names match this pattern
413
- will be included in the suite. If None, all discovered tests are included.
372
+ Fully qualified name of the module to discover tests from.
373
+ test_name_pattern : str, optional
374
+ Regular expression pattern to filter test names.
414
375
 
415
376
  Returns
416
377
  -------
417
378
  UnitTest
418
- The current UnitTest instance with the discovered tests added, allowing method chaining.
379
+ The current UnitTest instance with discovered tests added.
419
380
 
420
381
  Raises
421
382
  ------
422
383
  OrionisTestValueError
423
- If `module_name` is invalid, `test_name_pattern` is not a valid regex, the module cannot be imported,
424
- or if no tests are found after filtering.
425
- OrionisTestValueError
426
- For any unexpected error during test discovery, with details about the failure.
427
-
428
- Notes
429
- -----
430
- - Input parameters are validated using Orionis validators before discovery.
431
- - If `test_name_pattern` is provided, only tests matching the pattern are included.
432
- - Metadata about the discovery (module name and test count) is appended to the internal `__discovered_tests` list.
433
- - This method is useful for dynamically loading tests from specific modules, such as in plugin architectures or
434
- when tests are not organized in standard file patterns.
384
+ If module_name is invalid, test_name_pattern is not a valid regex, the module cannot be imported, or no tests are found.
435
385
  """
436
386
 
437
387
  # Validate input parameters
@@ -503,28 +453,16 @@ class UnitTest(IUnitTest):
503
453
  """
504
454
  Execute the test suite and return a summary of the results.
505
455
 
506
- This method manages the full test execution lifecycle: it prints start and finish messages,
507
- executes the test suite, captures output and error buffers, processes the results, and
508
- optionally raises an exception if failures occur and exception throwing is enabled.
509
-
510
456
  Returns
511
457
  -------
512
- Dict[str, Any]
513
- A dictionary summarizing the test results, including statistics and execution time.
458
+ dict
459
+ Dictionary summarizing the test results, including statistics and execution time.
514
460
 
515
461
  Raises
516
462
  ------
517
463
  OrionisTestFailureException
518
- If the test suite execution fails and `throw_exception` is set to True.
519
-
520
- Notes
521
- -----
522
- - Measures total execution time in milliseconds.
523
- - Uses the configured printer to display start, result, and finish messages.
524
- - Captures and stores output and error buffers.
525
- - Raises an exception if tests fail and exception throwing is enabled.
464
+ If the test suite execution fails and throw_exception is True.
526
465
  """
527
-
528
466
  # Record the start time in nanoseconds
529
467
  start_time = time.time_ns()
530
468
 
@@ -569,161 +507,122 @@ class UnitTest(IUnitTest):
569
507
  suite: unittest.TestSuite
570
508
  ) -> List[unittest.TestCase]:
571
509
  """
572
- Recursively flattens a (potentially nested) unittest.TestSuite into a list of unique unittest.TestCase instances.
573
-
574
- This method traverses the provided test suite, which may contain nested suites or individual test cases,
575
- and collects all unique TestCase instances into a flat list. It ensures that each test case appears only once
576
- in the resulting list, based on a short identifier derived from the test's id. This is particularly useful
577
- for operations that require direct access to all test cases, such as filtering, counting, or custom execution.
510
+ Recursively flattens a unittest.TestSuite into a list of unique unittest.TestCase instances.
578
511
 
579
512
  Parameters
580
513
  ----------
581
514
  suite : unittest.TestSuite
582
- The test suite to flatten. This can be a single suite, a nested suite, or a suite containing test cases.
515
+ The test suite to be flattened.
583
516
 
584
517
  Returns
585
518
  -------
586
519
  List[unittest.TestCase]
587
- A flat list containing all unique unittest.TestCase instances found within the input suite.
520
+ A flat list containing unique unittest.TestCase instances extracted from the suite.
588
521
 
589
522
  Notes
590
523
  -----
591
- - The uniqueness of test cases is determined by a "short id", which is composed of the last two segments
592
- of the test's full id (typically "ClassName.methodName"). This helps avoid duplicate test cases in the result.
593
- - The method uses recursion to traverse all levels of nested suites.
594
- - Only objects with an 'id' attribute (i.e., test cases) are included in the result.
524
+ Test uniqueness is determined by a shortened test identifier (the last two components of the test id).
525
+ This helps avoid duplicate test cases in the returned list.
595
526
  """
527
+
528
+ # Initialize an empty list to hold unique test cases and a set to track seen test IDs
596
529
  tests = []
597
530
  seen_ids = set()
598
531
 
532
+ # Recursive function to flatten the test suite
599
533
  def _flatten(item):
600
- """
601
- Recursively process a TestSuite or test case, collecting unique test cases.
602
-
603
- - If the item is a TestSuite, recursively process its children.
604
- - If the item is a test case (has 'id'), generate a short id and add it if not already seen.
605
- """
606
534
  if isinstance(item, unittest.TestSuite):
607
- # Recursively flatten all sub-items in the suite
608
535
  for sub_item in item:
609
536
  _flatten(sub_item)
610
537
  elif hasattr(item, "id"):
611
- # Generate a short id for uniqueness (e.g., "ClassName.methodName")
612
538
  test_id = item.id()
539
+
540
+ # Use the last two components of the test id for uniqueness
613
541
  parts = test_id.split('.')
614
542
  if len(parts) >= 2:
615
543
  short_id = '.'.join(parts[-2:])
616
544
  else:
617
545
  short_id = test_id
618
- # Add the test case only if its short id has not been seen
619
546
  if short_id not in seen_ids:
620
547
  seen_ids.add(short_id)
621
548
  tests.append(item)
622
549
 
623
- # Start flattening from the root suite
550
+ # Start the flattening process
624
551
  _flatten(suite)
625
-
626
- # Return a flat list of unique unittest.TestCase instances
627
552
  return tests
628
553
 
629
554
  def __runSuite(
630
555
  self
631
556
  ) -> Tuple[unittest.TestResult, io.StringIO, io.StringIO]:
632
557
  """
633
- Executes the test suite using the configured execution mode (sequential or parallel),
634
- while capturing both standard output and error streams during the test run.
635
-
636
- This method determines the execution mode (sequential or parallel) based on the current
637
- configuration and delegates the actual test execution to the appropriate internal method.
638
- It ensures that all output and error messages generated during the test run are captured
639
- in dedicated buffers for later inspection or reporting.
558
+ Executes the test suite according to the configured execution mode, capturing both standard output and error streams.
640
559
 
641
560
  Returns
642
561
  -------
643
- Tuple[unittest.TestResult, io.StringIO, io.StringIO]
644
- A tuple containing:
645
- - result: The unittest.TestResult object with detailed information about the test run,
646
- including passed, failed, errored, and skipped tests.
647
- - output_buffer: An io.StringIO object containing all captured standard output produced
648
- during the test execution.
649
- - error_buffer: An io.StringIO object containing all captured standard error output
650
- produced during the test execution.
651
-
652
- Notes
653
- -----
654
- - The execution mode is determined by the value of self.__execution_mode.
655
- - Output and error streams are always captured, regardless of execution mode.
656
- - The returned buffers can be used for further processing, logging, or displaying test output.
562
+ tuple
563
+ result : unittest.TestResult
564
+ The result object containing the outcomes of the executed tests.
565
+ output_buffer : io.StringIO
566
+ Buffer capturing the standard output generated during test execution.
567
+ error_buffer : io.StringIO
568
+ Buffer capturing the standard error generated during test execution.
657
569
  """
658
570
 
659
- # Create buffers to capture standard output and error during test execution
571
+ # Initialize output and error buffers to capture test execution output
660
572
  output_buffer = io.StringIO()
661
573
  error_buffer = io.StringIO()
662
574
 
663
- # Determine execution mode and run tests accordingly
575
+ # Run tests in parallel mode using multiple workers
664
576
  if self.__execution_mode == ExecutionMode.PARALLEL.value:
665
- # Run tests in parallel mode
666
577
  result = self.__runTestsInParallel(
667
578
  output_buffer,
668
579
  error_buffer
669
580
  )
581
+
582
+ # Run tests sequentially
670
583
  else:
671
- # Run tests sequentially (default)
672
584
  result = self.__runTestsSequentially(
673
585
  output_buffer,
674
586
  error_buffer
675
587
  )
676
588
 
677
- # Return the test result along with the captured output and error buffers
589
+ # Return the result, output, and error buffers
678
590
  return result, output_buffer, error_buffer
679
591
 
680
592
  def __resolveFlattenedTestSuite(
681
593
  self
682
594
  ) -> unittest.TestSuite:
683
595
  """
684
- Resolves and injects dependencies for all test cases in the suite, returning a flattened TestSuite.
596
+ Resolves and injects dependencies for all test cases in the current suite, returning a flattened TestSuite.
685
597
 
686
- This method processes each test case in the internal suite, inspects the test method signatures,
687
- and uses the application's dependency resolver to inject any required dependencies. It handles
688
- decorated methods, methods without dependencies, and raises errors for unresolved dependencies.
689
- The result is a new, flat unittest.TestSuite containing test cases with all dependencies resolved
690
- and injected, ready for execution.
691
-
692
- Parameters
693
- ----------
694
- None
598
+ This method iterates through all test cases in the suite, checks for failed imports, decorated methods, and unresolved dependencies.
599
+ For each test case, it uses reflection to determine the test method and its dependencies. If dependencies are required and can be resolved,
600
+ it injects them using the application's resolver. If a test method has unresolved dependencies, an exception is raised.
601
+ Decorated methods and failed imports are added as-is. The resulting TestSuite contains all test cases with dependencies injected where needed.
695
602
 
696
603
  Returns
697
604
  -------
698
605
  unittest.TestSuite
699
- A new TestSuite containing all test cases from the original suite, with dependencies injected
700
- where required. Test cases with unresolved dependencies will cause an exception to be raised.
606
+ A new TestSuite containing all test cases with dependencies injected as required.
701
607
 
702
608
  Raises
703
609
  ------
704
610
  OrionisTestValueError
705
- If any test method has dependencies that cannot be resolved.
706
-
707
- Notes
708
- -----
709
- - Decorated test methods are left unchanged and added as-is.
710
- - Test methods without dependencies are added directly.
711
- - Test methods with unresolved dependencies will trigger an error.
712
- - The returned TestSuite is flat and contains all processed test cases.
611
+ If any test method has unresolved dependencies that cannot be resolved by the resolver.
713
612
  """
714
613
 
715
- # Create a new test suite to hold test cases with dependencies resolved
614
+ # Create a new TestSuite to hold the resolved test cases
716
615
  flattened_suite = unittest.TestSuite()
717
616
 
718
- # Iterate through all test cases in the original (possibly nested) suite
617
+ # Iterate through all test cases in the flattened suite
719
618
  for test_case in self.__flattenTestSuite(self.__suite):
720
619
 
721
- # If it's a failed test, add it as-is to the flattened suite
620
+ # If the test case is a failed import, add it directly
722
621
  if test_case.__class__.__name__ == "_FailedTest":
723
622
  flattened_suite.addTest(test_case)
724
623
  continue
725
624
 
726
- # Get the test method name using reflection
625
+ # Use reflection to get the test method name
727
626
  rf_instance = ReflectionInstance(test_case)
728
627
  method_name = rf_instance.getAttribute("_testMethodName")
729
628
 
@@ -732,30 +631,29 @@ class UnitTest(IUnitTest):
732
631
  flattened_suite.addTest(test_case)
733
632
  continue
734
633
 
735
- # Retrieve the actual test method object from the class
634
+ # Retrieve the test method from the class
736
635
  test_method = getattr(test_case.__class__, method_name, None)
737
636
 
738
- # Check if the test method is decorated by looking for __wrapped__ attributes
637
+ # Check if the method is decorated (wrapped)
739
638
  decorators = []
740
639
  if hasattr(test_method, '__wrapped__'):
741
640
  original = test_method
742
641
  while hasattr(original, '__wrapped__'):
743
- # Collect decorator names for informational purposes
744
642
  if hasattr(original, '__qualname__'):
745
643
  decorators.append(original.__qualname__)
746
644
  elif hasattr(original, '__name__'):
747
645
  decorators.append(original.__name__)
748
646
  original = original.__wrapped__
749
647
 
750
- # If decorators are present, add the test case as-is (do not inject dependencies)
648
+ # If decorators are present, add the test case as-is
751
649
  if decorators:
752
650
  flattened_suite.addTest(test_case)
753
651
  continue
754
652
 
755
- # Attempt to extract dependency information from the test method signature
653
+ # Get the method's dependency signature
756
654
  signature = rf_instance.getMethodDependencies(method_name)
757
655
 
758
- # If there are no dependencies to resolve, or unresolved dependencies exist, add as-is
656
+ # If no dependencies are required or unresolved, add the test case as-is
759
657
  if ((not signature.resolved and not signature.unresolved) or (not signature.resolved and len(signature.unresolved) > 0)):
760
658
  flattened_suite.addTest(test_case)
761
659
  continue
@@ -767,32 +665,25 @@ class UnitTest(IUnitTest):
767
665
  "Please ensure all dependencies are correctly defined and available."
768
666
  )
769
667
 
770
- # All dependencies are resolved; prepare to inject them into the test method
668
+ # Get the original test class and method
771
669
  test_class = ReflectionInstance(test_case).getClass()
772
670
  original_method = getattr(test_class, method_name)
773
671
 
774
672
  # Resolve dependencies using the application's resolver
775
673
  params = Resolver(self.__app).resolveSignature(signature)
776
674
 
777
- # Create a wrapper function that injects resolved dependencies into the test method
675
+ # Create a wrapper to inject resolved dependencies into the test method
778
676
  def create_test_wrapper(original_test, resolved_args: dict):
779
677
  def wrapper(self_instance):
780
678
  return original_test(self_instance, **resolved_args)
781
679
  return wrapper
782
680
 
783
- # Wrap the original test method with the dependency-injecting wrapper
784
- wrapped_method = create_test_wrapper(original_method, params)
785
-
786
681
  # Bind the wrapped method to the test case instance
682
+ wrapped_method = create_test_wrapper(original_method, params)
787
683
  bound_method = wrapped_method.__get__(test_case, test_case.__class__)
788
-
789
- # Replace the original test method on the test case with the wrapped version
790
684
  setattr(test_case, method_name, bound_method)
791
-
792
- # Add the modified test case to the flattened suite
793
685
  flattened_suite.addTest(test_case)
794
686
 
795
- # Return the new flattened suite with all dependencies resolved and injected
796
687
  return flattened_suite
797
688
 
798
689
  def __runTestsSequentially(
@@ -801,31 +692,45 @@ class UnitTest(IUnitTest):
801
692
  error_buffer: io.StringIO
802
693
  ) -> unittest.TestResult:
803
694
  """
804
- Executes the test suite sequentially, capturing the output and error streams.
695
+ Executes all test cases in the test suite sequentially, capturing standard output and error streams.
805
696
 
806
697
  Parameters
807
698
  ----------
808
699
  output_buffer : io.StringIO
809
- A buffer to capture the standard output during test execution.
700
+ Buffer to capture the standard output generated during test execution.
810
701
  error_buffer : io.StringIO
811
- A buffer to capture the standard error during test execution.
702
+ Buffer to capture the standard error generated during test execution.
812
703
 
813
704
  Returns
814
705
  -------
815
706
  unittest.TestResult
816
- The result of the test suite execution, containing information about
817
- passed, failed, and skipped tests.
707
+ The aggregated result object containing the outcomes of all executed test cases.
708
+
709
+ Raises
710
+ ------
711
+ OrionisTestValueError
712
+ If an item in the suite is not a valid unittest.TestCase instance.
713
+
714
+ Notes
715
+ -----
716
+ Each test case is executed individually, and results are merged into a single result object.
717
+ Output and error streams are redirected for each test case to ensure complete capture.
718
+ The printer is used to display the result of each test immediately after execution.
818
719
  """
819
720
 
820
- # Create a custom result class to capture detailed test results
721
+ # Initialize output and error buffers to capture test execution output
821
722
  result = None
723
+
724
+ # Iterate through all resolved test cases in the suite
822
725
  for case in self.__resolveFlattenedTestSuite():
823
726
 
727
+ # Ensure the test case is a valid unittest.TestCase instance
824
728
  if not isinstance(case, unittest.TestCase):
825
729
  raise OrionisTestValueError(
826
730
  f"Invalid test case type: Expected unittest.TestCase, got {type(case).__name__}."
827
731
  )
828
732
 
733
+ # Redirect output and error streams for the current test case
829
734
  with redirect_stdout(output_buffer), redirect_stderr(error_buffer):
830
735
  runner = unittest.TextTestRunner(
831
736
  stream=output_buffer,
@@ -833,18 +738,19 @@ class UnitTest(IUnitTest):
833
738
  failfast=self.__fail_fast,
834
739
  resultclass=self.__customResultClass()
835
740
  )
741
+ # Run the current test case and obtain the result
836
742
  single_result: IOrionisTestResult = runner.run(unittest.TestSuite([case]))
837
743
 
838
- # Print a concise summary for each test.
744
+ # Print the result of the current test case using the printer
839
745
  self.__printer.unittestResult(single_result.test_results[0])
840
746
 
841
- # Merge results
747
+ # Merge the result of the current test case into the aggregated result
842
748
  if result is None:
843
749
  result = single_result
844
750
  else:
845
751
  self.__mergeTestResults(result, single_result)
846
752
 
847
- # Return the result object containing test outcomes
753
+ # Return the aggregated result containing all test outcomes
848
754
  return result
849
755
 
850
756
  def __runTestsInParallel(
@@ -853,82 +759,72 @@ class UnitTest(IUnitTest):
853
759
  error_buffer: io.StringIO
854
760
  ) -> unittest.TestResult:
855
761
  """
856
- Executes all test cases in the test suite concurrently using a thread pool,
857
- aggregating their results into a single result object. Standard output and error
858
- streams are redirected to the provided buffers during execution.
859
-
860
- This method is designed to speed up test execution by running multiple test cases
861
- in parallel threads, making use of the configured maximum number of workers. Each
862
- test case is executed in isolation, and their results are merged into a combined
863
- result object. If the `fail_fast` option is enabled and a test fails, remaining
864
- tests are canceled as soon as possible.
762
+ Executes all test cases in the test suite concurrently using a thread pool and aggregates their results.
865
763
 
866
764
  Parameters
867
765
  ----------
868
766
  output_buffer : io.StringIO
869
- Buffer to capture standard output produced during test execution.
767
+ Buffer to capture the standard output generated during test execution.
870
768
  error_buffer : io.StringIO
871
- Buffer to capture standard error produced during test execution.
769
+ Buffer to capture the standard error generated during test execution.
872
770
 
873
771
  Returns
874
772
  -------
875
773
  unittest.TestResult
876
- A combined result object (instance of the custom result class) containing
877
- the aggregated outcomes of all executed tests, including detailed information
878
- about passed, failed, errored, and skipped tests.
774
+ Combined result object containing the outcomes of all executed test cases.
879
775
 
880
776
  Notes
881
777
  -----
882
- - Uses a custom result class to collect detailed test outcomes.
883
- - If `fail_fast` is enabled and a test fails, remaining tests are canceled.
884
- - Output and error streams are captured for the entire parallel execution.
778
+ Each test case is executed in a separate thread using a ThreadPoolExecutor.
779
+ Results from all threads are merged into a single result object.
780
+ Output and error streams are redirected for the entire parallel execution.
781
+ If fail-fast is enabled, execution stops as soon as a failure is detected.
885
782
  """
886
783
 
887
- # Flatten the test suite to get individual test cases
784
+ # Resolve and flatten all test cases in the suite, injecting dependencies if needed
888
785
  test_cases = list(self.__resolveFlattenedTestSuite())
889
786
 
890
- # Create a custom result instance to collect all results
787
+ # Get the custom result class for enhanced test tracking
891
788
  result_class = self.__customResultClass()
789
+
790
+ # Create a combined result object to aggregate all individual test results
892
791
  combined_result = result_class(io.StringIO(), descriptions=True, verbosity=self.__verbosity)
893
792
 
894
- # Helper function to run a single test and return its result.
895
- # Each test runs in its own thread with minimal output.
793
+ # Define a function to run a single test case and return its result
896
794
  def run_single_test(test):
897
795
  runner = unittest.TextTestRunner(
898
- stream=io.StringIO(), # Use a dummy stream for individual test output
796
+ stream=io.StringIO(), # Use a separate buffer for each test
899
797
  verbosity=0,
900
798
  failfast=False,
901
799
  resultclass=result_class
902
800
  )
903
- # Run the test and return its result object
904
801
  return runner.run(unittest.TestSuite([test]))
905
802
 
906
- # Redirect stdout and stderr to the provided buffers during parallel execution
803
+ # Redirect output and error streams for the entire parallel execution
907
804
  with redirect_stdout(output_buffer), redirect_stderr(error_buffer):
908
805
 
909
- # Create a ThreadPoolExecutor to run tests in parallel
806
+ # Create a thread pool with the configured number of workers
910
807
  with ThreadPoolExecutor(max_workers=self.__max_workers) as executor:
911
808
 
912
- # Submit all test cases to the executor
809
+ # Submit all test cases to the thread pool for execution
913
810
  futures = [executor.submit(run_single_test, test) for test in test_cases]
914
811
 
915
- # Process the results as they complete
812
+ # As each test completes, merge its result into the combined result
916
813
  for future in as_completed(futures):
917
814
  test_result = future.result()
918
- # Merge each individual test result into the combined result
919
815
  self.__mergeTestResults(combined_result, test_result)
920
816
 
921
- # If fail_fast is enabled and a test failed, cancel remaining futures
817
+ # If fail-fast is enabled and a failure occurs, cancel remaining tests
922
818
  if self.__fail_fast and not combined_result.wasSuccessful():
923
819
  for f in futures:
924
820
  f.cancel()
925
821
  break
926
822
 
927
- # Print a concise summary for each test in the combined result
823
+ # Print the result of each individual test using the printer
928
824
  for test_result in combined_result.test_results:
929
825
  self.__printer.unittestResult(test_result)
930
826
 
931
- # Return the combined result object containing all test outcomes
827
+ # Return the aggregated result containing all test outcomes
932
828
  return combined_result
933
829
 
934
830
  def __mergeTestResults(
@@ -939,42 +835,45 @@ class UnitTest(IUnitTest):
939
835
  """
940
836
  Merge the results of two unittest.TestResult objects into a single result.
941
837
 
942
- This method updates the `combined_result` object by aggregating the test run counts,
943
- failures, errors, skipped tests, expected failures, and unexpected successes from the
944
- `individual_result` object. It also merges any custom test results stored in the
945
- `test_results` attribute, if present, ensuring that all detailed test outcomes are
946
- included in the combined result.
947
-
948
838
  Parameters
949
839
  ----------
950
840
  combined_result : unittest.TestResult
951
- The TestResult object that will be updated to include the results from `individual_result`.
841
+ The TestResult object that will be updated with the merged results.
952
842
  individual_result : unittest.TestResult
953
- The TestResult object whose results will be merged into `combined_result`.
843
+ The TestResult object whose results will be merged into the combined_result.
954
844
 
955
845
  Returns
956
846
  -------
957
847
  None
958
- This method does not return a value. It modifies `combined_result` in place.
848
+ This method does not return a value. It updates combined_result in place.
959
849
 
960
850
  Notes
961
851
  -----
962
- - The method aggregates all relevant test outcome lists and counters.
963
- - If the `test_results` attribute exists (for custom result classes), it is also merged.
964
- - This is useful for combining results from parallel or sequential test executions.
852
+ This method aggregates the test statistics and detailed results from individual_result into combined_result.
853
+ It updates the total number of tests run, and extends the lists of failures, errors, skipped tests,
854
+ expected failures, and unexpected successes. If the result objects contain a 'test_results' attribute,
855
+ this method also merges the detailed test result entries.
965
856
  """
966
857
 
967
- # Aggregate the number of tests run
858
+ # Increment the total number of tests run
968
859
  combined_result.testsRun += individual_result.testsRun
969
860
 
970
- # Extend the lists of failures, errors, skipped, expected failures, and unexpected successes
861
+ # Extend the list of failures with those from the individual result
971
862
  combined_result.failures.extend(individual_result.failures)
863
+
864
+ # Extend the list of errors with those from the individual result
972
865
  combined_result.errors.extend(individual_result.errors)
866
+
867
+ # Extend the list of skipped tests with those from the individual result
973
868
  combined_result.skipped.extend(individual_result.skipped)
869
+
870
+ # Extend the list of expected failures with those from the individual result
974
871
  combined_result.expectedFailures.extend(individual_result.expectedFailures)
872
+
873
+ # Extend the list of unexpected successes with those from the individual result
975
874
  combined_result.unexpectedSuccesses.extend(individual_result.unexpectedSuccesses)
976
875
 
977
- # Merge custom test results if present (for enhanced result tracking)
876
+ # If the individual result contains detailed test results, merge them as well
978
877
  if hasattr(individual_result, 'test_results'):
979
878
  if not hasattr(combined_result, 'test_results'):
980
879
  combined_result.test_results = []
@@ -984,46 +883,45 @@ class UnitTest(IUnitTest):
984
883
  self
985
884
  ) -> type:
986
885
  """
987
- Creates a custom test result class for enhanced test tracking.
988
- This method dynamically generates an `OrionisTestResult` class that extends
989
- `unittest.TextTestResult`. The custom class provides advanced functionality for
990
- tracking test execution details, including timings, statuses, and error information.
886
+ Create and return a custom test result class for enhanced test tracking.
991
887
 
992
888
  Returns
993
889
  -------
994
890
  type
995
- A dynamically created class `OrionisTestResult` that overrides methods to handle
996
- test results, including success, failure, error, and skipped tests. The class
997
- collects detailed information about each test, such as execution time, error
998
- messages, traceback, and file path.
891
+ A dynamically created subclass of unittest.TextTestResult that collects
892
+ detailed information about each test execution, including timing, status,
893
+ error messages, tracebacks, and metadata.
999
894
 
1000
895
  Notes
1001
896
  -----
1002
- The `OrionisTestResult` class includes the following method overrides:
1003
- The method uses the `this` reference to access the outer class's methods, such as
1004
- `_extractErrorInfo`, for extracting and formatting error information.
897
+ The returned class, OrionisTestResult, extends unittest.TextTestResult and
898
+ overrides key methods to capture additional data for each test case. This
899
+ includes execution time, error details, and test metadata, which are stored
900
+ in a list of TestResult objects for later reporting and analysis.
1005
901
  """
1006
-
1007
- # Use `this` to refer to the outer class instance
1008
902
  this = self
1009
903
 
1010
- # Define the custom test result class
1011
904
  class OrionisTestResult(unittest.TextTestResult):
905
+
906
+ # Initialize the parent class and custom attributes for tracking results and timings
1012
907
  def __init__(self, *args, **kwargs):
1013
908
  super().__init__(*args, **kwargs)
1014
- self.test_results = []
1015
- self._test_timings = {}
1016
- self._current_test_start = None
909
+ self.test_results = [] # Stores detailed results for each test
910
+ self._test_timings = {} # Maps test instances to their execution time
911
+ self._current_test_start = None # Tracks the start time of the current test
1017
912
 
913
+ # Record the start time of the test
1018
914
  def startTest(self, test):
1019
915
  self._current_test_start = time.time()
1020
916
  super().startTest(test)
1021
917
 
918
+ # Calculate and store the elapsed time for the test
1022
919
  def stopTest(self, test):
1023
920
  elapsed = time.time() - self._current_test_start
1024
921
  self._test_timings[test] = elapsed
1025
922
  super().stopTest(test)
1026
923
 
924
+ # Handle a successful test case and record its result
1027
925
  def addSuccess(self, test):
1028
926
  super().addSuccess(test)
1029
927
  elapsed = self._test_timings.get(test, 0.0)
@@ -1041,6 +939,7 @@ class UnitTest(IUnitTest):
1041
939
  )
1042
940
  )
1043
941
 
942
+ # Handle a failed test case, extract error info, and record its result
1044
943
  def addFailure(self, test, err):
1045
944
  super().addFailure(test, err)
1046
945
  elapsed = self._test_timings.get(test, 0.0)
@@ -1062,6 +961,7 @@ class UnitTest(IUnitTest):
1062
961
  )
1063
962
  )
1064
963
 
964
+ # Handle a test case that raised an error, extract error info, and record its result
1065
965
  def addError(self, test, err):
1066
966
  super().addError(test, err)
1067
967
  elapsed = self._test_timings.get(test, 0.0)
@@ -1083,6 +983,7 @@ class UnitTest(IUnitTest):
1083
983
  )
1084
984
  )
1085
985
 
986
+ # Handle a skipped test case and record its result
1086
987
  def addSkip(self, test, reason):
1087
988
  super().addSkip(test, reason)
1088
989
  elapsed = self._test_timings.get(test, 0.0)
@@ -1111,11 +1012,6 @@ class UnitTest(IUnitTest):
1111
1012
  """
1112
1013
  Extracts the file path and a cleaned traceback from a given traceback string.
1113
1014
 
1114
- This method analyzes a Python traceback string to determine the file path of the Python file
1115
- where the error occurred (typically the last file in the traceback). It also removes lines
1116
- related to framework internals and irrelevant noise, such as those containing 'unittest/',
1117
- 'lib/python', or 'site-packages', to produce a more concise and relevant traceback for reporting.
1118
-
1119
1015
  Parameters
1120
1016
  ----------
1121
1017
  traceback_str : str
@@ -1123,21 +1019,23 @@ class UnitTest(IUnitTest):
1123
1019
 
1124
1020
  Returns
1125
1021
  -------
1126
- Tuple[Optional[str], Optional[str]]
1127
- A tuple containing:
1128
- - file_path (Optional[str]): The path to the Python file where the error occurred, or None if not found.
1129
- - clean_tb (Optional[str]): The cleaned traceback string, with framework internals and unrelated lines removed.
1022
+ tuple
1023
+ file_path : str or None
1024
+ The path to the Python file where the error occurred, or None if not found.
1025
+ clean_tb : str or None
1026
+ The cleaned traceback string with framework internals removed, or the original traceback if no cleaning was possible.
1130
1027
 
1131
1028
  Notes
1132
1029
  -----
1133
- The cleaned traceback starts from the first occurrence of the test file path and omits lines
1134
- that are part of the Python standard library or third-party packages, focusing on user code.
1030
+ This method parses the traceback string to identify the most relevant file path (typically the last Python file in the traceback).
1031
+ It then filters out lines related to framework internals (such as 'unittest/', 'lib/python', or 'site-packages') to produce a more concise and relevant traceback.
1032
+ The cleaned traceback starts from the first occurrence of the relevant file path.
1135
1033
  """
1136
1034
 
1137
- # Extract all Python file paths from the traceback string
1035
+ # Find all Python file paths in the traceback
1138
1036
  file_matches = re.findall(r'File ["\'](.*?.py)["\']', traceback_str)
1139
1037
 
1140
- # Use the last file in the traceback as the most relevant (where the error occurred)
1038
+ # Select the last file path as the most relevant one
1141
1039
  file_path = file_matches[-1] if file_matches else None
1142
1040
 
1143
1041
  # Split the traceback into individual lines for processing
@@ -1145,25 +1043,21 @@ class UnitTest(IUnitTest):
1145
1043
  clean_lines = []
1146
1044
  relevant_lines_started = False
1147
1045
 
1148
- # Iterate through each line in the traceback
1046
+ # Iterate through each line to filter out framework internals
1149
1047
  for line in tb_lines:
1150
1048
 
1151
- # Skip lines that are part of framework internals or third-party libraries
1049
+ # Skip lines that are part of unittest, Python standard library, or site-packages
1152
1050
  if any(s in line for s in ['unittest/', 'lib/python', 'site-packages']):
1153
1051
  continue
1154
1052
 
1155
- # Start including lines once the relevant file path is found
1053
+ # Start collecting lines from the first occurrence of the relevant file path
1156
1054
  if file_path and file_path in line and not relevant_lines_started:
1157
1055
  relevant_lines_started = True
1158
-
1159
- # If we've started collecting relevant lines, add them to the cleaned traceback
1160
1056
  if relevant_lines_started:
1161
1057
  clean_lines.append(line)
1162
1058
 
1163
- # Join the cleaned lines into a single string; if none, return the original traceback
1059
+ # Join the filtered lines to form the cleaned traceback
1164
1060
  clean_tb = str('\n').join(clean_lines) if clean_lines else traceback_str
1165
-
1166
- # Return the file path and cleaned traceback
1167
1061
  return file_path, clean_tb
1168
1062
 
1169
1063
  def __generateSummary(
@@ -1172,51 +1066,31 @@ class UnitTest(IUnitTest):
1172
1066
  execution_time: float
1173
1067
  ) -> Dict[str, Any]:
1174
1068
  """
1175
- Generates a comprehensive summary of the test suite execution.
1176
-
1177
- This method processes the provided unittest.TestResult object and aggregates
1178
- statistics such as the total number of tests, counts of passed, failed, errored,
1179
- and skipped tests, as well as the overall execution time and success rate.
1180
- It also collects detailed information for each individual test, including
1181
- identifiers, class and method names, status, execution time, error messages,
1182
- tracebacks, file paths, and docstrings.
1183
-
1184
- If result persistence is enabled, the summary is saved using the configured
1185
- persistence driver (e.g., SQLite or JSON). If web reporting is enabled, a
1186
- web report is generated and linked.
1069
+ Generates a summary dictionary of the test suite execution, including statistics,
1070
+ timing, and detailed results for each test. Optionally persists the summary and/or
1071
+ generates a web report if configured.
1187
1072
 
1188
1073
  Parameters
1189
1074
  ----------
1190
1075
  result : unittest.TestResult
1191
1076
  The result object containing details of the test execution.
1192
1077
  execution_time : float
1193
- The total execution time of the test suite in milliseconds.
1078
+ The total execution time of the test suite in seconds.
1194
1079
 
1195
1080
  Returns
1196
1081
  -------
1197
- Dict[str, Any]
1198
- A dictionary containing:
1199
- - total_tests (int): Total number of tests executed.
1200
- - passed (int): Number of tests that passed.
1201
- - failed (int): Number of tests that failed.
1202
- - errors (int): Number of tests that encountered errors.
1203
- - skipped (int): Number of tests that were skipped.
1204
- - total_time (float): Total execution time in milliseconds.
1205
- - success_rate (float): Percentage of tests that passed.
1206
- - test_details (List[Dict[str, Any]]): List of dictionaries with details for each test,
1207
- including id, class, method, status, execution_time, error_message, traceback,
1208
- file_path, and doc_string.
1209
- - timestamp (str): ISO-formatted timestamp of when the summary was generated.
1210
-
1211
- Side Effects
1212
- ------------
1213
- - If persistence is enabled, the summary is persisted to storage.
1082
+ dict
1083
+ A dictionary containing test statistics, details, and metadata.
1084
+
1085
+ Notes
1086
+ -----
1087
+ - If persistence is enabled, the summary is saved to storage.
1214
1088
  - If web reporting is enabled, a web report is generated.
1089
+ - The summary includes per-test details, overall statistics, and a timestamp.
1215
1090
  """
1216
1091
 
1217
- test_details = []
1218
-
1219
1092
  # Collect detailed information for each test result
1093
+ test_details = []
1220
1094
  for test_result in result.test_results:
1221
1095
  rst: TestResult = test_result
1222
1096
  test_details.append({
@@ -1233,10 +1107,11 @@ class UnitTest(IUnitTest):
1233
1107
 
1234
1108
  # Calculate the number of passed tests
1235
1109
  passed = result.testsRun - len(result.failures) - len(result.errors) - len(result.skipped)
1110
+
1236
1111
  # Calculate the success rate as a percentage
1237
1112
  success_rate = (passed / result.testsRun * 100) if result.testsRun > 0 else 100.0
1238
1113
 
1239
- # Build the summary dictionary
1114
+ # Build the summary dictionary with all relevant statistics and details
1240
1115
  self.__result = {
1241
1116
  "total_tests": result.testsRun,
1242
1117
  "passed": passed,
@@ -1267,38 +1142,33 @@ class UnitTest(IUnitTest):
1267
1142
  """
1268
1143
  Generate a web-based report for the provided test results summary.
1269
1144
 
1270
- This method creates a web report for the test execution summary using the `TestingResultRender` class.
1271
- It determines the appropriate storage path for the report, configures persistence options based on the
1272
- current settings, and invokes the rendering process. After generating the report, it prints a link to
1273
- the web report using the configured printer.
1274
-
1275
1145
  Parameters
1276
1146
  ----------
1277
1147
  summary : dict
1278
- The summary of test results for which the web report will be generated.
1148
+ Summary of test results for web report generation.
1279
1149
 
1280
1150
  Returns
1281
1151
  -------
1282
1152
  None
1283
- This method does not return any value. The generated web report is rendered and a link to it is printed
1284
- to the console via the printer.
1285
1153
 
1286
1154
  Notes
1287
1155
  -----
1288
- - The storage path for the report is determined by `self.__base_path`.
1289
- - If result persistence is enabled and the driver is set to 'sqlite', the report is marked as persistent.
1290
- - The web report is generated using the `TestingResultRender` class.
1291
- - The method prints the link to the generated web report using the printer.
1156
+ This method creates a web-based report for the given test results summary.
1157
+ It uses the TestingResultRender class to generate the report, passing the storage path,
1158
+ the summary result, and a flag indicating whether to persist the report based on the
1159
+ persistence configuration and driver. After rendering, it prints a link to the generated
1160
+ web report using the printer.
1292
1161
  """
1293
1162
 
1294
- # Create the TestingResultRender instance with the storage path and summary.
1163
+ # Create a TestingResultRender instance with the storage path, result summary,
1164
+ # and persistence flag (True if persistent and using sqlite driver)
1295
1165
  render = TestingResultRender(
1296
1166
  storage_path=self.__storage,
1297
1167
  result=summary,
1298
1168
  persist=self.__persistent and self.__persistent_driver == 'sqlite'
1299
1169
  )
1300
1170
 
1301
- # Render the web report and print the link using the printer.
1171
+ # Print the link to the generated web report
1302
1172
  self.__printer.linkWebReport(render.render())
1303
1173
 
1304
1174
  def __handlePersistResults(
@@ -1308,71 +1178,51 @@ class UnitTest(IUnitTest):
1308
1178
  """
1309
1179
  Persist the test results summary using the configured persistence driver.
1310
1180
 
1311
- This method saves the provided test results summary to persistent storage, based on the
1312
- current configuration. Supported drivers include SQLite (using the TestLogs class) and
1313
- JSON file output. The storage location is determined by the configured base path.
1314
-
1315
1181
  Parameters
1316
1182
  ----------
1317
1183
  summary : dict
1318
- The summary of test results to persist. This should include all relevant test execution
1319
- details, such as test counts, statuses, execution times, and individual test results.
1320
-
1321
- Returns
1322
- -------
1323
- None
1324
- This method does not return any value. It performs persistence as a side effect.
1184
+ The summary dictionary containing test results and metadata to be persisted.
1325
1185
 
1326
1186
  Raises
1327
1187
  ------
1328
1188
  OSError
1329
- If there is an error creating directories or writing files to disk.
1189
+ If there is an error creating directories or writing files.
1330
1190
  OrionisTestPersistenceError
1331
1191
  If database operations fail or any other error occurs during persistence.
1332
1192
 
1333
1193
  Notes
1334
1194
  -----
1335
- - If `self.__persistent_driver` is set to 'sqlite', the summary is stored in an SQLite database
1336
- using the TestLogs class.
1337
- - If `self.__persistent_driver` is set to 'json', the summary is written to a timestamped JSON
1338
- file in the specified base path.
1339
- - The method ensures that the target directory exists before writing files.
1340
- - Any errors encountered during persistence are raised as exceptions for the caller to handle.
1195
+ This method persists the test results summary according to the configured persistence driver.
1196
+ If the driver is set to 'sqlite', the summary is stored in a SQLite database using the TestLogs class.
1197
+ If the driver is set to 'json', the summary is saved as a JSON file in the specified storage directory,
1198
+ with a filename based on the current timestamp. The method ensures that the target directory exists,
1199
+ and handles any errors that may occur during file or database operations.
1341
1200
  """
1342
-
1343
1201
  try:
1344
1202
 
1203
+ # If the persistence driver is SQLite, store the summary in the database
1345
1204
  if self.__persistent_driver == PersistentDrivers.SQLITE.value:
1346
-
1347
- # Persist results to SQLite database using TestLogs
1348
1205
  history = TestLogs(self.__storage)
1349
-
1350
- # Insert the summary into the database
1351
1206
  history.create(summary)
1352
1207
 
1208
+ # If the persistence driver is JSON, write the summary to a JSON file
1353
1209
  elif self.__persistent_driver == PersistentDrivers.JSON.value:
1354
-
1355
- # Generate a timestamp for the log file name
1356
1210
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
1357
-
1358
- # Construct the log file path with the timestamp
1359
1211
  log_path = Path(self.__storage) / f"{timestamp}_test_results.json"
1360
1212
 
1361
- # Ensure the directory exists
1213
+ # Ensure the parent directory exists
1362
1214
  log_path.parent.mkdir(parents=True, exist_ok=True)
1363
1215
 
1364
- # Write the summary dictionary to the JSON file
1216
+ # Write the summary to the JSON file
1365
1217
  with open(log_path, 'w', encoding='utf-8') as log:
1366
1218
  json.dump(summary, log, indent=4)
1367
-
1368
1219
  except OSError as e:
1369
1220
 
1370
- # Raise an OSError if there is an issue with file or directory operations
1221
+ # Raise an error if directory creation or file writing fails
1371
1222
  raise OSError(f"Error creating directories or writing files: {str(e)}")
1372
-
1373
1223
  except Exception as e:
1374
1224
 
1375
- # Raise a custom exception for any other issues during persistence
1225
+ # Raise a persistence error for any other exceptions
1376
1226
  raise OrionisTestPersistenceError(f"Error persisting test results: {str(e)}")
1377
1227
 
1378
1228
  def __filterTestsByName(
@@ -1381,44 +1231,57 @@ class UnitTest(IUnitTest):
1381
1231
  pattern: str
1382
1232
  ) -> unittest.TestSuite:
1383
1233
  """
1384
- Filters tests in a given test suite based on a specified name pattern.
1234
+ Filter tests in a test suite by a regular expression pattern applied to test names.
1235
+
1385
1236
  Parameters
1386
1237
  ----------
1387
1238
  suite : unittest.TestSuite
1388
- The test suite containing the tests to filter.
1239
+ The test suite containing the tests to be filtered.
1389
1240
  pattern : str
1390
- A regular expression pattern to match test names.
1241
+ Regular expression pattern to match against test names (test IDs).
1242
+
1391
1243
  Returns
1392
1244
  -------
1393
1245
  unittest.TestSuite
1394
- A new test suite containing only the tests that match the pattern.
1246
+ A new TestSuite containing only the tests whose names match the given pattern.
1247
+
1395
1248
  Raises
1396
1249
  ------
1397
1250
  OrionisTestValueError
1398
1251
  If the provided pattern is not a valid regular expression.
1252
+
1399
1253
  Notes
1400
1254
  -----
1255
+ This method compiles the provided regular expression and applies it to the IDs of all test cases
1256
+ in the flattened suite. Only tests whose IDs match the pattern are included in the returned suite.
1257
+ If the pattern is invalid, an OrionisTestValueError is raised with details about the regex error.
1401
1258
  """
1402
1259
 
1403
- # Initialize an empty TestSuite to hold the filtered tests
1260
+ # Create a new TestSuite to hold the filtered tests
1404
1261
  filtered_suite = unittest.TestSuite()
1405
1262
 
1406
- # Validate the pattern
1407
1263
  try:
1264
+
1265
+ # Compile the provided regular expression pattern
1408
1266
  regex = re.compile(pattern)
1267
+
1409
1268
  except re.error as e:
1269
+
1270
+ # Raise a value error if the regex is invalid
1410
1271
  raise OrionisTestValueError(
1411
1272
  f"The provided test name pattern is invalid: '{pattern}'. "
1412
1273
  f"Regular expression compilation error: {str(e)}. "
1413
1274
  "Please check the pattern syntax and try again."
1414
1275
  )
1415
1276
 
1416
- # Iterate through all tests in the suite and filter by the regex pattern
1277
+ # Iterate through all test cases in the flattened suite
1417
1278
  for test in self.__flattenTestSuite(suite):
1279
+
1280
+ # Add the test to the filtered suite if its ID matches the regex
1418
1281
  if regex.search(test.id()):
1419
1282
  filtered_suite.addTest(test)
1420
1283
 
1421
- # Return the filtered suite containing only tests that match the pattern
1284
+ # Return the suite containing only the filtered tests
1422
1285
  return filtered_suite
1423
1286
 
1424
1287
  def __filterTestsByTags(
@@ -1427,47 +1290,56 @@ class UnitTest(IUnitTest):
1427
1290
  tags: List[str]
1428
1291
  ) -> unittest.TestSuite:
1429
1292
  """
1430
- Filter tests in a unittest TestSuite by specified tags.
1431
-
1432
- Iterates through all tests in the provided TestSuite and checks for a `__tags__`
1433
- attribute either on the test method or the test case class. If any of the specified
1434
- tags match the tags associated with the test, the test is included in the filtered suite.
1293
+ Filters tests in a unittest TestSuite by matching specified tags.
1435
1294
 
1436
1295
  Parameters
1437
1296
  ----------
1438
1297
  suite : unittest.TestSuite
1439
- The original TestSuite containing all tests.
1298
+ The original TestSuite containing all test cases to be filtered.
1440
1299
  tags : list of str
1441
1300
  List of tags to filter the tests by.
1442
1301
 
1443
1302
  Returns
1444
1303
  -------
1445
1304
  unittest.TestSuite
1446
- A new TestSuite containing only the tests that match the specified tags.
1305
+ A new TestSuite containing only the tests that have at least one matching tag.
1306
+
1307
+ Notes
1308
+ -----
1309
+ This method inspects each test case in the provided suite and checks for the presence of tags
1310
+ either on the test method (via a `__tags__` attribute) or on the test class instance itself.
1311
+ If any of the specified tags are found in the test's tags, the test is included in the returned suite.
1447
1312
  """
1448
1313
 
1449
- # Initialize an empty TestSuite to hold the filtered tests
1314
+ # Create a new TestSuite to hold the filtered tests
1450
1315
  filtered_suite = unittest.TestSuite()
1316
+
1317
+ # Convert the list of tags to a set for efficient intersection checks
1451
1318
  tag_set = set(tags)
1452
1319
 
1320
+ # Iterate through all test cases in the flattened suite
1453
1321
  for test in self.__flattenTestSuite(suite):
1454
1322
 
1455
- # Get test method if this is a TestCase instance
1323
+ # Attempt to retrieve the test method from the test case
1456
1324
  test_method = getattr(test, test._testMethodName, None)
1457
1325
 
1458
- # Check for tags attribute on the test method
1326
+ # Check if the test method has a __tags__ attribute
1459
1327
  if hasattr(test_method, '__tags__'):
1460
1328
  method_tags = set(getattr(test_method, '__tags__'))
1329
+
1330
+ # If there is any intersection between the method's tags and the filter tags, add the test
1461
1331
  if tag_set.intersection(method_tags):
1462
1332
  filtered_suite.addTest(test)
1463
1333
 
1464
- # Also check on the test case class
1334
+ # If the method does not have tags, check if the test case itself has a __tags__ attribute
1465
1335
  elif hasattr(test, '__tags__'):
1466
1336
  class_tags = set(getattr(test, '__tags__'))
1337
+
1338
+ # If there is any intersection between the class's tags and the filter tags, add the test
1467
1339
  if tag_set.intersection(class_tags):
1468
1340
  filtered_suite.addTest(test)
1469
1341
 
1470
- # Return the filtered suite containing only tests with matching tags
1342
+ # Return the suite containing only the filtered tests
1471
1343
  return filtered_suite
1472
1344
 
1473
1345
  def getTestNames(
@@ -1478,8 +1350,8 @@ class UnitTest(IUnitTest):
1478
1350
 
1479
1351
  Returns
1480
1352
  -------
1481
- List[str]
1482
- List of test names (unique identifiers) from the test suite.
1353
+ list of str
1354
+ List of test names from the test suite.
1483
1355
  """
1484
1356
  return [test.id() for test in self.__flattenTestSuite(self.__suite)]
1485
1357
 
@@ -1487,12 +1359,12 @@ class UnitTest(IUnitTest):
1487
1359
  self
1488
1360
  ) -> int:
1489
1361
  """
1490
- Returns the total number of test cases in the test suite.
1362
+ Get the total number of test cases in the test suite.
1491
1363
 
1492
1364
  Returns
1493
1365
  -------
1494
1366
  int
1495
- The total number of individual test cases in the suite.
1367
+ Total number of individual test cases in the suite.
1496
1368
  """
1497
1369
  return len(list(self.__flattenTestSuite(self.__suite)))
1498
1370
 
@@ -1502,7 +1374,9 @@ class UnitTest(IUnitTest):
1502
1374
  """
1503
1375
  Clear all tests from the current test suite.
1504
1376
 
1505
- Resets the internal test suite to an empty `unittest.TestSuite`, removing any previously added tests.
1377
+ Returns
1378
+ -------
1379
+ None
1506
1380
  """
1507
1381
  self.__suite = unittest.TestSuite()
1508
1382
 
@@ -1510,12 +1384,12 @@ class UnitTest(IUnitTest):
1510
1384
  self
1511
1385
  ) -> dict:
1512
1386
  """
1513
- Returns the results of the executed test suite.
1387
+ Get the results of the executed test suite.
1514
1388
 
1515
1389
  Returns
1516
1390
  -------
1517
- UnitTest
1518
- The result of the executed test suite.
1391
+ dict
1392
+ Result of the executed test suite.
1519
1393
  """
1520
1394
  return self.__result
1521
1395
 
@@ -1523,12 +1397,12 @@ class UnitTest(IUnitTest):
1523
1397
  self
1524
1398
  ) -> int:
1525
1399
  """
1526
- Returns the output buffer used for capturing test results.
1527
- This method returns the internal output buffer that collects the results of the test execution.
1400
+ Get the output buffer used for capturing test results.
1401
+
1528
1402
  Returns
1529
1403
  -------
1530
1404
  int
1531
- The output buffer containing the results of the test execution.
1405
+ Output buffer containing the results of the test execution.
1532
1406
  """
1533
1407
  return self.__output_buffer
1534
1408
 
@@ -1536,8 +1410,11 @@ class UnitTest(IUnitTest):
1536
1410
  self
1537
1411
  ) -> None:
1538
1412
  """
1539
- Prints the contents of the output buffer to the console.
1540
- This method retrieves the output buffer and prints its contents using the rich console.
1413
+ Print the contents of the output buffer to the console.
1414
+
1415
+ Returns
1416
+ -------
1417
+ None
1541
1418
  """
1542
1419
  self.__printer.print(self.__output_buffer)
1543
1420
 
@@ -1545,12 +1422,12 @@ class UnitTest(IUnitTest):
1545
1422
  self
1546
1423
  ) -> int:
1547
1424
  """
1548
- Returns the error buffer used for capturing test errors.
1549
- This method returns the internal error buffer that collects any errors encountered during test execution.
1425
+ Get the error buffer used for capturing test errors.
1426
+
1550
1427
  Returns
1551
1428
  -------
1552
1429
  int
1553
- The error buffer containing the errors encountered during the test execution.
1430
+ Error buffer containing errors encountered during test execution.
1554
1431
  """
1555
1432
  return self.__error_buffer
1556
1433
 
@@ -1558,7 +1435,10 @@ class UnitTest(IUnitTest):
1558
1435
  self
1559
1436
  ) -> None:
1560
1437
  """
1561
- Prints the contents of the error buffer to the console.
1562
- This method retrieves the error buffer and prints its contents using the rich console.
1438
+ Print the contents of the error buffer to the console.
1439
+
1440
+ Returns
1441
+ -------
1442
+ None
1563
1443
  """
1564
1444
  self.__printer.print(self.__error_buffer)