orionis 0.245.0__py3-none-any.whl → 0.246.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.
- orionis/framework.py +1 -1
- orionis/luminate/config/contracts/__init__.py +0 -0
- orionis/luminate/config/contracts/config.py +27 -0
- orionis/luminate/config/entities/__init__.py +0 -0
- orionis/luminate/config/entities/testing.py +37 -0
- orionis/luminate/support/environment/env.py +1 -0
- orionis/luminate/support/introspection/abstracts/entities/__init__.py +0 -0
- orionis/luminate/support/introspection/abstracts/entities/abstract_class_attributes.py +11 -0
- orionis/luminate/support/introspection/abstracts/reflect_abstract.py +154 -16
- orionis/luminate/support/introspection/instances/reflection_instance.py +2 -2
- orionis/luminate/test/core/contracts/test_unit.py +100 -60
- orionis/luminate/test/core/test_suite.py +52 -45
- orionis/luminate/test/core/test_unit.py +774 -197
- orionis/luminate/test/entities/test_result.py +6 -2
- orionis/luminate/test/enums/test_mode.py +16 -0
- orionis/luminate/test/exceptions/test_config_exception.py +28 -0
- orionis/luminate/test/exceptions/test_exception.py +40 -33
- orionis/luminate/test/output/test_std_out.py +55 -13
- {orionis-0.245.0.dist-info → orionis-0.246.0.dist-info}/METADATA +1 -1
- {orionis-0.245.0.dist-info → orionis-0.246.0.dist-info}/RECORD +37 -29
- tests/support/inspection/fakes/fake_reflect_abstract.py +61 -5
- tests/support/inspection/test_reflect_abstract.py +62 -1
- tests/support/inspection/test_reflect_instance.py +0 -1
- /orionis/luminate/config/{app.py → entities/app.py} +0 -0
- /orionis/luminate/config/{auth.py → entities/auth.py} +0 -0
- /orionis/luminate/config/{cache.py → entities/cache.py} +0 -0
- /orionis/luminate/config/{cors.py → entities/cors.py} +0 -0
- /orionis/luminate/config/{database.py → entities/database.py} +0 -0
- /orionis/luminate/config/{filesystems.py → entities/filesystems.py} +0 -0
- /orionis/luminate/config/{logging.py → entities/logging.py} +0 -0
- /orionis/luminate/config/{mail.py → entities/mail.py} +0 -0
- /orionis/luminate/config/{queue.py → entities/queue.py} +0 -0
- /orionis/luminate/config/{session.py → entities/session.py} +0 -0
- {orionis-0.245.0.dist-info → orionis-0.246.0.dist-info}/LICENCE +0 -0
- {orionis-0.245.0.dist-info → orionis-0.246.0.dist-info}/WHEEL +0 -0
- {orionis-0.245.0.dist-info → orionis-0.246.0.dist-info}/entry_points.txt +0 -0
- {orionis-0.245.0.dist-info → orionis-0.246.0.dist-info}/top_level.txt +0 -0
orionis/framework.py
CHANGED
File without changes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
from abc import ABC
|
2
|
+
from dataclasses import dataclass
|
3
|
+
|
4
|
+
@dataclass
|
5
|
+
class EmptyData:
|
6
|
+
"""
|
7
|
+
A placeholder dataclass that can be used as a default or empty configuration.
|
8
|
+
This class doesn't have any fields or data, but serves as a default value
|
9
|
+
for the 'config' attribute in classes implementing IConfig.
|
10
|
+
"""
|
11
|
+
pass
|
12
|
+
|
13
|
+
class IConfig(ABC):
|
14
|
+
"""
|
15
|
+
An abstract base class that defines an interface for classes that must have
|
16
|
+
a `config` attribute.
|
17
|
+
|
18
|
+
The subclass is required to implement the `config` attribute, which should be
|
19
|
+
a dataclass instance representing the configuration data.
|
20
|
+
|
21
|
+
Attributes
|
22
|
+
----------
|
23
|
+
config : object
|
24
|
+
A dataclass instance representing the configuration.
|
25
|
+
"""
|
26
|
+
|
27
|
+
config = EmptyData()
|
File without changes
|
@@ -0,0 +1,37 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import List
|
3
|
+
|
4
|
+
@dataclass(frozen=True, kw_only=True)
|
5
|
+
class Testing:
|
6
|
+
"""
|
7
|
+
Testing is a dataclass that holds configuration options for running tests.
|
8
|
+
|
9
|
+
Attributes:
|
10
|
+
verbosity (int): The verbosity level of the test output. Default is 2.
|
11
|
+
- 0: Silent
|
12
|
+
- 1: Minimal output
|
13
|
+
- 2: Detailed output (default)
|
14
|
+
execution_mode (ExecutionMode): The mode of test execution. Default is ExecutionMode.SEQUENTIAL.
|
15
|
+
- ExecutionMode.SEQUENTIAL: Tests are executed one after another.
|
16
|
+
- ExecutionMode.PARALLEL: Tests are executed in parallel.
|
17
|
+
max_workers (int): The maximum number of worker threads/processes to use when running tests in parallel. Default is 4.
|
18
|
+
fail_fast (bool): Whether to stop execution after the first test failure. Default is False.
|
19
|
+
print_result (bool): Whether to print the test results to the console. Default is True.
|
20
|
+
throw_exception (bool): Whether to throw an exception if a test fails. Default is False.
|
21
|
+
base_path (str): The base directory where tests are located. Default is 'tests'.
|
22
|
+
folder_path (str): The folder path pattern to search for tests. Default is '*'.
|
23
|
+
pattern (str): The filename pattern to identify test files. Default is 'test_*.py'.
|
24
|
+
test_name_pattern (str | None): A pattern to match specific test names. Default is None.
|
25
|
+
tags (List[str] | None): A list of tags to filter tests. Default is None.
|
26
|
+
"""
|
27
|
+
verbosity: int = 2
|
28
|
+
execution_mode: str = 'sequential'
|
29
|
+
max_workers: int = 4
|
30
|
+
fail_fast: bool = False
|
31
|
+
print_result: bool = True
|
32
|
+
throw_exception: bool = False
|
33
|
+
base_path: str = 'tests'
|
34
|
+
folder_path: str = '*'
|
35
|
+
pattern: str = 'test_*.py'
|
36
|
+
test_name_pattern: str | None = None,
|
37
|
+
tags: List[str] | None = None
|
File without changes
|
@@ -0,0 +1,11 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import Any, Dict
|
3
|
+
|
4
|
+
@dataclass(frozen=True, kw_only=True)
|
5
|
+
class AbstractClassAttributes:
|
6
|
+
"""
|
7
|
+
A class to represent the attributes of an entity.
|
8
|
+
"""
|
9
|
+
public: Dict[str, Any]
|
10
|
+
private: Dict[str, Any]
|
11
|
+
protected: Dict[str, Any]
|
@@ -3,11 +3,11 @@ import ast
|
|
3
3
|
import inspect
|
4
4
|
import types
|
5
5
|
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, TypeVar
|
6
|
-
from orionis.luminate.support.introspection.
|
6
|
+
from orionis.luminate.support.introspection.abstracts.entities.abstract_class_attributes import AbstractClassAttributes
|
7
7
|
|
8
8
|
ABC = TypeVar('ABC', bound=abc.ABC)
|
9
9
|
|
10
|
-
class ReflexionAbstract
|
10
|
+
class ReflexionAbstract:
|
11
11
|
"""A reflection object encapsulating an abstract class.
|
12
12
|
|
13
13
|
Parameters
|
@@ -64,7 +64,7 @@ class ReflexionAbstract(IReflexionAbstract):
|
|
64
64
|
"""
|
65
65
|
return self._abstract.__module__
|
66
66
|
|
67
|
-
def getAllAttributes(self) ->
|
67
|
+
def getAllAttributes(self) -> AbstractClassAttributes:
|
68
68
|
"""
|
69
69
|
Get all attributes of the abstract class.
|
70
70
|
|
@@ -93,11 +93,161 @@ class ReflexionAbstract(IReflexionAbstract):
|
|
93
93
|
else:
|
94
94
|
public[attr] = value
|
95
95
|
|
96
|
-
return
|
96
|
+
return AbstractClassAttributes(
|
97
|
+
public=public,
|
98
|
+
private=private,
|
99
|
+
protected=protected
|
100
|
+
)
|
97
101
|
|
102
|
+
def getAttributes(self) -> Dict[str, Any]:
|
103
|
+
"""
|
104
|
+
Get all attributes of the instance.
|
98
105
|
|
106
|
+
Returns
|
107
|
+
-------
|
108
|
+
Dict[str, Any]
|
109
|
+
Dictionary of attribute names and their values
|
110
|
+
"""
|
111
|
+
attr = self.getAllAttributes()
|
112
|
+
return {**attr.public, **attr.private, **attr.protected}
|
99
113
|
|
114
|
+
def getPublicAttributes(self) -> Dict[str, Any]:
|
115
|
+
"""
|
116
|
+
Get all public attributes of the instance.
|
100
117
|
|
118
|
+
Returns
|
119
|
+
-------
|
120
|
+
Dict[str, Any]
|
121
|
+
Dictionary of public attribute names and their values
|
122
|
+
"""
|
123
|
+
attr = self.getAllAttributes()
|
124
|
+
return attr.public
|
125
|
+
|
126
|
+
def getPrivateAttributes(self) -> Dict[str, Any]:
|
127
|
+
"""
|
128
|
+
Get all private attributes of the instance.
|
129
|
+
|
130
|
+
Returns
|
131
|
+
-------
|
132
|
+
Dict[str, Any]
|
133
|
+
Dictionary of private attribute names and their values
|
134
|
+
"""
|
135
|
+
attr = self.getAllAttributes()
|
136
|
+
return attr.private
|
137
|
+
|
138
|
+
def getProtectedAttributes(self) -> Dict[str, Any]:
|
139
|
+
"""
|
140
|
+
Get all Protected attributes of the instance.
|
141
|
+
|
142
|
+
Returns
|
143
|
+
-------
|
144
|
+
Dict[str, Any]
|
145
|
+
Dictionary of Protected attribute names and their values
|
146
|
+
"""
|
147
|
+
attr = self.getAllAttributes()
|
148
|
+
return attr.protected
|
149
|
+
|
150
|
+
def getAllMethods(self) -> Dict[str, List[str]]:
|
151
|
+
"""
|
152
|
+
Categorize all methods and relevant members of the abstract class into public, private, protected,
|
153
|
+
static, asynchronous, synchronous, class methods, magic methods, abstract methods, and properties.
|
154
|
+
|
155
|
+
Returns
|
156
|
+
-------
|
157
|
+
Dict[str, List[str]]
|
158
|
+
A dictionary categorizing methods and attributes into various types.
|
159
|
+
"""
|
160
|
+
class_name = self.getClassName()
|
161
|
+
private_prefix = f"_{class_name}"
|
162
|
+
attributes = set(self.getAttributes().keys()) | {attr for attr in dir(self._abstract) if attr.startswith('_abc_')}
|
163
|
+
|
164
|
+
result = {
|
165
|
+
"public": [],
|
166
|
+
"private": [],
|
167
|
+
"protected": [],
|
168
|
+
"static": [],
|
169
|
+
"asynchronous": [],
|
170
|
+
"synchronous": [],
|
171
|
+
"class_methods": [],
|
172
|
+
"asynchronous_static": [],
|
173
|
+
"synchronous_static": [],
|
174
|
+
"magic": [],
|
175
|
+
"abstract": [],
|
176
|
+
"abstract_class_methods": [],
|
177
|
+
"abstract_static_methods": []
|
178
|
+
}
|
179
|
+
|
180
|
+
# Precompute all members once
|
181
|
+
members = inspect.getmembers(self._abstract)
|
182
|
+
static_attrs = {}
|
183
|
+
|
184
|
+
# First pass to collect all relevant information
|
185
|
+
for name, attr in members:
|
186
|
+
if name in attributes:
|
187
|
+
continue
|
188
|
+
|
189
|
+
# Get static attribute once
|
190
|
+
static_attr = inspect.getattr_static(self._abstract, name)
|
191
|
+
static_attrs[name] = static_attr
|
192
|
+
|
193
|
+
# Magic methods
|
194
|
+
if name.startswith("__") and name.endswith("__"):
|
195
|
+
result["magic"].append(name)
|
196
|
+
continue
|
197
|
+
|
198
|
+
# Static and class methods
|
199
|
+
if isinstance(static_attr, staticmethod):
|
200
|
+
result["static"].append(name)
|
201
|
+
elif isinstance(static_attr, classmethod):
|
202
|
+
result["class_methods"].append(name)
|
203
|
+
|
204
|
+
# Private, protected, public
|
205
|
+
if name.startswith(private_prefix):
|
206
|
+
clean_name = name.replace(private_prefix, "")
|
207
|
+
result["private"].append(clean_name)
|
208
|
+
elif name.startswith("_"):
|
209
|
+
result["protected"].append(name)
|
210
|
+
else:
|
211
|
+
result["public"].append(name)
|
212
|
+
|
213
|
+
# Async methods
|
214
|
+
if inspect.iscoroutinefunction(attr):
|
215
|
+
clean_name = name.replace(private_prefix, "")
|
216
|
+
if name in result["static"]:
|
217
|
+
result["asynchronous_static"].append(clean_name)
|
218
|
+
else:
|
219
|
+
result["asynchronous"].append(clean_name)
|
220
|
+
|
221
|
+
# Second pass for synchronous methods (needs info from first pass)
|
222
|
+
for name, attr in members:
|
223
|
+
if name in attributes or name in result["magic"] or name in result["class_methods"] or name in result["static"]:
|
224
|
+
continue
|
225
|
+
|
226
|
+
if inspect.isfunction(attr):
|
227
|
+
clean_name = name.replace(private_prefix, "")
|
228
|
+
if clean_name not in result["asynchronous"]:
|
229
|
+
result["synchronous"].append(clean_name)
|
230
|
+
|
231
|
+
# Synchronous static methods
|
232
|
+
for name in result["static"]:
|
233
|
+
if name not in attributes and name not in result["asynchronous_static"] and name not in result["class_methods"]:
|
234
|
+
result["synchronous_static"].append(name)
|
235
|
+
|
236
|
+
# Abstract methods
|
237
|
+
abstract_methods = getattr(self._abstract, "__abstractmethods__", set())
|
238
|
+
for name in abstract_methods:
|
239
|
+
if name in attributes:
|
240
|
+
continue
|
241
|
+
|
242
|
+
static_attr = static_attrs.get(name, inspect.getattr_static(self._abstract, name))
|
243
|
+
if isinstance(static_attr, staticmethod):
|
244
|
+
result["abstract_static_methods"].append(name)
|
245
|
+
elif isinstance(static_attr, classmethod):
|
246
|
+
result["abstract_class_methods"].append(name)
|
247
|
+
elif not isinstance(static_attr, property):
|
248
|
+
result["abstract"].append(name)
|
249
|
+
|
250
|
+
return result
|
101
251
|
|
102
252
|
|
103
253
|
|
@@ -109,19 +259,7 @@ class ReflexionAbstract(IReflexionAbstract):
|
|
109
259
|
|
110
260
|
|
111
261
|
|
112
|
-
def getAbstractMethods(self) -> Set[str]:
|
113
|
-
"""Get all abstract method names required by the class.
|
114
262
|
|
115
|
-
Returns
|
116
|
-
-------
|
117
|
-
Set[str]
|
118
|
-
Set of abstract method names
|
119
|
-
"""
|
120
|
-
methods = []
|
121
|
-
for method in self._abstract.__abstractmethods__:
|
122
|
-
if not isinstance(getattr(self._abstract, method), property):
|
123
|
-
methods.append(method)
|
124
|
-
return set(methods)
|
125
263
|
|
126
264
|
def getAbstractProperties(self) -> Set[str]:
|
127
265
|
"""Get all abstract property names required by the class.
|
@@ -171,8 +171,8 @@ class ReflectionInstance(IReflectionInstance):
|
|
171
171
|
def getAllMethods(self):
|
172
172
|
"""
|
173
173
|
Retrieves and categorizes all methods of the instance's class into various classifications.
|
174
|
-
This method inspects the instance's class and its methods, categorizing them into public, private,
|
175
|
-
protected, static, asynchronous, synchronous, class methods, asynchronous static, synchronous static,
|
174
|
+
This method inspects the instance's class and its methods, categorizing them into public, private,
|
175
|
+
protected, static, asynchronous, synchronous, class methods, asynchronous static, synchronous static,
|
176
176
|
and magic methods.
|
177
177
|
Returns
|
178
178
|
-------
|
@@ -1,82 +1,122 @@
|
|
1
|
-
from
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
from typing import Any, Dict, List, Optional
|
3
|
+
from orionis.luminate.test.enums.test_mode import ExecutionMode
|
2
4
|
|
3
|
-
class IUnitTest:
|
4
|
-
"""
|
5
|
-
Advanced unit testing utility for discovering, executing, and reporting test results
|
6
|
-
with support for folder-based discovery, regex filtering, and customizable output.
|
5
|
+
class IUnitTest(ABC):
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
7
|
+
@abstractmethod
|
8
|
+
def configure(
|
9
|
+
self,
|
10
|
+
verbosity: int = None,
|
11
|
+
execution_mode: ExecutionMode = None,
|
12
|
+
max_workers: int = None,
|
13
|
+
fail_fast: bool = None,
|
14
|
+
print_result: bool = None
|
15
|
+
):
|
16
|
+
"""
|
17
|
+
Configures the UnitTest instance with the specified parameters.
|
18
|
+
|
19
|
+
Parameters:
|
20
|
+
verbosity (int, optional): The verbosity level for test output. Defaults to None.
|
21
|
+
execution_mode (ExecutionMode, optional): The mode in which the tests will be executed. Defaults to None.
|
22
|
+
max_workers (int, optional): The maximum number of workers to use for parallel execution. Defaults to None.
|
23
|
+
fail_fast (bool, optional): Whether to stop execution upon the first failure. Defaults to None.
|
24
|
+
print_result (bool, optional): Whether to print the test results after execution. Defaults to None.
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
UnitTest: The configured UnitTest instance.
|
28
|
+
"""
|
29
|
+
pass
|
19
30
|
|
31
|
+
@abstractmethod
|
20
32
|
def discoverTestsInFolder(
|
21
33
|
self,
|
22
34
|
folder_path: str,
|
23
35
|
base_path: str = "tests",
|
24
36
|
pattern: str = "test_*.py",
|
25
|
-
test_name_pattern: Optional[str] = None
|
37
|
+
test_name_pattern: Optional[str] = None,
|
38
|
+
tags: Optional[List[str]] = None
|
26
39
|
):
|
27
40
|
"""
|
28
|
-
|
41
|
+
Discovers and loads unit tests from a specified folder.
|
42
|
+
Args:
|
43
|
+
folder_path (str): The relative path to the folder containing the tests.
|
44
|
+
base_path (str, optional): The base directory where the test folder is located. Defaults to "tests".
|
45
|
+
pattern (str, optional): The filename pattern to match test files. Defaults to "test_*.py".
|
46
|
+
test_name_pattern (Optional[str], optional): A pattern to filter test names. Defaults to None.
|
47
|
+
tags (Optional[List[str]], optional): A list of tags to filter tests. Defaults to None.
|
48
|
+
Returns:
|
49
|
+
UnitTest: The current instance of the UnitTest class with the discovered tests added.
|
50
|
+
Raises:
|
51
|
+
ValueError: If the test folder does not exist, no tests are found, or an error occurs during test discovery.
|
52
|
+
"""
|
53
|
+
pass
|
54
|
+
|
55
|
+
@abstractmethod
|
56
|
+
def discoverTestsInModule(self, module_name: str, test_name_pattern: Optional[str] = None):
|
57
|
+
"""
|
58
|
+
Discovers and loads tests from a specified module, optionally filtering them
|
59
|
+
by a test name pattern, and adds them to the test suite.
|
60
|
+
Args:
|
61
|
+
module_name (str): The name of the module to discover tests from.
|
62
|
+
test_name_pattern (Optional[str]): A pattern to filter test names. Only
|
63
|
+
tests matching this pattern will be included. Defaults to None.
|
64
|
+
Returns:
|
65
|
+
UnitTest: The current instance of the UnitTest class, allowing method chaining.
|
66
|
+
Raises:
|
67
|
+
ValueError: If the specified module cannot be imported.
|
68
|
+
"""
|
69
|
+
pass
|
70
|
+
|
71
|
+
@abstractmethod
|
72
|
+
def run(self, print_result: bool = None, throw_exception: bool = False) -> Dict[str, Any]:
|
73
|
+
"""
|
74
|
+
Executes the test suite and processes the results.
|
75
|
+
Args:
|
76
|
+
print_result (bool, optional): If provided, overrides the instance's
|
77
|
+
`print_result` attribute to determine whether to print the test results.
|
78
|
+
throw_exception (bool, optional): If True, raises an exception if any
|
79
|
+
test failures or errors are detected.
|
80
|
+
Returns:
|
81
|
+
Dict[str, Any]: A summary of the test execution, including details such as
|
82
|
+
execution time, test results, and a timestamp.
|
83
|
+
Raises:
|
84
|
+
OrionisTestFailureException: If `throw_exception` is True and there are
|
85
|
+
test failures or errors.
|
86
|
+
"""
|
87
|
+
pass
|
29
88
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
base_path : str, default="tests"
|
35
|
-
Base path used to resolve full path to test modules.
|
36
|
-
pattern : str, default="test_*.py"
|
37
|
-
Glob pattern to match test filenames.
|
38
|
-
test_name_pattern : Optional[str], optional
|
39
|
-
Regex pattern to filter discovered test method names.
|
89
|
+
@abstractmethod
|
90
|
+
def getTestNames(self) -> List[str]:
|
91
|
+
"""
|
92
|
+
Retrieves a list of test names from the test suite.
|
40
93
|
|
41
|
-
|
42
|
-
|
43
|
-
UnitTest
|
44
|
-
Self instance for chaining.
|
94
|
+
This method flattens the test suite and extracts the unique identifier
|
95
|
+
(`id`) of each test case.
|
45
96
|
|
46
|
-
|
47
|
-
|
48
|
-
ValueError
|
49
|
-
If folder is invalid or no tests are found.
|
97
|
+
Returns:
|
98
|
+
List[str]: A list of test names (unique identifiers) from the test suite.
|
50
99
|
"""
|
51
100
|
pass
|
52
101
|
|
53
|
-
|
102
|
+
@abstractmethod
|
103
|
+
def getTestCount(self) -> int:
|
54
104
|
"""
|
55
|
-
|
105
|
+
Calculate the total number of tests in the test suite.
|
56
106
|
|
57
|
-
|
58
|
-
|
59
|
-
print_result : bool, default=True
|
60
|
-
Whether to print a formatted report to the console.
|
61
|
-
throw_exception : bool, default=False
|
62
|
-
Raise an exception if there are failures or errors.
|
107
|
+
This method flattens the test suite structure and counts the total
|
108
|
+
number of individual test cases.
|
63
109
|
|
64
|
-
Returns
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
- total_time : str (e.g., '1.234 seconds')
|
74
|
-
- success_rate : str (e.g., '87.5%')
|
75
|
-
- test_details : List[Dict[str, Any]]
|
110
|
+
Returns:
|
111
|
+
int: The total number of test cases in the test suite.
|
112
|
+
"""
|
113
|
+
pass
|
114
|
+
|
115
|
+
@abstractmethod
|
116
|
+
def clearTests(self) -> None:
|
117
|
+
"""
|
118
|
+
Clears the current test suite by reinitializing it to an empty `unittest.TestSuite`.
|
76
119
|
|
77
|
-
|
78
|
-
------
|
79
|
-
OrionisTestFailureException
|
80
|
-
If any test fails or errors occur and `throw_exception=True`.
|
120
|
+
This method is used to reset the test suite, removing any previously added tests.
|
81
121
|
"""
|
82
122
|
pass
|
@@ -1,53 +1,61 @@
|
|
1
1
|
import re
|
2
2
|
from os import walk
|
3
|
-
from orionis.luminate.
|
4
|
-
from orionis.luminate.test.core.test_unit import UnitTest
|
3
|
+
from orionis.luminate.config.entities.testing import Testing
|
4
|
+
from orionis.luminate.test.core.test_unit import UnitTest
|
5
|
+
from orionis.luminate.test.exceptions.test_config_exception import OrionisTestConfigException
|
5
6
|
|
6
|
-
class TestSuite
|
7
|
-
"""
|
8
|
-
A class containing test utility methods.
|
9
|
-
"""
|
7
|
+
class TestSuite:
|
10
8
|
|
11
9
|
@staticmethod
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
def config(config:Testing) -> UnitTest:
|
11
|
+
"""
|
12
|
+
Configures and initializes a test suite based on the provided configuration.
|
13
|
+
Args:
|
14
|
+
config (Testing): An instance of the `Testing` class containing configuration
|
15
|
+
parameters for the test suite.
|
16
|
+
Returns:
|
17
|
+
UnitTest: An initialized test suite configured with the provided settings.
|
18
|
+
Raises:
|
19
|
+
OrionisTestConfigException: If the `config` parameter is not an instance of
|
20
|
+
the `Testing` class.
|
21
|
+
The function performs the following steps:
|
22
|
+
1. Validates that the `config` parameter is an instance of the `Testing` class.
|
23
|
+
2. Initializes a `UnitTest` object and assigns configuration values to it.
|
24
|
+
3. Extracts configuration values such as `base_path`, `folder_path`, and `pattern`.
|
25
|
+
4. Discovers folders matching the specified `folder_path` and `pattern`:
|
26
|
+
- If `folder_path` is '*', all matching folders in the `base_path` are discovered.
|
27
|
+
- If `folder_path` is a list, matching folders in each path are discovered.
|
28
|
+
- Otherwise, matching folders in the specified `folder_path` are discovered.
|
29
|
+
5. Adds discovered folders to the test suite by calling `discoverTestsInFolder`.
|
30
|
+
Notes:
|
31
|
+
- The `list_matching_folders` helper function is used to find folders matching
|
32
|
+
the specified pattern.
|
33
|
+
- The `pattern` supports wildcard characters (`*` and `?`) for flexible matching.
|
34
|
+
- The `test_name_pattern` and `tags` from the `config` are used when adding
|
35
|
+
folders to the test suite.
|
17
36
|
"""
|
18
|
-
Discover and initialize a test suite from the specified folder(s).
|
19
37
|
|
20
|
-
|
21
|
-
|
38
|
+
# Check if the config is an instance of Testing
|
39
|
+
if not isinstance(config, Testing):
|
40
|
+
raise OrionisTestConfigException("The config parameter must be an instance of the Testing class.")
|
22
41
|
|
23
|
-
|
24
|
-
|
25
|
-
base_path : str, optional
|
26
|
-
The base path for the tests. Defaults to 'tests'.
|
27
|
-
folder_path : str or list of str, optional
|
28
|
-
Path(s) to the folder(s) containing test files. Use '*' to scan all folders
|
29
|
-
under the base path. Defaults to '*'.
|
30
|
-
pattern : str, optional
|
31
|
-
File pattern to match test files. Defaults to 'test_*.py'.
|
42
|
+
# Initialize the test suite
|
43
|
+
tests = UnitTest()
|
32
44
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
45
|
+
# Assign config values to the test suite
|
46
|
+
tests.configure(
|
47
|
+
verbosity=config.verbosity,
|
48
|
+
execution_mode=config.execution_mode,
|
49
|
+
max_workers=config.max_workers,
|
50
|
+
fail_fast=config.fail_fast,
|
51
|
+
print_result=config.print_result,
|
52
|
+
throw_exception=config.throw_exception
|
53
|
+
)
|
37
54
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
`pattern` is not a string.
|
43
|
-
"""
|
44
|
-
# Validate parameters
|
45
|
-
if not isinstance(base_path, str):
|
46
|
-
raise TypeError("base_path must be a string")
|
47
|
-
if not isinstance(folder_path, (str, list)):
|
48
|
-
raise TypeError("folder_path must be a string or a list")
|
49
|
-
if not isinstance(pattern, str):
|
50
|
-
raise TypeError("pattern must be a string")
|
55
|
+
# Extract configuration values
|
56
|
+
base_path = config.base_path
|
57
|
+
folder_path = config.folder_path
|
58
|
+
pattern = config.pattern
|
51
59
|
|
52
60
|
# Helper function to list folders matching the pattern
|
53
61
|
def list_matching_folders(custom_path: str, pattern: str):
|
@@ -70,15 +78,14 @@ class TestSuite(ITestSuite):
|
|
70
78
|
else:
|
71
79
|
discovered_folders.extend(list_matching_folders(folder_path, pattern))
|
72
80
|
|
73
|
-
# Initialize the test suite
|
74
|
-
tests = UnitTestClass()
|
75
|
-
|
76
81
|
# Add discovered folders to the test suite
|
77
82
|
for folder in discovered_folders:
|
78
83
|
tests.discoverTestsInFolder(
|
79
|
-
base_path=base_path,
|
80
84
|
folder_path=folder,
|
81
|
-
|
85
|
+
base_path=base_path,
|
86
|
+
pattern=pattern,
|
87
|
+
test_name_pattern=config.test_name_pattern if config.test_name_pattern else None,
|
88
|
+
tags=config.tags if config.tags else None
|
82
89
|
)
|
83
90
|
|
84
91
|
# Return the initialized test suite
|