orionis 0.407.0__py3-none-any.whl → 0.409.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/container/container.py +11 -9
- orionis/container/enums/lifetimes.py +2 -0
- orionis/container/validators/__init__.py +21 -0
- orionis/metadata/framework.py +1 -1
- orionis/services/log/contracts/log_service.py +56 -4
- orionis/services/log/handlers/filename.py +20 -12
- orionis/services/log/handlers/size_rotating.py +11 -3
- orionis/services/log/handlers/timed_rotating.py +11 -3
- orionis/services/log/log_service.py +122 -72
- orionis/services/paths/contracts/resolver.py +0 -1
- {orionis-0.407.0.dist-info → orionis-0.409.0.dist-info}/METADATA +1 -1
- {orionis-0.407.0.dist-info → orionis-0.409.0.dist-info}/RECORD +37 -35
- tests/container/context/test_manager.py +15 -5
- tests/container/context/test_scope.py +12 -4
- tests/container/entities/test_binding.py +130 -21
- tests/container/enums/test_lifetimes.py +52 -18
- tests/container/facades/test_facade.py +29 -12
- tests/container/providers/test_providers.py +17 -10
- tests/container/resolver/test_resolver.py +14 -7
- tests/container/test_container.py +226 -71
- tests/container/test_singleton.py +43 -24
- tests/container/test_thread_safety.py +28 -156
- tests/container/validators/test_implements.py +59 -13
- tests/container/validators/test_is_abstract_class.py +73 -25
- tests/container/validators/test_is_callable.py +55 -26
- tests/container/validators/test_is_concrete_class.py +80 -17
- tests/container/validators/test_is_instance.py +67 -22
- tests/container/validators/test_is_not_subclass.py +28 -95
- tests/container/validators/test_is_subclass.py +84 -21
- tests/container/validators/test_is_valid_alias.py +46 -12
- tests/container/validators/test_lifetime.py +45 -14
- tests/services/log/__init__.py +0 -0
- tests/services/log/test_log.py +97 -0
- {orionis-0.407.0.dist-info → orionis-0.409.0.dist-info}/WHEEL +0 -0
- {orionis-0.407.0.dist-info → orionis-0.409.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.407.0.dist-info → orionis-0.409.0.dist-info}/top_level.txt +0 -0
- {orionis-0.407.0.dist-info → orionis-0.409.0.dist-info}/zip-safe +0 -0
|
@@ -7,16 +7,23 @@ class TestServiceProviderMethods(AsyncTestCase):
|
|
|
7
7
|
|
|
8
8
|
async def testMethodsExist(self):
|
|
9
9
|
"""
|
|
10
|
-
|
|
10
|
+
Validates the implementation of required methods and inheritance in the ServiceProvider class.
|
|
11
11
|
|
|
12
|
-
This test
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
12
|
+
This test performs the following checks:
|
|
13
|
+
- Verifies that the ServiceProvider class defines the '__init__', 'register', and 'boot' methods.
|
|
14
|
+
- Ensures that the 'register' and 'boot' methods are asynchronous coroutine functions.
|
|
15
|
+
- Confirms that ServiceProvider is a subclass of IServiceProvider.
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
None
|
|
20
|
+
|
|
21
|
+
Returns
|
|
22
|
+
-------
|
|
23
|
+
None
|
|
24
|
+
The method does not return any value. Assertions are used to validate class structure and method types.
|
|
19
25
|
"""
|
|
26
|
+
|
|
20
27
|
# List of required methods and their associated class
|
|
21
28
|
expected_methods = [
|
|
22
29
|
("__init__", ServiceProvider),
|
|
@@ -34,15 +41,15 @@ class TestServiceProviderMethods(AsyncTestCase):
|
|
|
34
41
|
# Ensure 'register' and 'boot' are asynchronous methods
|
|
35
42
|
self.assertTrue(
|
|
36
43
|
inspect.iscoroutinefunction(ServiceProvider.register),
|
|
37
|
-
"register must be async"
|
|
44
|
+
"'register' must be an async coroutine function."
|
|
38
45
|
)
|
|
39
46
|
self.assertTrue(
|
|
40
47
|
inspect.iscoroutinefunction(ServiceProvider.boot),
|
|
41
|
-
"boot must be async"
|
|
48
|
+
"'boot' must be an async coroutine function."
|
|
42
49
|
)
|
|
43
50
|
|
|
44
51
|
# Ensure ServiceProvider inherits from IServiceProvider
|
|
45
52
|
self.assertTrue(
|
|
46
53
|
issubclass(ServiceProvider, IServiceProvider),
|
|
47
|
-
"ServiceProvider must inherit from IServiceProvider"
|
|
54
|
+
"ServiceProvider must inherit from IServiceProvider."
|
|
48
55
|
)
|
|
@@ -7,15 +7,22 @@ class TestResolverMethods(AsyncTestCase):
|
|
|
7
7
|
|
|
8
8
|
async def testMethodsExist(self):
|
|
9
9
|
"""
|
|
10
|
-
|
|
10
|
+
Validates the implementation and structure of the `Resolver` class.
|
|
11
11
|
|
|
12
|
-
This test
|
|
13
|
-
|
|
12
|
+
This test checks that the `Resolver` class:
|
|
13
|
+
- Implements all required methods.
|
|
14
|
+
- Inherits from the `IResolver` interface.
|
|
15
|
+
- Has main public methods (`resolve`, `resolveType`, `resolveSignature`) that are synchronous.
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
self : TestResolverMethods
|
|
20
|
+
The test case instance.
|
|
14
21
|
|
|
15
22
|
Returns
|
|
16
23
|
-------
|
|
17
24
|
None
|
|
18
|
-
|
|
25
|
+
The method does not return any value. Assertions are used to validate the class structure.
|
|
19
26
|
"""
|
|
20
27
|
|
|
21
28
|
# List of required method names that must be implemented by Resolver
|
|
@@ -34,20 +41,20 @@ class TestResolverMethods(AsyncTestCase):
|
|
|
34
41
|
"_Resolver__resolveDependencies",
|
|
35
42
|
]
|
|
36
43
|
|
|
37
|
-
#
|
|
44
|
+
# Check that each required method exists in Resolver
|
|
38
45
|
for method in required_methods:
|
|
39
46
|
self.assertTrue(
|
|
40
47
|
hasattr(Resolver, method),
|
|
41
48
|
f"Resolver must implement the method '{method}'"
|
|
42
49
|
)
|
|
43
50
|
|
|
44
|
-
#
|
|
51
|
+
# Ensure Resolver inherits from IResolver
|
|
45
52
|
self.assertTrue(
|
|
46
53
|
issubclass(Resolver, IResolver),
|
|
47
54
|
"Resolver must inherit from IResolver"
|
|
48
55
|
)
|
|
49
56
|
|
|
50
|
-
#
|
|
57
|
+
# Verify that main public methods are not asynchronous
|
|
51
58
|
for method in ["resolve", "resolveType", "resolveSignature"]:
|
|
52
59
|
self.assertFalse(
|
|
53
60
|
inspect.iscoroutinefunction(getattr(Resolver, method)),
|
|
@@ -5,63 +5,109 @@ from orionis.test.cases.asynchronous import AsyncTestCase
|
|
|
5
5
|
from tests.container.mocks.mock_simple_classes import Car, ICar
|
|
6
6
|
|
|
7
7
|
class TestContainer(AsyncTestCase):
|
|
8
|
-
"""Test suite for the Container class functionality."""
|
|
9
8
|
|
|
10
9
|
async def testTransientRegistration(self) -> None:
|
|
11
10
|
"""
|
|
12
11
|
Tests the transient registration of a service in the container.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
|
|
13
|
+
This method verifies the following behaviors:
|
|
14
|
+
- The `container.transient()` method correctly registers a transient binding from an abstract type (`ICar`) to a concrete implementation (`Car`).
|
|
15
|
+
- Each call to `container.make(ICar)` returns a new instance of `Car`, confirming transient behavior.
|
|
16
|
+
- The resolved instances are of the correct type (`Car`), and each instance is a distinct object.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
self : TestContainer
|
|
21
|
+
The test case instance.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
None
|
|
26
|
+
This method does not return any value. Assertions are used to validate expected behavior.
|
|
27
|
+
|
|
28
|
+
Notes
|
|
29
|
+
-----
|
|
30
|
+
After the test, the registration for `ICar` is dropped from the container to clean up.
|
|
17
31
|
"""
|
|
18
32
|
container = Container()
|
|
33
|
+
# Register ICar as a transient binding to Car
|
|
19
34
|
container.transient(ICar, Car)
|
|
35
|
+
# Resolve two instances of ICar (should be different objects)
|
|
20
36
|
instance1 = container.make(ICar)
|
|
21
37
|
instance2 = container.make(ICar)
|
|
22
38
|
|
|
39
|
+
# Assert both instances are of type Car
|
|
23
40
|
self.assertIsInstance(instance1, Car)
|
|
24
41
|
self.assertIsInstance(instance2, Car)
|
|
42
|
+
# Assert that the instances are not the same object (transient behavior)
|
|
25
43
|
self.assertIsNot(instance1, instance2)
|
|
26
44
|
|
|
45
|
+
# Clean up registration
|
|
27
46
|
container.drop(abstract=ICar)
|
|
28
47
|
|
|
29
48
|
async def testSingletonRegistration(self) -> None:
|
|
30
49
|
"""
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
50
|
+
Tests singleton registration and resolution from the container.
|
|
51
|
+
|
|
52
|
+
This method ensures:
|
|
53
|
+
- A class (`Car`) can be registered as a singleton implementation of an interface (`ICar`).
|
|
54
|
+
- The container returns an instance of the registered implementation.
|
|
55
|
+
- Multiple requests for the same interface return the same instance, confirming singleton behavior.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
self : TestContainer
|
|
60
|
+
The test case instance.
|
|
61
|
+
|
|
62
|
+
Returns
|
|
63
|
+
-------
|
|
64
|
+
None
|
|
65
|
+
This method does not return any value. Assertions are used to validate expected behavior.
|
|
66
|
+
|
|
67
|
+
Notes
|
|
68
|
+
-----
|
|
69
|
+
The registration for `ICar` is dropped after the test.
|
|
40
70
|
"""
|
|
41
71
|
container = Container()
|
|
72
|
+
# Register ICar as a singleton binding to Car
|
|
42
73
|
container.singleton(ICar, Car)
|
|
74
|
+
# Resolve two instances of ICar (should be the same object)
|
|
43
75
|
instance1 = container.make(ICar)
|
|
44
76
|
instance2 = container.make(ICar)
|
|
45
77
|
|
|
78
|
+
# Assert both instances are of type Car
|
|
46
79
|
self.assertIsInstance(instance1, Car)
|
|
47
80
|
self.assertIsInstance(instance2, Car)
|
|
81
|
+
# Assert that both instances are the same object (singleton behavior)
|
|
48
82
|
self.assertIs(instance1, instance2)
|
|
49
83
|
|
|
84
|
+
# Clean up registration
|
|
50
85
|
container.drop(abstract=ICar)
|
|
51
86
|
|
|
52
87
|
async def testScopedRegistration(self) -> None:
|
|
53
88
|
"""
|
|
54
89
|
Tests the scoped registration functionality of the container.
|
|
55
|
-
This test verifies that:
|
|
56
|
-
1. Within a single context, scoped registrations return the same instance
|
|
57
|
-
when the same interface is requested multiple times
|
|
58
|
-
2. Different contexts produce different instances of the same registration
|
|
59
|
-
The test creates two separate contexts and confirms that instances obtained
|
|
60
|
-
within a single context are identical, but instances from different contexts
|
|
61
|
-
are distinct.
|
|
62
|
-
"""
|
|
63
90
|
|
|
91
|
+
This method verifies:
|
|
92
|
+
- Within a single context, scoped registrations return the same instance when the same interface is requested multiple times.
|
|
93
|
+
- Different contexts produce different instances of the same registration.
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
96
|
+
----------
|
|
97
|
+
self : TestContainer
|
|
98
|
+
The test case instance.
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
None
|
|
103
|
+
This method does not return any value. Assertions are used to validate expected behavior.
|
|
104
|
+
|
|
105
|
+
Notes
|
|
106
|
+
-----
|
|
107
|
+
The registration for `ICar` is dropped after the test.
|
|
108
|
+
"""
|
|
64
109
|
container = Container()
|
|
110
|
+
# First context: instances should be the same
|
|
65
111
|
with container.createContext():
|
|
66
112
|
container.scoped(ICar, Car)
|
|
67
113
|
instance1 = container.make(ICar)
|
|
@@ -71,43 +117,70 @@ class TestContainer(AsyncTestCase):
|
|
|
71
117
|
self.assertIsInstance(instance2, Car)
|
|
72
118
|
self.assertIs(instance1, instance2)
|
|
73
119
|
|
|
120
|
+
# Second context: instance should be different from previous context
|
|
74
121
|
with container.createContext():
|
|
75
122
|
container.scoped(ICar, Car)
|
|
76
123
|
instance3 = container.make(ICar)
|
|
77
124
|
self.assertIsNot(instance1, instance3)
|
|
78
125
|
|
|
126
|
+
# Clean up registration
|
|
79
127
|
container.drop(abstract=ICar)
|
|
80
128
|
|
|
81
129
|
async def testInstanceRegistration(self) -> None:
|
|
82
130
|
"""
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
131
|
+
Tests instance registration in the container.
|
|
132
|
+
|
|
133
|
+
This method ensures:
|
|
134
|
+
- When an instance is registered to a service in the container, the container returns exactly the same instance when resolving that service.
|
|
135
|
+
|
|
136
|
+
Parameters
|
|
137
|
+
----------
|
|
138
|
+
self : TestContainer
|
|
139
|
+
The test case instance.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
None
|
|
144
|
+
This method does not return any value. Assertions are used to validate expected behavior.
|
|
145
|
+
|
|
146
|
+
Notes
|
|
147
|
+
-----
|
|
148
|
+
The registration for `ICar` is dropped after the test.
|
|
91
149
|
"""
|
|
92
150
|
car_instance = Car()
|
|
93
151
|
container = Container()
|
|
152
|
+
# Register a specific instance of Car to ICar
|
|
94
153
|
container.instance(ICar, car_instance)
|
|
154
|
+
# Resolve ICar and check that it returns the same instance
|
|
95
155
|
resolved = container.make(ICar)
|
|
96
156
|
|
|
97
157
|
self.assertIs(resolved, car_instance)
|
|
98
158
|
|
|
159
|
+
# Clean up registration
|
|
99
160
|
container.drop(abstract=ICar)
|
|
100
161
|
|
|
101
162
|
async def testCallableRegistration(self) -> None:
|
|
102
163
|
"""
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
164
|
+
Tests that callables can be registered and resolved from the container.
|
|
165
|
+
|
|
166
|
+
This method verifies:
|
|
167
|
+
- Functions can be registered in the container using the `callable()` method.
|
|
168
|
+
- Registered functions can be resolved and executed using the `make()` method.
|
|
169
|
+
- Arguments can be passed to the resolved functions as positional and keyword arguments.
|
|
170
|
+
|
|
171
|
+
Parameters
|
|
172
|
+
----------
|
|
173
|
+
self : TestContainer
|
|
174
|
+
The test case instance.
|
|
175
|
+
|
|
176
|
+
Returns
|
|
177
|
+
-------
|
|
178
|
+
None
|
|
179
|
+
This method does not return any value. Assertions are used to validate expected behavior.
|
|
180
|
+
|
|
181
|
+
Notes
|
|
182
|
+
-----
|
|
183
|
+
The registrations for 'add' and 'multiply' are dropped after the test.
|
|
111
184
|
"""
|
|
112
185
|
def add(a: int, b: int) -> int:
|
|
113
186
|
return a + b
|
|
@@ -116,28 +189,44 @@ class TestContainer(AsyncTestCase):
|
|
|
116
189
|
return a * b
|
|
117
190
|
|
|
118
191
|
container = Container()
|
|
192
|
+
# Register callables
|
|
119
193
|
container.callable('add', add)
|
|
120
194
|
container.callable('multiply', multiply)
|
|
121
195
|
|
|
196
|
+
# Test resolution and execution with positional and keyword arguments
|
|
122
197
|
self.assertEqual(container.make('add', 1, 2), 3)
|
|
123
198
|
self.assertEqual(container.make('multiply', 3, 4), 12)
|
|
124
199
|
self.assertEqual(container.make('add', a=5, b=7), 12)
|
|
125
200
|
|
|
201
|
+
# Clean up registrations
|
|
126
202
|
container.drop(alias='add')
|
|
127
203
|
container.drop(alias='multiply')
|
|
128
204
|
|
|
129
205
|
async def testTransientFacade(self) -> None:
|
|
130
206
|
"""
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
207
|
+
Tests transient instance resolution using the Facade pattern.
|
|
208
|
+
|
|
209
|
+
This method validates:
|
|
210
|
+
- The container can register a transient binding between an interface and a class.
|
|
211
|
+
- The Facade pattern correctly resolves instances of the registered interface.
|
|
212
|
+
- Multiple calls to the Facade's `resolve()` method return different instances, confirming transient behavior.
|
|
213
|
+
|
|
214
|
+
Parameters
|
|
215
|
+
----------
|
|
216
|
+
self : TestContainer
|
|
217
|
+
The test case instance.
|
|
218
|
+
|
|
219
|
+
Returns
|
|
220
|
+
-------
|
|
221
|
+
None
|
|
222
|
+
This method does not return any value. Assertions are used to validate expected behavior.
|
|
223
|
+
|
|
224
|
+
Notes
|
|
225
|
+
-----
|
|
226
|
+
The registration for `ICar` is dropped after the test.
|
|
139
227
|
"""
|
|
140
228
|
container = Application()
|
|
229
|
+
# Register ICar as a transient binding to Car
|
|
141
230
|
container.transient(ICar, Car)
|
|
142
231
|
|
|
143
232
|
class CarFacade(Facade):
|
|
@@ -145,6 +234,7 @@ class TestContainer(AsyncTestCase):
|
|
|
145
234
|
def getFacadeAccessor(cls):
|
|
146
235
|
return ICar
|
|
147
236
|
|
|
237
|
+
# Resolve two instances via Facade (should be different objects)
|
|
148
238
|
instance1 = CarFacade.resolve()
|
|
149
239
|
instance2 = CarFacade.resolve()
|
|
150
240
|
|
|
@@ -152,20 +242,35 @@ class TestContainer(AsyncTestCase):
|
|
|
152
242
|
self.assertIsInstance(instance2, Car)
|
|
153
243
|
self.assertIsNot(instance1, instance2)
|
|
154
244
|
|
|
245
|
+
# Clean up registration
|
|
155
246
|
container.drop(abstract=ICar)
|
|
156
247
|
|
|
157
248
|
async def testSingletonFacade(self) -> None:
|
|
158
249
|
"""
|
|
159
|
-
Tests
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
250
|
+
Tests singleton instance resolution using the Facade pattern.
|
|
251
|
+
|
|
252
|
+
This method verifies:
|
|
253
|
+
- A singleton binding can be registered in the container.
|
|
254
|
+
- A Facade class can be created to access this binding.
|
|
255
|
+
- Multiple resolutions through the Facade return the same instance, confirming singleton behavior.
|
|
256
|
+
- The resolved instances are of the correct type (`Car`).
|
|
257
|
+
|
|
258
|
+
Parameters
|
|
259
|
+
----------
|
|
260
|
+
self : TestContainer
|
|
261
|
+
The test case instance.
|
|
262
|
+
|
|
263
|
+
Returns
|
|
264
|
+
-------
|
|
265
|
+
None
|
|
266
|
+
This method does not return any value. Assertions are used to validate expected behavior.
|
|
267
|
+
|
|
268
|
+
Notes
|
|
269
|
+
-----
|
|
270
|
+
The registration for `ICar` is dropped after the test.
|
|
167
271
|
"""
|
|
168
272
|
container = Application()
|
|
273
|
+
# Register ICar as a singleton binding to Car
|
|
169
274
|
container.singleton(ICar, Car)
|
|
170
275
|
|
|
171
276
|
class CarFacade(Facade):
|
|
@@ -173,6 +278,7 @@ class TestContainer(AsyncTestCase):
|
|
|
173
278
|
def getFacadeAccessor(cls):
|
|
174
279
|
return ICar
|
|
175
280
|
|
|
281
|
+
# Resolve two instances via Facade (should be the same object)
|
|
176
282
|
instance1 = CarFacade.resolve()
|
|
177
283
|
instance2 = CarFacade.resolve()
|
|
178
284
|
|
|
@@ -180,22 +286,36 @@ class TestContainer(AsyncTestCase):
|
|
|
180
286
|
self.assertIsInstance(instance2, Car)
|
|
181
287
|
self.assertIs(instance1, instance2)
|
|
182
288
|
|
|
289
|
+
# Clean up registration
|
|
183
290
|
container.drop(abstract=ICar)
|
|
184
291
|
|
|
185
292
|
async def testScopedFacade(self) -> None:
|
|
186
293
|
"""
|
|
187
294
|
Tests the functionality of a Facade accessing a scoped service within a container context.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
295
|
+
|
|
296
|
+
This method verifies:
|
|
297
|
+
- The Facade can properly resolve a scoped service.
|
|
298
|
+
- Multiple resolves within the same scope return the same instance, confirming scoped behavior.
|
|
299
|
+
- The resolved instance is of the correct type (`Car`).
|
|
300
|
+
|
|
301
|
+
Parameters
|
|
302
|
+
----------
|
|
303
|
+
self : TestContainer
|
|
304
|
+
The test case instance.
|
|
305
|
+
|
|
306
|
+
Returns
|
|
307
|
+
-------
|
|
308
|
+
None
|
|
309
|
+
This method does not return any value. Assertions are used to validate expected behavior.
|
|
310
|
+
|
|
311
|
+
Notes
|
|
312
|
+
-----
|
|
313
|
+
The registration for `ICar` is dropped after the test.
|
|
196
314
|
"""
|
|
197
315
|
container = Application()
|
|
316
|
+
# Create a new scope/context
|
|
198
317
|
with container.createContext():
|
|
318
|
+
# Register ICar as a scoped binding to Car
|
|
199
319
|
container.scoped(ICar, Car)
|
|
200
320
|
|
|
201
321
|
class CarFacade(Facade):
|
|
@@ -203,6 +323,7 @@ class TestContainer(AsyncTestCase):
|
|
|
203
323
|
def getFacadeAccessor(cls):
|
|
204
324
|
return ICar
|
|
205
325
|
|
|
326
|
+
# Resolve two instances via Facade (should be the same object within the scope)
|
|
206
327
|
instance1 = CarFacade.resolve()
|
|
207
328
|
instance2 = CarFacade.resolve()
|
|
208
329
|
|
|
@@ -210,29 +331,60 @@ class TestContainer(AsyncTestCase):
|
|
|
210
331
|
self.assertIsInstance(instance2, Car)
|
|
211
332
|
self.assertIs(instance1, instance2)
|
|
212
333
|
|
|
334
|
+
# Clean up registration
|
|
213
335
|
container.drop(abstract=ICar)
|
|
214
336
|
|
|
215
337
|
async def testResolvingUnregisteredType(self) -> None:
|
|
216
338
|
"""
|
|
217
339
|
Tests that attempting to resolve an unregistered type from the container raises an exception.
|
|
218
|
-
This test ensures that the container correctly validates that a type is registered before attempting to resolve it.
|
|
219
340
|
|
|
220
|
-
|
|
221
|
-
|
|
341
|
+
This method ensures:
|
|
342
|
+
- The container correctly validates that a type is registered before attempting to resolve it.
|
|
343
|
+
- An exception is raised when attempting to resolve an unregistered type.
|
|
344
|
+
|
|
345
|
+
Parameters
|
|
346
|
+
----------
|
|
347
|
+
self : TestContainer
|
|
348
|
+
The test case instance.
|
|
349
|
+
|
|
350
|
+
Returns
|
|
351
|
+
-------
|
|
352
|
+
None
|
|
353
|
+
This method does not return any value. Assertions are used to validate expected behavior.
|
|
354
|
+
|
|
355
|
+
Raises
|
|
356
|
+
------
|
|
357
|
+
Exception
|
|
358
|
+
Raised when attempting to resolve an unregistered type.
|
|
222
359
|
"""
|
|
223
360
|
container = Container()
|
|
361
|
+
# Attempt to resolve an unregistered type; should raise Exception
|
|
224
362
|
with self.assertRaises(Exception):
|
|
225
363
|
container.make('ICar')
|
|
226
364
|
|
|
227
365
|
async def testOverridingRegistration(self) -> None:
|
|
228
366
|
"""
|
|
229
367
|
Tests the ability of the container to override existing registrations.
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
368
|
+
|
|
369
|
+
This method verifies:
|
|
370
|
+
- When a class is registered as a singleton for an interface.
|
|
371
|
+
- A different class can later be registered for the same interface.
|
|
372
|
+
- The container returns the new class when resolving the interface.
|
|
373
|
+
- The new instance is different from the previous instance, confirming the override.
|
|
374
|
+
|
|
375
|
+
Parameters
|
|
376
|
+
----------
|
|
377
|
+
self : TestContainer
|
|
378
|
+
The test case instance.
|
|
379
|
+
|
|
380
|
+
Returns
|
|
381
|
+
-------
|
|
382
|
+
None
|
|
383
|
+
This method does not return any value. Assertions are used to validate expected behavior.
|
|
384
|
+
|
|
385
|
+
Notes
|
|
386
|
+
-----
|
|
387
|
+
The registration for `ICar` is dropped after the test.
|
|
236
388
|
"""
|
|
237
389
|
class SportsCar(Car):
|
|
238
390
|
def start(self):
|
|
@@ -241,14 +393,17 @@ class TestContainer(AsyncTestCase):
|
|
|
241
393
|
return f"{self.brand} {self.model} is stopping."
|
|
242
394
|
|
|
243
395
|
container = Container()
|
|
396
|
+
# Register ICar as a singleton binding to Car
|
|
244
397
|
container.singleton(ICar, Car)
|
|
245
398
|
first = container.make(ICar)
|
|
246
399
|
self.assertIsInstance(first, Car)
|
|
247
400
|
self.assertNotIsInstance(first, SportsCar)
|
|
248
401
|
|
|
402
|
+
# Override registration: register ICar as a singleton binding to SportsCar
|
|
249
403
|
container.singleton(ICar, SportsCar)
|
|
250
404
|
second = container.make(ICar)
|
|
251
405
|
self.assertIsInstance(second, SportsCar)
|
|
252
406
|
self.assertIsNot(first, second)
|
|
253
407
|
|
|
408
|
+
# Clean up registration
|
|
254
409
|
container.drop(abstract=ICar)
|