orionis 0.404.0__py3-none-any.whl → 0.406.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 (165) hide show
  1. orionis/console/base/command.py +57 -50
  2. orionis/console/base/contracts/command.py +68 -0
  3. orionis/console/dynamic/contracts/progress_bar.py +3 -3
  4. orionis/console/dynamic/progress_bar.py +8 -8
  5. orionis/console/output/console.py +8 -2
  6. orionis/console/output/contracts/console.py +1 -1
  7. orionis/container/container.py +2 -2
  8. orionis/container/context/scope.py +4 -1
  9. orionis/container/contracts/service_provider.py +2 -2
  10. orionis/container/entities/binding.py +31 -44
  11. orionis/container/enums/lifetimes.py +22 -1
  12. orionis/container/facades/facade.py +1 -2
  13. orionis/container/providers/service_provider.py +2 -2
  14. orionis/foundation/application.py +542 -248
  15. orionis/foundation/config/app/entities/app.py +107 -90
  16. orionis/foundation/config/auth/entities/auth.py +4 -33
  17. orionis/foundation/config/cache/entities/cache.py +18 -41
  18. orionis/foundation/config/cache/entities/file.py +8 -35
  19. orionis/foundation/config/cache/entities/stores.py +17 -38
  20. orionis/foundation/config/cors/entities/cors.py +41 -54
  21. orionis/foundation/config/database/entities/connections.py +40 -56
  22. orionis/foundation/config/database/entities/database.py +11 -38
  23. orionis/foundation/config/database/entities/mysql.py +48 -76
  24. orionis/foundation/config/database/entities/oracle.py +30 -57
  25. orionis/foundation/config/database/entities/pgsql.py +45 -61
  26. orionis/foundation/config/database/entities/sqlite.py +26 -53
  27. orionis/foundation/config/filesystems/entitites/aws.py +28 -49
  28. orionis/foundation/config/filesystems/entitites/disks.py +27 -47
  29. orionis/foundation/config/filesystems/entitites/filesystems.py +15 -37
  30. orionis/foundation/config/filesystems/entitites/local.py +9 -35
  31. orionis/foundation/config/filesystems/entitites/public.py +14 -41
  32. orionis/foundation/config/logging/entities/channels.py +56 -86
  33. orionis/foundation/config/logging/entities/chunked.py +18 -10
  34. orionis/foundation/config/logging/entities/daily.py +17 -9
  35. orionis/foundation/config/logging/entities/hourly.py +15 -7
  36. orionis/foundation/config/logging/entities/logging.py +12 -18
  37. orionis/foundation/config/logging/entities/monthly.py +16 -8
  38. orionis/foundation/config/logging/entities/stack.py +15 -7
  39. orionis/foundation/config/logging/entities/weekly.py +15 -7
  40. orionis/foundation/config/logging/validators/path.py +6 -0
  41. orionis/foundation/config/mail/entities/file.py +9 -36
  42. orionis/foundation/config/mail/entities/mail.py +22 -40
  43. orionis/foundation/config/mail/entities/mailers.py +29 -44
  44. orionis/foundation/config/mail/entities/smtp.py +47 -48
  45. orionis/foundation/config/queue/entities/brokers.py +19 -41
  46. orionis/foundation/config/queue/entities/database.py +24 -46
  47. orionis/foundation/config/queue/entities/queue.py +28 -40
  48. orionis/foundation/config/roots/paths.py +272 -468
  49. orionis/foundation/config/session/entities/session.py +23 -53
  50. orionis/foundation/config/startup.py +165 -135
  51. orionis/foundation/config/testing/entities/testing.py +137 -122
  52. orionis/foundation/config/testing/enums/__init__.py +6 -2
  53. orionis/foundation/config/testing/enums/drivers.py +16 -0
  54. orionis/foundation/config/testing/enums/verbosity.py +18 -0
  55. orionis/foundation/contracts/application.py +152 -362
  56. orionis/foundation/providers/console_provider.py +24 -2
  57. orionis/foundation/providers/dumper_provider.py +24 -2
  58. orionis/foundation/providers/logger_provider.py +24 -2
  59. orionis/foundation/providers/path_resolver_provider.py +25 -2
  60. orionis/foundation/providers/progress_bar_provider.py +24 -2
  61. orionis/foundation/providers/testing_provider.py +39 -0
  62. orionis/foundation/providers/workers_provider.py +24 -2
  63. orionis/metadata/framework.py +1 -1
  64. orionis/services/environment/helpers/functions.py +1 -2
  65. orionis/services/environment/key/__init__.py +0 -0
  66. orionis/services/environment/key/key_generator.py +37 -0
  67. orionis/services/log/handlers/filename.py +64 -0
  68. orionis/services/log/handlers/size_rotating.py +9 -40
  69. orionis/services/log/handlers/timed_rotating.py +9 -41
  70. orionis/services/log/log_service.py +9 -52
  71. orionis/support/entities/__init__.py +0 -0
  72. orionis/support/entities/base.py +104 -0
  73. orionis/support/facades/testing.py +15 -0
  74. orionis/support/facades/workers.py +1 -1
  75. orionis/test/cases/asynchronous.py +0 -11
  76. orionis/test/cases/synchronous.py +0 -9
  77. orionis/test/contracts/dumper.py +11 -4
  78. orionis/test/contracts/kernel.py +5 -110
  79. orionis/test/contracts/logs.py +27 -65
  80. orionis/test/contracts/printer.py +16 -128
  81. orionis/test/contracts/test_result.py +100 -0
  82. orionis/test/contracts/unit_test.py +87 -150
  83. orionis/test/core/unit_test.py +608 -554
  84. orionis/test/entities/result.py +22 -2
  85. orionis/test/enums/__init__.py +0 -2
  86. orionis/test/enums/status.py +14 -9
  87. orionis/test/exceptions/config.py +9 -1
  88. orionis/test/exceptions/failure.py +34 -11
  89. orionis/test/exceptions/persistence.py +10 -2
  90. orionis/test/exceptions/runtime.py +9 -1
  91. orionis/test/exceptions/value.py +13 -1
  92. orionis/test/kernel.py +87 -289
  93. orionis/test/output/dumper.py +82 -18
  94. orionis/test/output/printer.py +399 -156
  95. orionis/test/records/logs.py +203 -82
  96. orionis/test/validators/__init__.py +33 -0
  97. orionis/test/validators/base_path.py +45 -0
  98. orionis/test/validators/execution_mode.py +45 -0
  99. orionis/test/validators/fail_fast.py +37 -0
  100. orionis/test/validators/folder_path.py +34 -0
  101. orionis/test/validators/module_name.py +31 -0
  102. orionis/test/validators/name_pattern.py +40 -0
  103. orionis/test/validators/pattern.py +36 -0
  104. orionis/test/validators/persistent.py +42 -0
  105. orionis/test/validators/persistent_driver.py +43 -0
  106. orionis/test/validators/print_result.py +37 -0
  107. orionis/test/validators/tags.py +37 -0
  108. orionis/test/validators/throw_exception.py +39 -0
  109. orionis/test/validators/verbosity.py +37 -0
  110. orionis/test/validators/web_report.py +35 -0
  111. orionis/test/validators/workers.py +31 -0
  112. orionis/test/view/render.py +48 -54
  113. {orionis-0.404.0.dist-info → orionis-0.406.0.dist-info}/METADATA +1 -1
  114. {orionis-0.404.0.dist-info → orionis-0.406.0.dist-info}/RECORD +160 -108
  115. tests/container/__init__.py +0 -0
  116. tests/container/context/__init__.py +0 -0
  117. tests/container/context/test_manager.py +27 -0
  118. tests/container/context/test_scope.py +23 -0
  119. tests/container/entities/__init__.py +0 -0
  120. tests/container/entities/test_binding.py +133 -0
  121. tests/container/enums/__init__.py +0 -0
  122. tests/container/enums/test_lifetimes.py +63 -0
  123. tests/container/facades/__init__.py +0 -0
  124. tests/container/facades/test_facade.py +61 -0
  125. tests/container/mocks/__init__.py +0 -0
  126. tests/container/mocks/mock_complex_classes.py +482 -0
  127. tests/container/mocks/mock_simple_classes.py +32 -0
  128. tests/container/providers/__init__.py +0 -0
  129. tests/container/providers/test_providers.py +48 -0
  130. tests/container/resolver/__init__.py +0 -0
  131. tests/container/resolver/test_resolver.py +55 -0
  132. tests/container/test_container.py +254 -0
  133. tests/container/test_singleton.py +98 -0
  134. tests/container/test_thread_safety.py +217 -0
  135. tests/container/validators/__init__.py +0 -0
  136. tests/container/validators/test_implements.py +140 -0
  137. tests/container/validators/test_is_abstract_class.py +99 -0
  138. tests/container/validators/test_is_callable.py +73 -0
  139. tests/container/validators/test_is_concrete_class.py +97 -0
  140. tests/container/validators/test_is_instance.py +105 -0
  141. tests/container/validators/test_is_not_subclass.py +117 -0
  142. tests/container/validators/test_is_subclass.py +115 -0
  143. tests/container/validators/test_is_valid_alias.py +113 -0
  144. tests/container/validators/test_lifetime.py +75 -0
  145. tests/foundation/config/logging/test_foundation_config_logging_chunked.py +12 -34
  146. tests/foundation/config/logging/test_foundation_config_logging_daily.py +11 -11
  147. tests/foundation/config/logging/test_foundation_config_logging_hourly.py +7 -8
  148. tests/foundation/config/logging/test_foundation_config_logging_monthly.py +7 -10
  149. tests/foundation/config/logging/test_foundation_config_logging_stack.py +6 -11
  150. tests/foundation/config/logging/test_foundation_config_logging_weekly.py +6 -5
  151. tests/foundation/config/testing/test_foundation_config_testing.py +1 -1
  152. tests/metadata/test_metadata_framework.py +18 -18
  153. tests/testing/test_testing_result.py +117 -117
  154. tests/testing/test_testing_unit.py +209 -209
  155. orionis/foundation/config/base.py +0 -112
  156. orionis/test/arguments/parser.py +0 -187
  157. orionis/test/contracts/parser.py +0 -43
  158. orionis/test/entities/arguments.py +0 -38
  159. orionis/test/enums/execution_mode.py +0 -16
  160. /orionis/{test/arguments → console/base/contracts}/__init__.py +0 -0
  161. /orionis/foundation/config/testing/enums/{test_mode.py → mode.py} +0 -0
  162. {orionis-0.404.0.dist-info → orionis-0.406.0.dist-info}/WHEEL +0 -0
  163. {orionis-0.404.0.dist-info → orionis-0.406.0.dist-info}/licenses/LICENCE +0 -0
  164. {orionis-0.404.0.dist-info → orionis-0.406.0.dist-info}/top_level.txt +0 -0
  165. {orionis-0.404.0.dist-info → orionis-0.406.0.dist-info}/zip-safe +0 -0
