orionis 0.371.0__py3-none-any.whl → 0.373.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 (99) hide show
  1. orionis/__init__.py +9 -0
  2. orionis/container/resolver/resolver.py +3 -3
  3. orionis/foundation/application.py +66 -31
  4. orionis/foundation/contracts/application.py +1 -1
  5. orionis/metadata/framework.py +1 -1
  6. orionis/services/introspection/dependencies/entities/callable_dependencies.py +6 -6
  7. orionis/services/introspection/dependencies/entities/class_dependencies.py +7 -7
  8. orionis/services/introspection/dependencies/entities/{resolved_dependencies.py → known_dependencies.py} +1 -1
  9. orionis/services/introspection/dependencies/entities/method_dependencies.py +6 -6
  10. orionis/services/introspection/dependencies/reflection.py +4 -4
  11. orionis/test/arguments/parser.py +197 -0
  12. orionis/test/cases/asynchronous.py +145 -0
  13. orionis/test/cases/synchronous.py +135 -0
  14. orionis/test/contracts/kernel.py +99 -0
  15. orionis/test/contracts/logs.py +125 -0
  16. orionis/test/contracts/parser.py +37 -0
  17. orionis/test/contracts/render.py +30 -0
  18. orionis/test/contracts/unit_test.py +21 -0
  19. orionis/test/core/unit_test.py +104 -23
  20. orionis/test/entities/arguments.py +38 -0
  21. orionis/test/kernel.py +276 -0
  22. orionis/test/output/dumper.py +3 -4
  23. orionis/test/output/printer.py +22 -0
  24. orionis/test/{logs → record}/history.py +25 -9
  25. orionis/test/records/__init__.py +0 -0
  26. orionis/test/records/logs.py +385 -0
  27. orionis/test/view/render.py +8 -5
  28. {orionis-0.371.0.dist-info → orionis-0.373.0.dist-info}/METADATA +1 -1
  29. {orionis-0.371.0.dist-info → orionis-0.373.0.dist-info}/RECORD +93 -88
  30. tests/example/test_example.py +4 -3
  31. tests/foundation/config/app/test_foundation_config_app.py +2 -2
  32. tests/foundation/config/auth/test_foundation_config_auth.py +2 -2
  33. tests/foundation/config/cache/test_foundation_config_cache.py +2 -2
  34. tests/foundation/config/cache/test_foundation_config_cache_file.py +2 -2
  35. tests/foundation/config/cache/test_foundation_config_cache_stores.py +2 -2
  36. tests/foundation/config/cors/test_foundation_config_cors.py +2 -2
  37. tests/foundation/config/database/test_foundation_config_database.py +2 -2
  38. tests/foundation/config/database/test_foundation_config_database_connections.py +2 -2
  39. tests/foundation/config/database/test_foundation_config_database_mysql.py +2 -2
  40. tests/foundation/config/database/test_foundation_config_database_oracle.py +2 -2
  41. tests/foundation/config/database/test_foundation_config_database_pgsql.py +2 -2
  42. tests/foundation/config/database/test_foundation_config_database_sqlite.py +2 -2
  43. tests/foundation/config/filesystems/test_foundation_config_filesystems.py +2 -2
  44. tests/foundation/config/filesystems/test_foundation_config_filesystems_aws.py +2 -2
  45. tests/foundation/config/filesystems/test_foundation_config_filesystems_disks.py +2 -2
  46. tests/foundation/config/filesystems/test_foundation_config_filesystems_local.py +2 -2
  47. tests/foundation/config/filesystems/test_foundation_config_filesystems_public.py +2 -2
  48. tests/foundation/config/logging/test_foundation_config_logging.py +2 -2
  49. tests/foundation/config/logging/test_foundation_config_logging_channels.py +2 -2
  50. tests/foundation/config/logging/test_foundation_config_logging_chunked.py +2 -2
  51. tests/foundation/config/logging/test_foundation_config_logging_daily.py +2 -2
  52. tests/foundation/config/logging/test_foundation_config_logging_hourly.py +2 -2
  53. tests/foundation/config/logging/test_foundation_config_logging_monthly.py +2 -2
  54. tests/foundation/config/logging/test_foundation_config_logging_stack.py +2 -2
  55. tests/foundation/config/logging/test_foundation_config_logging_weekly.py +2 -2
  56. tests/foundation/config/mail/test_foundation_config_mail.py +2 -2
  57. tests/foundation/config/mail/test_foundation_config_mail_file.py +2 -2
  58. tests/foundation/config/mail/test_foundation_config_mail_mailers.py +2 -2
  59. tests/foundation/config/mail/test_foundation_config_mail_smtp.py +2 -2
  60. tests/foundation/config/queue/test_foundation_config_queue.py +2 -5
  61. tests/foundation/config/queue/test_foundation_config_queue_brokers.py +2 -2
  62. tests/foundation/config/queue/test_foundation_config_queue_database.py +3 -2
  63. tests/foundation/config/root/test_foundation_config_root_paths.py +3 -3
  64. tests/foundation/config/session/test_foundation_config_session.py +4 -3
  65. tests/foundation/config/startup/test_foundation_config_startup.py +4 -3
  66. tests/foundation/config/testing/test_foundation_config_testing.py +3 -3
  67. tests/foundation/exceptions/test_foundation_config_exceptions.py +3 -3
  68. tests/metadata/test_metadata_framework.py +2 -2
  69. tests/metadata/test_metadata_package.py +3 -2
  70. tests/services/asynchrony/test_services_asynchrony_coroutine.py +2 -2
  71. tests/services/environment/test_services_environment.py +2 -2
  72. tests/services/inspection/dependencies/test_reflect_dependencies.py +22 -22
  73. tests/services/inspection/reflection/test_reflection_abstract.py +2 -2
  74. tests/services/inspection/reflection/test_reflection_callable.py +2 -2
  75. tests/services/inspection/reflection/test_reflection_concrete.py +2 -2
  76. tests/services/inspection/reflection/test_reflection_instance.py +2 -2
  77. tests/services/inspection/reflection/test_reflection_module.py +2 -2
  78. tests/services/inspection/test_reflection.py +2 -2
  79. tests/services/path/test_services_resolver.py +2 -2
  80. tests/services/system/test_services_system_imports.py +2 -2
  81. tests/services/system/test_services_system_workers.py +3 -2
  82. tests/support/parsers/test_services_parser_exceptions.py +2 -2
  83. tests/support/patterns/singleton/test_patterns_singleton.py +2 -2
  84. tests/support/standard/test_services_std.py +2 -2
  85. tests/support/wrapper/test_services_wrapper_docdict.py +2 -2
  86. tests/testing/test_testing_result.py +4 -6
  87. tests/testing/test_testing_unit.py +9 -10
  88. orionis/test/cases/test_async.py +0 -55
  89. orionis/test/cases/test_case.py +0 -42
  90. orionis/test/cases/test_sync.py +0 -33
  91. orionis/test/contracts/history.py +0 -54
  92. orionis/test/test_suite.py +0 -142
  93. orionis/unittesting.py +0 -64
  94. /orionis/test/{logs → arguments}/__init__.py +0 -0
  95. /orionis/test/entities/{test_result.py → result.py} +0 -0
  96. {orionis-0.371.0.dist-info → orionis-0.373.0.dist-info}/WHEEL +0 -0
  97. {orionis-0.371.0.dist-info → orionis-0.373.0.dist-info}/licenses/LICENCE +0 -0
  98. {orionis-0.371.0.dist-info → orionis-0.373.0.dist-info}/top_level.txt +0 -0
  99. {orionis-0.371.0.dist-info → orionis-0.373.0.dist-info}/zip-safe +0 -0