orionis/test/kernel.py CHANGED
@@ -1,347 +1,145 @@
1
- import gc
2
- import os
1
+ from pathlib import Path
3
2
  import re
3
+ from typing import List
4
4
  from os import walk
5
- import sys
6
- from orionis.foundation.config.testing.entities.testing import Testing as Configuration
5
+ from orionis.foundation.config.testing.entities.testing import Testing
7
6
  from orionis.foundation.contracts.application import IApplication
8
7
  from orionis.test.contracts.kernel import ITestKernel
9
- from orionis.test.arguments.parser import TestArgumentParser
10
- from orionis.test.core.unit_test import UnitTest
11
- from orionis.test.entities.arguments import TestArguments
12
- from orionis.test.enums.execution_mode import ExecutionMode
8
+ from orionis.test.contracts.unit_test import IUnitTest
13
9
  from orionis.test.exceptions import OrionisTestConfigException
14
10
 
15
11
  class TestKernel(ITestKernel):
16
- """
17
- Core test kernel for the Orionis testing framework.
18
-
19
- This class provides the main interface for discovering, configuring, and executing
20
- test suites within the Orionis framework. It handles test configuration validation,
21
- test discovery across multiple directories, and orchestrates the execution of
22
- discovered tests.
23
-
24
- Parameters
25
- ----------
26
- app : IApplication
27
- The Orionis application instance that provides the testing context.
28
-
29
- Attributes
30
- ----------
31
- __app : IApplication
32
- Private reference to the application instance.
33
- __config : Configuration
34
- Private reference to the testing configuration.
35
- """
36
12
 
37
13
  def __init__(
38
14
  self,
39
15
  app: IApplication
40
16
  ) -> None:
41
17
  """
42
- Initialize the Orionis test kernel.
18
+ Initialize the TestKernel with the provided application instance.
43
19
 
44
20
  Parameters
45
21
  ----------
46
22
  app : IApplication
47
- The application instance that implements the IApplication interface.
48
- This provides the context and services needed for test execution.
23
+ The application instance implementing the IApplication contract.
49
24
 
50
25
  Raises
51
26
  ------
52
- ValueError
53
- If the provided app is None or not an instance of IApplication.
27
+ OrionisTestConfigException
28
+ If the provided app is not an instance of IApplication.
54
29
  """
55
- # Validate application instance
56
- if app is None or not isinstance(app, IApplication):
57
- raise ValueError("The provided application is not a valid instance of IApplication.")
58
30
 
59
- # Set the application instance
60
- self.__app = app
31
+ # Validate that the app is an instance of IApplication
32
+ if not isinstance(app, IApplication):
33
+ raise OrionisTestConfigException(
34
+ f"Failed to initialize TestKernel: expected IApplication, got {type(app).__module__}.{type(app).__name__}."
35
+ )
36
+
37
+ # Load testing configuration from the application
38
+ self.__config = Testing(**app.config('testing'))
61
39
 