@@ -10,9 +10,10 @@ from contextlib import redirect_stdout, redirect_stderr
10
10
  from datetime import datetime
11
11
  from pathlib import Path
12
12
  from typing import Any, Dict, List, Optional, Tuple
13
+ from orionis.foundation.contracts.application import IApplication
13
14
  from orionis.services.introspection.instances.reflection import ReflectionInstance
14
15
  from orionis.services.system.workers import Workers
15
- from orionis.test.entities.test_result import TestResult
16
+ from orionis.test.entities.result import TestResult
16
17
  from orionis.test.enums import (
17
18
  ExecutionMode,
18
19
  TestStatus
@@ -22,7 +23,7 @@ from orionis.test.exceptions import (
22
23
  OrionisTestPersistenceError,
23
24
  OrionisTestValueError
24
25
  )
25
- from orionis.test.logs.history import TestHistory
26
+ from orionis.test.records.logs import TestLogs
26
27
  from orionis.test.contracts.unit_test import IUnitTest
27
28
  from orionis.test.output.printer import TestPrinter
28
29
  from orionis.test.view.render import TestingResultRender
@@ -42,7 +43,9 @@ class UnitTest(IUnitTest):
42
43
  This is an especially suitable choice for those seeking greater robustness, traceability, and visibility in their automated testing processes, offering advantages often missing from other alternatives.
43
44
  """
44
45
 
45
- def __init__(self) -> None:
46
+ def __init__(
47
+ self
48
+ ) -> None:
46
49
  """
47
50
  Initializes the test suite configuration and supporting components.
48
51
 
@@ -100,28 +103,30 @@ class UnitTest(IUnitTest):
100
103
  Result of the test execution.
101
104
  """
102
105
 
106
+ # Value for application instance
107
+ self.app: Optional[IApplication] = None
108
+
103
109
  # Values for configuration
104
- self.verbosity: int
105
- self.execution_mode: str
106
- self.max_workers: int
107
- self.fail_fast: bool
108
- self.print_result: bool
109
- self.throw_exception: bool
110
- self.persistent: bool
111
- self.persistent_driver: str
112
- self.web_report: bool
110
+ self.verbosity: Optional[int] = None
111
+ self.execution_mode: Optional[str] = None
112
+ self.max_workers: Optional[int] = None
113
+ self.fail_fast: Optional[bool] = None
114
+ self.print_result: Optional[bool] = None
115
+ self.throw_exception: Optional[bool] = None
116
+ self.persistent: Optional[bool] = None
117
+ self.persistent_driver: Optional[str] = None
118
+ self.web_report: Optional[bool] = None
113
119
 
114
120
  # Values for discovering tests in folders
115
- self.full_path: Optional[str]
116
- self.folder_path: str
117
- self.base_path: str
118
- self.pattern: str
119
- self.test_name_pattern: Optional[str]
120
- self.tags: Optional[List[str]]
121
+ self.full_path: Optional[str] = None
122
+ self.folder_path: Optional[str] = None
123
+ self.base_path: Optional[str] = None
124
+ self.pattern: Optional[str] = None
125
+ self.test_name_pattern: Optional[str] = None
126
+ self.tags: Optional[List[str]] = None
121
127
 
122
128
  # Values for discovering tests in modules
123
- self.module_name: str
124
- self.test_name_pattern: Optional[str]
129
+ self.module_name: Optional[str] = None
125
130
 
126
131
  # Initialize the test loader and suite
127
132
  self.loader = unittest.TestLoader()
@@ -138,6 +143,33 @@ class UnitTest(IUnitTest):
138
143
  # Result of the test execution
139
144
  self.__result = None
140
145
 
146
+ def setApplication(
147
+ self,
148
+ app: 'IApplication'
149
+ ) -> 'UnitTest':
150
+ """
151
+ Set the application instance for the UnitTest.
152
+ This method allows the UnitTest to access the application instance, which is necessary for resolving dependencies and executing tests.
153
+
154
+ Parameters
155
+ ----------
156
+ app : IApplication
157
+ The application instance to be set for the UnitTest.
158
+
159
+ Returns
160
+ -------
161
+ UnitTest
162
+ """
163
+
164
+ # Validate the provided application instance
165
+ if not isinstance(app, IApplication):
166
+ raise OrionisTestValueError(
167
+ f"The provided application is not a valid instance of IApplication: {type(app).__name__}."
168
+ )
169
+
170
+ # Set the application instance
171
+ self.app = app
172
+
141
173
  def configure(
142
174
  self,
143
175
  *,
@@ -657,6 +689,55 @@ class UnitTest(IUnitTest):
657
689
  # Flatten the suite to avoid duplicate tests
658
690
  flattened_suite = unittest.TestSuite(self.__flattenTestSuite(self.suite))
659
691
 
692
+ # Create a new test suite with tests that have their dependencies resolved
693
+ flattened_suite = unittest.TestSuite()
694
+ app = self.app
695
+
696
+ # Iterate through all test cases
697
+ for test_case in self.__flattenTestSuite(self.suite):
698
+ # Get the test method name
699
+ method_name = getattr(test_case, '_testMethodName', None)
700
+
701
+ # Skip if we can't identify the test method
702
+ if not method_name:
703
+ flattened_suite.addTest(test_case)
704
+ continue
705
+
706
+ # Extract dependencies for the test method
707
+ rsv = ReflectionInstance(test_case).getMethodDependencies(method_name)
708
+
709
+ # If no dependencies to resolve, just add the original test
710
+ if not rsv.resolved and not rsv.unresolved:
711
+ flattened_suite.addTest(test_case)
712
+ continue
713
+
714
+ # Create a specialized test case with resolved dependencies
715
+ test_class = test_case.__class__
716
+ original_method = getattr(test_class, method_name)
717
+
718
+ # Create a dict of resolved dependencies
719
+ args_ = {}
720
+ for k, v in rsv.resolved.items():
721
+ from orionis.services.introspection.dependencies.entities.known_dependencies import KnownDependency
722
+ if isinstance(v, KnownDependency):
723
+ args_[k] = app.make(v.type)
724
+
725
+ # Create a wrapper method that injects dependencies
726
+ def create_test_wrapper(original_test, resolved_args, unresolved_args):
727
+ def wrapper(self_instance):
728
+ args_list = list(resolved_args.values())
729
+ args_list.extend(unresolved_args)
730
+ return original_test(self_instance, *args_list)
731
+ return wrapper
732
+
733
+ # Create a new test case with the wrapped method
734
+ setattr(test_class, f"_wrapped_{method_name}", create_test_wrapper(original_method, args_, rsv.unresolved))
735
+ setattr(test_case, '_testMethodName', f"_wrapped_{method_name}")
736
+
737
+ # Add the modified test case to the suite
738
+ flattened_suite.addTest(test_case)
739
+ # sys.exit(0)
740
+
660
741
  # Create a custom result class to capture detailed test results
661
742
  with redirect_stdout(output_buffer), redirect_stderr(error_buffer):
662
743
  runner = unittest.TextTestRunner(
@@ -1108,7 +1189,7 @@ class UnitTest(IUnitTest):
1108
1189
  Notes
1109
1190
  -----
1110
1191
  Depending on the value of `self.persistent_driver`, the summary is either:
1111
- - Stored in an SQLite database (using the TestHistory class), or
1192
+ - Stored in an SQLite database (using the TestLogs class), or
1112
1193
  - Written to a timestamped JSON file in the specified base path.
1113
1194
 
1114
1195
  Raises
@@ -1129,8 +1210,8 @@ class UnitTest(IUnitTest):
1129
1210
 
1130
1211
  if self.persistent_driver == 'sqlite':
1131
1212
 
1132
- # Initialize the TestHistory class for database operations
1133
- history = TestHistory(
1213
+ # Initialize the TestLogs class for database operations
1214
+ history = TestLogs(
1134
1215
  storage_path=storage_path,
1135
1216
  db_name='tests.sqlite',
1136
1217
  table_name='reports'
@@ -0,0 +1,38 @@
1
+ from dataclasses import dataclass
2
+ from typing import Literal, Optional
3
+
4
+ @dataclass
5
+ class TestArguments:
6
+ """
7
+ Parameters for Orionis test execution.
8
+
9
+ Parameters
10
+ ----------
11
+ verbosity : int, default=2
12
+ Level of test output verbosity.
13
+ mode : {'parallel', 'sequential'}, default='parallel'
14
+ Test execution mode. Whether to run tests in parallel or sequentially.
15
+ fail_fast : bool, default=False
16
+ If True, stop execution upon first test failure.
17
+ print_result : bool, default=True
18
+ If True, print test results to the console.
19
+ throw_exception : bool, default=False
20
+ If True, raise exceptions during test execution.
21
+ persistent : bool, default=False
22
+ If True, maintain state between test runs.
23
+ persistent_driver : str, optional
24
+ Driver to use for persistent test execution.
25
+ web_report : bool, default=False
26
+ If True, generate a web-based test report.
27
+ print_output_buffer : bool, default=False
28
+ If True, print the test output buffer.
29
+ """
30
+ verbosity: int = 2
31
+ mode: Literal['parallel', 'sequential'] = 'parallel'
32
+ fail_fast: bool = False
33
+ print_result: bool = True
34
+ throw_exception: bool = False
35
+ persistent: bool = False
36
+ persistent_driver: Optional[str] = None
37
+ web_report: bool = False
38
+ print_output_buffer: bool = False
orionis/test/kernel.py ADDED
@@ -0,0 +1,276 @@
1
+ import gc
2
+ import os
3
+ import re
4
+ from os import walk
5
+ from orionis.foundation.config.testing.entities.testing import Testing as Configuration
6
+ from orionis.foundation.contracts.application import IApplication
7
+ from orionis.test.contracts.kernel import ITestKernel
8
+ from orionis.test.core.unit_test import UnitTest
9
+ from orionis.test.exceptions import OrionisTestConfigException
10
+
11
+ class TestKernel(ITestKernel):
12
+ """
13
+ Core test kernel for the Orionis testing framework.
14
+
15
+ This class provides the main interface for discovering, configuring, and executing
16
+ test suites within the Orionis framework. It handles test configuration validation,
17
+ test discovery across multiple directories, and orchestrates the execution of
18
+ discovered tests.
19
+
20
+ Parameters
21
+ ----------
22
+ app : IApplication
23
+ The Orionis application instance that provides the testing context.
24
+
25
+ Attributes
26
+ ----------
27
+ __app : IApplication
28
+ Private reference to the application instance.
29
+ __config : Configuration
30
+ Private reference to the testing configuration.
31
+ """
32
+
33
+ def __init__(
34
+ self,
35
+ app: IApplication
36
+ ) -> None:
37
+ """
38
+ Initialize the Orionis test kernel.
39
+
40
+ Parameters
41
+ ----------
42
+ app : IApplication
43
+ The application instance that implements the IApplication interface.
44
+ This provides the context and services needed for test execution.
45
+
46
+ Raises
47
+ ------
48
+ ValueError
49
+ If the provided app is None or not an instance of IApplication.
50
+ """
51
+ # Validate application instance
52
+ if app is None or not isinstance(app, IApplication):
53
+ raise ValueError("The provided application is not a valid instance of IApplication.")
54
+
55
+ # Set the application instance
56
+ self.__app = app
57
+
58
+ def __checkConfiguration(
59
+ self,
60
+ config: Configuration = None,
61
+ **kwargs
62
+ ) -> Configuration:
63
+ """
64
+ Validate and initialize the testing configuration.
65
+
66
+ This method validates the provided configuration or creates a new one from
67
+ keyword arguments. It ensures that the configuration is properly set up
68
+ before test execution begins.
69
+
70
+ Parameters
71
+ ----------
72
+ config : Configuration, optional
73
+ A pre-configured Testing configuration instance. If None, attempts to
74
+ create one from kwargs.
75
+ **kwargs : dict
76
+ Keyword arguments to create a Configuration instance if config is None.
77
+ Must match the Configuration class constructor parameters.
78
+
79
+ Returns
80
+ -------
81
+ bool
82
+ True if configuration validation succeeds.
83
+
84
+ Raises
85
+ ------
86
+ OrionisTestConfigException
87
+ If the configuration is invalid or required fields are missing.
88
+ The exception message includes details about required fields and their types.
89
+ """
90
+ # Check if config is None and kwargs are provided
91
+ if config is None:
92
+ try:
93
+ # Attempt to create a Configuration instance with provided keyword arguments
94
+ config = Configuration(**kwargs)
95
+ except TypeError:
96
+ # If a TypeError occurs, it indicates that the provided arguments do not match the Configuration class
97
+ required_fields = []
98
+ for field in Configuration().getFields():
99
+ required_fields.append(f"{field.get('name')} = (Type: {field.get('type')}, Default: {field.get('default')})")
100
+
101
+ # Raise an exception with a detailed message about the required fields
102
+ 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)}]")
103
+
104
+ # Assign the configuration to the instance variable
105
+ return config or Configuration()
106
+
107
+ def handle(
108
+ self,
109
+ config: Configuration = None,
110
+ **kwargs
111
+ ) -> UnitTest:
112
+ """
113
+ Execute the complete test discovery and execution pipeline.
114
+
115
+ This is the main entry point for running tests. It validates the configuration,
116
+ discovers test files based on specified patterns and paths, configures the
117
+ test suite, and executes all discovered tests.
118
+
119
+ Parameters
120
+ ----------
121
+ config : Configuration, optional
122
+ A pre-configured Testing configuration instance. If None, attempts to
123
+ create one from kwargs.
124
+ **kwargs : dict
125
+ Keyword arguments to create a Configuration instance if config is None.
126
+ Common parameters include:
127
+ - base_path : str, base directory for test discovery
128
+ - folder_path : str or list, specific folders to search
129
+ - pattern : str, file pattern for test discovery
130
+ - verbosity : int, output verbosity level
131
+ - execution_mode : str, test execution mode
132
+ - max_workers : int, maximum number of worker threads
133
+ - fail_fast : bool, stop on first failure
134
+
135
+ Returns
136
+ -------
137
+ UnitTest
138
+ The configured and executed test suite instance containing all results.
139
+
140
+ Raises
141
+ ------
142
+ OrionisTestConfigException
143
+ If the configuration validation fails.
144
+ """
145
+ # Validate and set configuration
146
+ config = self.__checkConfiguration(config, **kwargs)
147
+
148
+ # Initialize the test suite
149
+ tests = UnitTest()
150
+
151
+ # Assign the application instance to the test suite
152
+ tests.setApplication(self.__app)
153
+
154
+ # Configure the test suite with validated configuration values
155
+ tests.configure(
156
+ verbosity=config.verbosity,
157
+ execution_mode=config.execution_mode,
158
+ max_workers=config.max_workers,
159
+ fail_fast=config.fail_fast,
160
+ print_result=config.print_result,
161
+ throw_exception=config.throw_exception,
162
+ persistent=config.persistent,
163
+ persistent_driver=config.persistent_driver,
164
+ web_report=config.web_report
165
+ )
166
+
167
+ # Extract configuration values for test discovery
168
+ base_path = config.base_path
169
+ folder_path = config.folder_path
170
+ pattern = config.pattern
171
+
172
+ def list_matching_folders(custom_path: str, pattern: str):
173
+ """
174
+ Discover folders containing files that match the specified pattern.
175
+
176
+ This helper function walks through the directory tree starting from
177
+ custom_path and identifies folders that contain files matching the
178
+ given pattern.
179
+
180
+ Parameters
181
+ ----------
182
+ custom_path : str
183
+ The root path to start the search from.
184
+ pattern : str
185
+ The file pattern to match (supports wildcards * and ?).
186
+
187
+ Returns
188
+ -------
189
+ list of str
190
+ List of relative folder paths containing matching files.
191
+ """
192
+ matched_folders = []
193
+ for root, _, files in walk(custom_path):
194
+ for file in files:
195
+ if re.fullmatch(pattern.replace('*', '.*').replace('?', '.'), file):
196
+ relative_path = root.replace(base_path, '').replace('\\', '/').lstrip('/')
197
+ if relative_path not in matched_folders:
198
+ matched_folders.append(relative_path)
199
+ return matched_folders
200
+
201
+ # Discover test folders based on configuration
202
+ discovered_folders = []
203
+ if folder_path == '*':
204
+ # Search all folders under base_path
205
+ discovered_folders.extend(list_matching_folders(base_path, pattern))
206
+ elif isinstance(folder_path, list):
207
+ # Search specific folders provided in the list
208
+ for custom_path in folder_path:
209
+ discovered_folders.extend(list_matching_folders(f"{base_path}/{custom_path}", pattern))
210
+ else:
211
+ # Search single specified folder
212
+ discovered_folders.extend(list_matching_folders(folder_path, pattern))
213
+
214
+ # Add discovered folders to the test suite for execution
215
+ for folder in discovered_folders:
216
+ tests.discoverTestsInFolder(
217
+ folder_path=folder,
218
+ base_path=base_path,
219
+ pattern=pattern,
220
+ test_name_pattern=config.test_name_pattern if config.test_name_pattern else None,
221
+ tags=config.tags if config.tags else None
222
+ )
223
+
224
+ # Execute the test suite and return the results
225
+ tests.run()
226
+
227
+ # Return the test suite instance containing all results
228
+ return tests
229
+
230
+ def exit(
231
+ self,
232
+ code: int = 0
233
+ ) -> None:
234
+ """
235
+ Terminate the test execution process and free associated resources.
236
+
237
+ This method performs a clean shutdown of the test kernel by explicitly
238
+ triggering garbage collection to release memory resources and then
239
+ terminating the process with the provided exit code. It ensures that any
240
+ remaining file handles, threads, or other resources are properly released.
241
+
242
+ Parameters
243
+ ----------
244
+ code : int
245
+ The exit code to return to the operating system. Should be 0 for
246
+ successful execution or a non-zero value to indicate an error.
247
+
248
+ Returns
249
+ -------
250
+ None
251
+ This method does not return as it terminates the process.
252
+
253
+ Raises
254
+ ------
255
+ ValueError
256
+ If the provided code is not a valid integer or outside the allowed range.
257
+
258
+ Notes
259
+ -----
260
+ Using os._exit() bypasses normal Python cleanup mechanisms and
261
+ immediately terminates the process. This can be necessary when
262
+ normal sys.exit() would be caught by exception handlers.
263
+ """
264
+ # Validate the exit code
265
+ if not isinstance(code, int):
266
+ raise ValueError("Exit code must be an integer")
267
+
268
+ # Check if the code is within the allowed range (typically 0-255)
269
+ if code < 0 or code > 255:
270
+ raise ValueError("Exit code must be between 0 and 255")
271
+
272
+ # Force garbage collection to free memory
273
+ gc.collect()
274
+
275
+ # Terminate the process immediately without running cleanup handlers
276
+ os._exit(code)
@@ -45,10 +45,9 @@ class TestDumper(ITestDumper):
45
45
  try:
46
46
  if value is None:
47
47
  return False
48
- from orionis.test.cases.test_async import AsyncTestCase
49
- from orionis.test.cases.test_case import TestCase
50
- from orionis.test.cases.test_sync import SyncTestCase
51
- return isinstance(value, (AsyncTestCase, TestCase, SyncTestCase))
48
+ from orionis.test.cases.asynchronous import AsyncTestCase
49
+ from orionis.test.cases.synchronous import SyncTestCase
50
+ return isinstance(value, (AsyncTestCase, SyncTestCase))
52
51
  except Exception:
53
52
  return False
54
53
 
@@ -16,6 +16,28 @@ class TestPrinter(ITestPrinter):
16
16
  def __init__(
17
17
  self
18
18
  ) -> None:
19
+ """
20
+ Initialize the test output printer.
21
+
22
+ This initializes a Rich Console for output rendering, setting up panel
23
+ parameters and debug keywords for test result display.
24
+
25
+ Parameters
26
+ ----------
27
+ None
28
+
29
+ Returns
30
+ -------
31
+ None
32
+
33
+ Notes
34
+ -----
35
+ Sets up the following attributes:
36
+ - __rich_console: Rich Console instance for formatted terminal output
37
+ - __panel_title: Title string for the output panel
38
+ - __panel_width: Width of the output panel (75% of console width)
39
+ - __debbug_keywords: List of keywords for identifying debug calls
40
+ """
19
41
  self.__rich_console = Console()
20
42
  self.__panel_title: str = "🧪 Orionis Framework - Component Test Suite"
21
43
  self.__panel_width: int = int(self.__rich_console.width * 0.75)
@@ -5,9 +5,9 @@ from pathlib import Path
5
5
  from typing import Dict, List, Optional, Tuple
6
6
  from orionis.services.environment.env import Env
7
7
  from orionis.test.exceptions import OrionisTestPersistenceError, OrionisTestValueError
8
- from orionis.test.contracts.history import ITestHistory
8
+ from orionis.test.contracts.logs import ITestLogs
9
9
 
10
- class TestHistory(ITestHistory):
10
+ class TestLogs(ITestLogs):
11
11
 
12
12
  def __init__(
13
13
  self,
@@ -71,7 +71,9 @@ class TestHistory(ITestHistory):
71
71
  # Create a connection to the database, initially set to None
72
72
  self._conn: Optional[sqlite3.Connection] = None
73
73
 
74
- def __connect(self) -> None:
74
+ def __connect(
75
+ self
76
+ ) -> None:
75
77
  """
76
78
  Establishes a connection to the SQLite database if not already connected.
77
79
 
@@ -89,7 +91,9 @@ class TestHistory(ITestHistory):
89
91
  except (sqlite3.Error, Exception) as e:
90
92
  raise OrionisTestPersistenceError(f"Database connection error: {e}")
91
93
 
92
- def __createTableIfNotExists(self) -> bool:
94
+ def __createTableIfNotExists(
95
+ self
96
+ ) -> bool:
93
97
  """
94
98
  Ensures that the test history table exists in the database.
95
99
 
@@ -135,7 +139,10 @@ class TestHistory(ITestHistory):
135
139
  self.__close()
136
140
  self._conn = None
137
141
 
138
- def __insertReport(self, report: Dict) -> bool:
142
+ def __insertReport(
143
+ self,
144
+ report: Dict
145
+ ) -> bool:
139
146
  """
140
147
  Inserts a test report into the history database table.
141
148
 
@@ -272,7 +279,9 @@ class TestHistory(ITestHistory):
272
279
  self.__close()
273
280
  self._conn = None
274
281
 
275
- def __resetDatabase(self) -> bool:
282
+ def __resetDatabase(
283
+ self
284
+ ) -> bool:
276
285
  """
277
286
  Resets the database by dropping the existing table.
278
287
  This method connects to the database, drops the table specified by
@@ -304,7 +313,9 @@ class TestHistory(ITestHistory):
304
313
  self.__close()
305
314
  self._conn = None
306
315
 
307
- def __close(self) -> None:
316
+ def __close(
317
+ self
318
+ ) -> None:
308
319
  """
309
320
  Closes the current database connection.
310
321
  This method checks if a database connection exists. If so, it closes the connection and sets the connection attribute to None.
@@ -318,7 +329,10 @@ class TestHistory(ITestHistory):
318
329
  self._conn.close()
319
330
  self._conn = None
320
331
 
321
- def create(self, report: Dict) -> bool:
332
+ def create(
333
+ self,
334
+ report: Dict
335
+ ) -> bool:
322
336
  """
323
337
  Create a new test report in the history database.
324
338
 
@@ -335,7 +349,9 @@ class TestHistory(ITestHistory):
335
349
  self.__createTableIfNotExists()
336
350
  return self.__insertReport(report)
337
351
 
338
- def reset(self) -> bool:
352
+ def reset(
353
+ self
354
+ ) -> bool:
339
355
  """
340
356
  Reset the history database by dropping the existing table.
341
357
 
File without changes