62
- def __checkConfiguration(
40
+ # Create and configure the unit test instance
41
+ self.__unit_test: IUnitTest = app.make('core.orionis.testing')
42
+ self.__unit_test._UnitTest__app = app
43
+ self.__unit_test._UnitTest__storage = app.path('storage_testing')
44
+
45
+ def __listMatchingFolders(
63
46
  self,
64
- config: Configuration = None,
65
- **kwargs
66
- ) -> Configuration:
47
+ base_path: Path,
48
+ custom_path: Path,
49
+ pattern: str
50
+ ) -> List[str]:
67
51
  """
68
- Validate and initialize the testing configuration.
69
-
70
- This method validates the provided configuration or creates a new one from
71
- keyword arguments. It ensures that the configuration is properly set up
72
- before test execution begins.
52
+ List folders within a custom path whose files match a given pattern.
73
53
 
74
54
  Parameters
75
55
  ----------
76
- config : Configuration, optional
77
- A pre-configured Testing configuration instance. If None, attempts to
78
- create one from kwargs.
79
- **kwargs : dict
80
- Keyword arguments to create a Configuration instance if config is None.
81
- Must match the Configuration class constructor parameters.
56
+ base_path : Path
57
+ The base directory path for relative calculation.
58
+ custom_path : Path
59
+ The custom directory path to search for matching files.
60
+ pattern : str
61
+ The filename pattern to match (supports '*' and '?').
82
62
 
83
63
  Returns
84
64
  -------
85
- bool
86
- True if configuration validation succeeds.
87
-
88
- Raises
89
- ------
90
- OrionisTestConfigException
91
- If the configuration is invalid or required fields are missing.
92
- The exception message includes details about required fields and their types.
65
+ List[str]
66
+ List of relative folder paths containing files matching the pattern.
93
67
  """
94
- # Check if config is None and kwargs are provided
95
- if config is None:
96
68
 
97
- # Try to create a Configuration instance with provided kwargs or default values
98
- try:
99
- # If no kwargs are provided, create a default Configuration instance
100
- if not kwargs:
101
- config = Configuration(**self.__app.config('testing'))
69
+ # Compile the pattern into a regex for matching file names
70
+ regex = re.compile('^' + pattern.replace('*', '.*').replace('?', '.') + '$')
71
+ matched_folders = set()
102
72
 
103
- # If kwargs are provided, create a Configuration instance with them
104
- else:
105
- config = Configuration(**kwargs)
73
+ # Walk through the directory tree starting at custom_path
74
+ for root, _, files in walk(str(custom_path)):
106
75
 
107
- except TypeError:
76
+ # Check if any file in the current folder matches the pattern
77
+ if any(regex.fullmatch(file) for file in files):
108
78
 
109
- # If a TypeError occurs, it indicates that the provided arguments do not match the Configuration class
110
- required_fields = []
111
- for field in Configuration().getFields():
112
- required_fields.append(f"{field.get('name')} = (Type: {field.get('type')}, Default: {field.get('default')})")
79
+ # Calculate the relative path from base_path and add to results
80
+ rel_path = Path(root).relative_to(base_path).as_posix()
81
+ matched_folders.add(rel_path)
113
82
 
114
- # Raise an exception with a detailed message about the required fields
115
- raise OrionisTestConfigException(f"The provided configuration is not valid. Please ensure it is an instance of the Configuration class or provide valid keyword arguments. \n{str('\n').join(required_fields)}]")
83
+ # Return the list of matching folder paths
84
+ return list(matched_folders)
116
85
 
117
- # Assign the configuration to the instance variable
118
- return config or Configuration()
119
-
120
- def handle(
121
- self,
122
- config: Configuration = None,
123
- **kwargs
124
- ) -> UnitTest:
86
+ def handle(self) -> IUnitTest:
125
87
  """
126
- Execute the complete test discovery and execution pipeline.
127
-
128
- This is the main entry point for running tests. It validates the configuration,
129
- discovers test files based on specified patterns and paths, configures the
130
- test suite, and executes all discovered tests.
131
-
132
- Parameters
133
- ----------
134
- config : Configuration, optional
135
- A pre-configured Testing configuration instance. If None, attempts to
136
- create one from kwargs.
137
- **kwargs : dict
138
- Keyword arguments to create a Configuration instance if config is None.
139
- Common parameters include:
140
- - base_path : str, base directory for test discovery
141
- - folder_path : str or list, specific folders to search
142
- - pattern : str, file pattern for test discovery
143
- - verbosity : int, output verbosity level
144
- - execution_mode : str, test execution mode
145
- - max_workers : int, maximum number of worker threads
146
- - fail_fast : bool, stop on first failure
88
+ Configure and execute the unit tests based on the current configuration.
147
89
 
148
90
  Returns
149
91
  -------
150
- UnitTest
151
- The configured and executed test suite instance containing all results.
152
-
153
- Raises
154
- ------
155
- OrionisTestConfigException
156
- If the configuration validation fails.
92
+ IUnitTest
93
+ The configured and executed unit test instance.
157
94
  """
158
- # Validate and set configuration
159
- config = self.__checkConfiguration(config, **kwargs)
160
-
161
- # Initialize the test suite
162
- tests = UnitTest()
163
-
164
- # Assign the application instance to the test suite
165
- tests.setApplication(self.__app)
166
95
 
167
- # Configure the test suite with validated configuration values
168
- tests.configure(
169
- verbosity=config.verbosity,
170
- execution_mode=config.execution_mode,
171
- max_workers=config.max_workers,
172
- fail_fast=config.fail_fast,
173
- print_result=config.print_result,
174
- throw_exception=config.throw_exception,
175
- persistent=config.persistent,
176
- persistent_driver=config.persistent_driver,
177
- web_report=config.web_report
96
+ # Configure the unit test with parameters from the configuration
97
+ self.__unit_test.configure(
98
+ verbosity=self.__config.verbosity,
99
+ execution_mode=self.__config.execution_mode,
100
+ max_workers=self.__config.max_workers,
101
+ fail_fast=self.__config.fail_fast,
102
+ print_result=self.__config.print_result,
103
+ throw_exception=self.__config.throw_exception,
104
+ persistent=self.__config.persistent,
105
+ persistent_driver=self.__config.persistent_driver,
106
+ web_report=self.__config.web_report
178
107
  )
179
108
 
180
- # Extract configuration values for test discovery
181
- base_path = config.base_path
182
- folder_path = config.folder_path
183
- pattern = config.pattern
109
+ # Prepare paths and pattern for test discovery
110
+ base_path = (Path.cwd() / self.__config.base_path).resolve()
111
+ folder_path = self.__config.folder_path
112
+ pattern = self.__config.pattern
184
113
 
185
- def list_matching_folders(custom_path: str, pattern: str):
186
- """
187
- Discover folders containing files that match the specified pattern.
114
+ # Set to hold discovered folders
115
+ discovered_folders = set()
188
116
 
189
- This helper function walks through the directory tree starting from
190
- custom_path and identifies folders that contain files matching the
191
- given pattern.
117
+ # Discover folders containing test files according to the configuration
192
118
 
193
- Parameters
194
- ----------
195
- custom_path : str
196
- The root path to start the search from.
197
- pattern : str
198
- The file pattern to match (supports wildcards * and ?).
199
-
200
- Returns
201
- -------
202
- list of str
203
- List of relative folder paths containing matching files.
204
- """
205
- matched_folders = []
206
- for root, _, files in walk(custom_path):
207
- for file in files:
208
- if re.fullmatch(pattern.replace('*', '.*').replace('?', '.'), file):
209
- relative_path = root.replace(base_path, '').replace('\\', '/').lstrip('/')
210
- if relative_path not in matched_folders:
211
- matched_folders.append(relative_path)
212
- return matched_folders
213
-
214
- # Discover test folders based on configuration
215
- discovered_folders = []
119
+ # Search all folders under base_path
216
120
  if folder_path == '*':
217
- # Search all folders under base_path
218
- discovered_folders.extend(list_matching_folders(base_path, pattern))
121
+ discovered_folders.update(self.__listMatchingFolders(base_path, base_path, pattern))
122
+
123
+ # Search each custom folder in the list
219
124
  elif isinstance(folder_path, list):
220
- # Search specific folders provided in the list
221
- for custom_path in folder_path:
222
- discovered_folders.extend(list_matching_folders(f"{base_path}/{custom_path}", pattern))
125
+ for custom in folder_path:
126
+ custom_path = (base_path / custom).resolve()
127
+ discovered_folders.update(self.__listMatchingFolders(base_path, custom_path, pattern))
128
+
129
+ # Search a single custom folder
223
130
  else:
224
- # Search single specified folder
225
- discovered_folders.extend(list_matching_folders(folder_path, pattern))
131
+ custom_path = (base_path / folder_path).resolve()
132
+ discovered_folders.update(self.__listMatchingFolders(base_path, custom_path, pattern))
226
133
 
227
- # Add discovered folders to the test suite for execution
134
+ # Register discovered folders with the unit test for test discovery
228
135
  for folder in discovered_folders:
229
- tests.discoverTestsInFolder(
136
+ self.__unit_test.discoverTestsInFolder(
230
137
  folder_path=folder,
231
- base_path=base_path,
138
+ base_path=self.__config.base_path,
232
139
  pattern=pattern,
233
- test_name_pattern=config.test_name_pattern if config.test_name_pattern else None,
234
- tags=config.tags if config.tags else None
140
+ test_name_pattern=self.__config.test_name_pattern or None,
141
+ tags=self.__config.tags or None
235
142
  )
236
143
 
237
- # Execute the test suite and return the results
238
- tests.run()
239
-
240
- # Return the test suite instance containing all results
241
- return tests
242
-
243
- def handleCLI(
244
- self,
245
- sys_argv: list[str],
246
- ) -> UnitTest:
247
-
248
- """
249
- Process command line arguments for test execution.
250
- This method configures and runs tests based on command line arguments. It extracts
251
- configuration from the provided TestArguments object, executes the tests, and
252
- handles output generation.
253
- Parameters
254
- ----------
255
- args : TestArguments
256
- Command line arguments parsed into a TestArguments object.
257
- base_path : str, optional
258
- Base directory to search for test files, by default 'tests'.
259
- folder_path : str, optional
260
- Pattern for folder selection within base_path, by default '*'.
261
- pattern : str, optional
262
- Filename pattern for test files, by default 'test_*.py'.
263
- Returns
264
- -------
265
- UnitTest
266
- The test suite instance containing all test results.
267
- Notes
268
- -----
269
- The method supports various test execution options including parallel/sequential
270
- execution mode, fail fast behavior, and result output configuration.
271
- """
272
-
273
- # Validate the provided arguments
274
- if not isinstance(sys_argv, list):
275
- raise OrionisTestConfigException("The provided sys_argv must be a list of command line arguments.")
276
-
277
- # Assign the provided arguments to a TestArguments instance
278
- parser = TestArgumentParser()
279
- args:TestArguments = parser.parse(sys_argv)
280
-
281
- # Extract and validate the configuration from command line arguments
282
- test = self.handle(
283
- verbosity = int(args.verbosity),
284
- execution_mode = ExecutionMode.PARALLEL if args.mode == 'parallel' else ExecutionMode.SEQUENTIAL,
285
- fail_fast = bool(args.fail_fast),
286
- print_result = bool(args.print_result),
287
- throw_exception = bool(args.throw_exception),
288
- persistent = bool(args.persistent),
289
- persistent_driver = str(args.persistent_driver) if args.persistent_driver else None,
290
- web_report = bool(args.web_report)
291
- )
292
-
293
- # If requested, print the output buffer
294
- if args.print_output_buffer:
295
- test.printOutputBuffer()
296
-
297
- # Return the test suite instance containing all results
298
- return test
299
-
300
- def exit(
301
- self,
302
- code: int = 0
303
- ) -> None:
304
- """
305
- Terminate the test execution process and free associated resources.
306
-
307
- This method performs a clean shutdown of the test kernel by explicitly
308
- triggering garbage collection to release memory resources and then
309
- terminating the process with the provided exit code. It ensures that any
310
- remaining file handles, threads, or other resources are properly released.
311
-
312
- Parameters
313
- ----------
314
- code : int
315
- The exit code to return to the operating system. Should be 0 for
316
- successful execution or a non-zero value to indicate an error.
317
-
318
- Returns
319
- -------
320
- None
321
- This method does not return as it terminates the process.
322
-
323
- Raises
324
- ------
325
- ValueError
326
- If the provided code is not a valid integer or outside the allowed range.
327
-
328
- Notes
329
- -----
330
- Using os._exit() bypasses normal Python cleanup mechanisms and
331
- immediately terminates the process. This can be necessary when
332
- normal sys.exit() would be caught by exception handlers.
333
- """
334
- # Validate the exit code
335
- if not isinstance(code, int):
336
- raise ValueError("Exit code must be an integer")
337
-
338
- # Check if the code is within the allowed range (typically 0-255)
339
- if code < 0 or code > 255:
340
- raise ValueError("Exit code must be between 0 and 255")
341
-
342
- # Force garbage collection to free memory
343
- gc.collect()
344
-
345
- # Terminate the process immediately without running cleanup handlers
346
- sys.exit(code)
347
- os._exit(code)
144
+ # Run the unit tests and return the result
145
+ return self.__unit_test.run()
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  import sys
3
- from orionis.test.exceptions.runtime import OrionisTestRuntimeError
3
+ from orionis.console.dumper.dump import Debug
4
+ from orionis.test.exceptions import OrionisTestRuntimeError
4
5
  from orionis.test.contracts.dumper import ITestDumper
5
6
 
6
7
  class TestDumper(ITestDumper):
@@ -29,102 +30,165 @@ class TestDumper(ITestDumper):
29
30
 
30
31
  def __isTestCaseClass(self, value) -> bool:
31
32
  """
32
- Check if the given value is an instance of a test case class.
33
+ Determines whether the provided value is an instance of a recognized test case class.
34
+
35
+ This method checks if the given object is an instance of either AsyncTestCase or SyncTestCase,
36
+ which are the supported test case base classes in the Orionis testing framework.
33
37
 
34
38
  Parameters
35
39
  ----------
36
40
  value : object
37
- The object to check.
41
+ The object to check for test case class membership.
38
42
 
39
43
  Returns
40
44
  -------
41
45
  bool
42
- True if `value` is an instance of AsyncTestCase, TestCase, or SyncTestCase;
43
- False otherwise.
46
+ Returns True if `value` is an instance of AsyncTestCase or SyncTestCase.
47
+ Returns False if `value` is None, not an instance of these classes, or if any import error occurs.
44
48
  """
49
+
50
+ # If the value is None, it cannot be a test case instance.
51
+ if value is None:
52
+ return False
53
+
45
54
  try:
46
- if value is None:
47
- return False
55
+
56
+ # Attempt to import the test case base classes.
48
57
  from orionis.test.cases.asynchronous import AsyncTestCase
49
58
  from orionis.test.cases.synchronous import SyncTestCase
50
- return isinstance(value, (AsyncTestCase, SyncTestCase))
59
+ import unittest
60
+
61
+ # Check if the value is an instance of either Orionis or native unittest test case class.
62
+ return isinstance(
63
+ value,
64
+ (
65
+ AsyncTestCase,
66
+ SyncTestCase,
67
+ unittest.TestCase,
68
+ ),
69
+ )
70
+
51
71
  except Exception:
72
+
73
+ # If imports fail or any other exception occurs, return False.
52
74
  return False
53
75
 
54
76
  def dd(self, *args) -> None:
55
77
  """
56
- Dumps debugging information using the Debug class.
78
+ Outputs debugging information using the Debug class and halts further execution.
57
79
 
58
- This method captures the caller's file and line number,
59
- and uses the Debug class to output debugging information.
80
+ This method captures the caller's file and line number to provide context for the debug output.
81
+ It temporarily redirects standard output and error streams to ensure the debug information is
82
+ displayed correctly. If the first argument is a recognized test case instance, it is skipped
83
+ in the output to avoid redundant information. The method raises an exception if any error
84
+ occurs during the dumping process.
60
85
 
61
86
  Parameters
62
87
  ----------
63
88
  *args : tuple
64
- Variable length argument list to be dumped.
89
+ Variable length argument list containing the objects to be dumped.
90
+
91
+ Returns
92
+ -------
93
+ None
94
+ This method does not return any value. It outputs debug information and may halt execution.
65
95
  """
96
+
97
+ # If no arguments are provided, exit the method early.
66
98
  if not args:
67
99
  return
68
100
 
101
+ # Save the original stdout and stderr to restore them later
69
102
  original_stdout = sys.stdout
70
103
  original_stderr = sys.stderr
71
104
 
72
105
  try:
73
- from orionis._console.dumper.dump_die import Debug
74
106
 
107
+ # Redirect stdout and stderr to the system defaults for proper debug output
75
108
  sys.stdout = sys.__stdout__
76
109
  sys.stderr = sys.__stderr__
77
110
 
111
+ # Retrieve the caller's frame to get file and line number context
78
112
  caller_frame = sys._getframe(1)
79
113
  _file = os.path.abspath(caller_frame.f_code.co_filename)
80
114
  _line = caller_frame.f_lineno
81
115
 
116
+ # Initialize the Debug dumper with context information
82
117
  dumper = Debug(f"{_file}:{_line}")
118
+
119
+ # If the first argument is a test case instance, skip it in the output
83
120
  if self.__isTestCaseClass(args[0]):
84
121
  dumper.dd(*args[1:])
85
122
  else:
86
123
  dumper.dd(*args)
124
+
87
125
  except Exception as e:
126
+
127
+ # Raise a custom runtime error if dumping fails
88
128
  raise OrionisTestRuntimeError(f"An error occurred while dumping debug information: {e}")
129
+
89
130
  finally:
131
+
132
+ # Restore the original stdout and stderr
90
133
  sys.stdout = original_stdout
91
134
  sys.stderr = original_stderr
92
135
 
93
136
  def dump(self, *args) -> None:
94
137
  """
95
- Dumps debugging information using the Debug class.
138
+ Outputs debugging information using the Debug class.
96
139
 
97
- This method captures the caller's file, method, and line number,
98
- and uses the Debug class to output debugging information.
140
+ This method captures the caller's file and line number to provide context for the debug output.
141
+ It temporarily redirects standard output and error streams to ensure the debug information is
142
+ displayed correctly. If the first argument is a recognized test case instance, it is skipped
143
+ in the output to avoid redundant information. The method raises an exception if any error
144
+ occurs during the dumping process.
99
145
 
100
146
  Parameters
101
147
  ----------
102
148
  *args : tuple
103
- Variable length argument list to be dumped.
149
+ Variable length argument list containing the objects to be dumped.
150
+
151
+ Returns
152
+ -------
153
+ None
154
+ This method does not return any value. It outputs debug information.
104
155
  """
156
+
157
+ # If no arguments are provided, exit the method early.
105
158
  if not args:
106
159
  return
107
160
 
161
+ # Save the original stdout and stderr to restore them later
108
162
  original_stdout = sys.stdout
109
163
  original_stderr = sys.stderr
110
164
 
111
165
  try:
112
- from orionis._console.dumper.dump_die import Debug
113
166
 
167
+ # Redirect stdout and stderr to the system defaults for proper debug output
114
168
  sys.stdout = sys.__stdout__
115
169
  sys.stderr = sys.__stderr__
116
170
 
171
+ # Retrieve the caller's frame to get file and line number context
117
172
  caller_frame = sys._getframe(1)
118
173
  _file = os.path.abspath(caller_frame.f_code.co_filename)
119
174
  _line = caller_frame.f_lineno
120
175
 
176
+ # Initialize the Debug dumper with context information
121
177
  dumper = Debug(f"{_file}:{_line}")
178
+
179
+ # If the first argument is a test case instance, skip it in the output
122
180
  if self.__isTestCaseClass(args[0]):
123
181
  dumper.dump(*args[1:])
124
182
  else:
125
183
  dumper.dump(*args)
184
+
126
185
  except Exception as e:
186
+
187
+ # Raise a custom runtime error if dumping fails
127
188
  raise OrionisTestRuntimeError(f"An error occurred while dumping debug information: {e}")
189
+
128
190
  finally:
191
+
192
+ # Restore the original stdout and stderr
129
193
  sys.stdout = original_stdout
130
194
  sys.stderr = original_stderr