orionis 0.546.0__py3-none-any.whl → 0.547.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 (160) hide show
  1. orionis/console/base/scheduler_event_listener.py +0 -17
  2. orionis/console/contracts/schedule_event_listener.py +0 -18
  3. orionis/foundation/config/app/entities/app.py +3 -2
  4. orionis/foundation/config/app/enums/ciphers.py +5 -19
  5. orionis/foundation/config/session/entities/session.py +2 -2
  6. orionis/metadata/framework.py +1 -1
  7. orionis/services/encrypter/encrypter.py +115 -0
  8. orionis/services/environment/dynamic/caster.py +35 -27
  9. orionis/services/environment/key/key_generator.py +32 -11
  10. {orionis-0.546.0.dist-info → orionis-0.547.0.dist-info}/METADATA +1 -1
  11. {orionis-0.546.0.dist-info → orionis-0.547.0.dist-info}/RECORD +15 -159
  12. {orionis-0.546.0.dist-info → orionis-0.547.0.dist-info}/top_level.txt +0 -1
  13. tests/container/__init__.py +0 -0
  14. tests/container/context/__init__.py +0 -0
  15. tests/container/context/test_manager.py +0 -38
  16. tests/container/context/test_scope.py +0 -32
  17. tests/container/core/__init__.py +0 -0
  18. tests/container/core/test_advanced_async.py +0 -234
  19. tests/container/core/test_async_optimizations.py +0 -268
  20. tests/container/core/test_container.py +0 -453
  21. tests/container/core/test_singleton.py +0 -122
  22. tests/container/core/test_thread_safety.py +0 -90
  23. tests/container/entities/__init__.py +0 -0
  24. tests/container/entities/test_binding.py +0 -242
  25. tests/container/enums/__init__.py +0 -0
  26. tests/container/enums/test_lifetimes.py +0 -97
  27. tests/container/facades/__init__.py +0 -0
  28. tests/container/facades/test_facade.py +0 -78
  29. tests/container/mocks/__init__.py +0 -0
  30. tests/container/mocks/mock_advanced_async.py +0 -332
  31. tests/container/mocks/mock_async_optimizations.py +0 -407
  32. tests/container/mocks/mock_auto_resolution.py +0 -192
  33. tests/container/mocks/mock_complex_classes.py +0 -792
  34. tests/container/mocks/mock_simple_classes.py +0 -98
  35. tests/container/providers/__init__.py +0 -0
  36. tests/container/providers/test_providers.py +0 -55
  37. tests/container/validators/__init__.py +0 -0
  38. tests/container/validators/test_implements.py +0 -186
  39. tests/container/validators/test_is_abstract_class.py +0 -147
  40. tests/container/validators/test_is_callable.py +0 -102
  41. tests/container/validators/test_is_concrete_class.py +0 -160
  42. tests/container/validators/test_is_instance.py +0 -150
  43. tests/container/validators/test_is_not_subclass.py +0 -49
  44. tests/container/validators/test_is_subclass.py +0 -178
  45. tests/container/validators/test_is_valid_alias.py +0 -147
  46. tests/container/validators/test_lifetime.py +0 -106
  47. tests/example/__init__.py +0 -0
  48. tests/example/test_example.py +0 -725
  49. tests/foundation/__init__.py +0 -0
  50. tests/foundation/config/__init__.py +0 -0
  51. tests/foundation/config/app/__init__.py +0 -0
  52. tests/foundation/config/app/test_foundation_config_app.py +0 -262
  53. tests/foundation/config/auth/__init__.py +0 -0
  54. tests/foundation/config/auth/test_foundation_config_auth.py +0 -29
  55. tests/foundation/config/cache/__init__.py +0 -0
  56. tests/foundation/config/cache/test_foundation_config_cache.py +0 -143
  57. tests/foundation/config/cache/test_foundation_config_cache_file.py +0 -126
  58. tests/foundation/config/cache/test_foundation_config_cache_stores.py +0 -156
  59. tests/foundation/config/cors/__init__.py +0 -0
  60. tests/foundation/config/cors/test_foundation_config_cors.py +0 -190
  61. tests/foundation/config/database/__init__.py +0 -0
  62. tests/foundation/config/database/test_foundation_config_database.py +0 -158
  63. tests/foundation/config/database/test_foundation_config_database_connections.py +0 -203
  64. tests/foundation/config/database/test_foundation_config_database_mysql.py +0 -354
  65. tests/foundation/config/database/test_foundation_config_database_oracle.py +0 -288
  66. tests/foundation/config/database/test_foundation_config_database_pgsql.py +0 -257
  67. tests/foundation/config/database/test_foundation_config_database_sqlite.py +0 -207
  68. tests/foundation/config/filesystems/__init__.py +0 -0
  69. tests/foundation/config/filesystems/test_foundation_config_filesystems.py +0 -160
  70. tests/foundation/config/filesystems/test_foundation_config_filesystems_aws.py +0 -189
  71. tests/foundation/config/filesystems/test_foundation_config_filesystems_disks.py +0 -184
  72. tests/foundation/config/filesystems/test_foundation_config_filesystems_local.py +0 -143
  73. tests/foundation/config/filesystems/test_foundation_config_filesystems_public.py +0 -184
  74. tests/foundation/config/logging/__init__.py +0 -0
  75. tests/foundation/config/logging/test_foundation_config_logging.py +0 -112
  76. tests/foundation/config/logging/test_foundation_config_logging_channels.py +0 -246
  77. tests/foundation/config/logging/test_foundation_config_logging_chunked.py +0 -217
  78. tests/foundation/config/logging/test_foundation_config_logging_daily.py +0 -220
  79. tests/foundation/config/logging/test_foundation_config_logging_hourly.py +0 -196
  80. tests/foundation/config/logging/test_foundation_config_logging_monthly.py +0 -214
  81. tests/foundation/config/logging/test_foundation_config_logging_stack.py +0 -178
  82. tests/foundation/config/logging/test_foundation_config_logging_weekly.py +0 -224
  83. tests/foundation/config/mail/__init__.py +0 -0
  84. tests/foundation/config/mail/test_foundation_config_mail.py +0 -145
  85. tests/foundation/config/mail/test_foundation_config_mail_file.py +0 -97
  86. tests/foundation/config/mail/test_foundation_config_mail_mailers.py +0 -106
  87. tests/foundation/config/mail/test_foundation_config_mail_smtp.py +0 -146
  88. tests/foundation/config/queue/__init__.py +0 -0
  89. tests/foundation/config/queue/test_foundation_config_queue.py +0 -88
  90. tests/foundation/config/queue/test_foundation_config_queue_brokers.py +0 -72
  91. tests/foundation/config/queue/test_foundation_config_queue_database.py +0 -134
  92. tests/foundation/config/root/__init__.py +0 -0
  93. tests/foundation/config/root/test_foundation_config_root_paths.py +0 -112
  94. tests/foundation/config/session/__init__.py +0 -0
  95. tests/foundation/config/session/test_foundation_config_session.py +0 -213
  96. tests/foundation/config/startup/__init__.py +0 -0
  97. tests/foundation/config/startup/test_foundation_config_startup.py +0 -202
  98. tests/foundation/config/testing/__init__.py +0 -0
  99. tests/foundation/config/testing/test_foundation_config_testing.py +0 -235
  100. tests/metadata/__init__.py +0 -0
  101. tests/metadata/test_metadata_framework.py +0 -140
  102. tests/metadata/test_metadata_package.py +0 -139
  103. tests/services/__init__.py +0 -0
  104. tests/services/asynchrony/__init__.py +0 -0
  105. tests/services/asynchrony/test_services_asynchrony_coroutine.py +0 -85
  106. tests/services/environment/__init__.py +0 -0
  107. tests/services/environment/test_services_environment.py +0 -226
  108. tests/services/introspection/__init__.py +0 -0
  109. tests/services/introspection/dependencies/__init__.py +0 -0
  110. tests/services/introspection/dependencies/mocks/__init__.py +0 -0
  111. tests/services/introspection/dependencies/mocks/mock_user.py +0 -30
  112. tests/services/introspection/dependencies/mocks/mock_user_controller.py +0 -27
  113. tests/services/introspection/dependencies/mocks/mock_users_permissions.py +0 -41
  114. tests/services/introspection/dependencies/test_reflect_dependencies.py +0 -261
  115. tests/services/introspection/reflection/__init__.py +0 -0
  116. tests/services/introspection/reflection/mock/__init__.py +0 -0
  117. tests/services/introspection/reflection/mock/fake_reflect_instance.py +0 -1115
  118. tests/services/introspection/reflection/test_reflection_abstract.py +0 -1011
  119. tests/services/introspection/reflection/test_reflection_callable.py +0 -206
  120. tests/services/introspection/reflection/test_reflection_concrete.py +0 -952
  121. tests/services/introspection/reflection/test_reflection_instance.py +0 -1233
  122. tests/services/introspection/reflection/test_reflection_module.py +0 -567
  123. tests/services/introspection/test_reflection.py +0 -462
  124. tests/services/log/__init__.py +0 -0
  125. tests/services/log/test_log.py +0 -97
  126. tests/services/system/__init__.py +0 -0
  127. tests/services/system/test_services_system_imports.py +0 -204
  128. tests/services/system/test_services_system_workers.py +0 -131
  129. tests/support/__init__.py +0 -0
  130. tests/support/entities/__init__.py +0 -0
  131. tests/support/entities/mock_dataclass.py +0 -40
  132. tests/support/entities/test_base.py +0 -64
  133. tests/support/patterns/__init__.py +0 -0
  134. tests/support/patterns/singleton/__init__.py +0 -0
  135. tests/support/patterns/singleton/test_patterns_singleton.py +0 -39
  136. tests/support/standard/__init__.py +0 -0
  137. tests/support/standard/test_services_std.py +0 -226
  138. tests/support/wrapper/__init__.py +0 -0
  139. tests/support/wrapper/test_services_wrapper_docdict.py +0 -202
  140. tests/testing/__init__.py +0 -0
  141. tests/testing/cases/__init__.py +0 -0
  142. tests/testing/cases/test_testing_asynchronous.py +0 -63
  143. tests/testing/cases/test_testing_synchronous.py +0 -57
  144. tests/testing/entities/__init__.py +0 -0
  145. tests/testing/entities/test_testing_result.py +0 -146
  146. tests/testing/enums/__init__.py +0 -0
  147. tests/testing/enums/test_testing_status.py +0 -63
  148. tests/testing/output/__init__.py +0 -0
  149. tests/testing/output/test_testing_dumper.py +0 -29
  150. tests/testing/output/test_testing_printer.py +0 -42
  151. tests/testing/records/__init__.py +0 -0
  152. tests/testing/records/test_testing_records.py +0 -171
  153. tests/testing/test_testing_unit.py +0 -164
  154. tests/testing/validators/__init__.py +0 -0
  155. tests/testing/validators/test_testing_validators.py +0 -392
  156. tests/testing/view/__init__.py +0 -0
  157. tests/testing/view/test_render.py +0 -30
  158. {orionis-0.546.0.dist-info → orionis-0.547.0.dist-info}/WHEEL +0 -0
  159. {orionis-0.546.0.dist-info → orionis-0.547.0.dist-info}/licenses/LICENCE +0 -0
  160. {orionis-0.546.0.dist-info → orionis-0.547.0.dist-info}/zip-safe +0 -0
@@ -1,453 +0,0 @@
1
- from orionis.container.container import Container
2
- from orionis.container.facades.facade import Facade
3
- from orionis.foundation.application import Application
4
- from orionis.test.cases.asynchronous import AsyncTestCase
5
- from tests.container.mocks.mock_simple_classes import Car, ICar
6
-
7
- class TestContainer(AsyncTestCase):
8
-
9
- async def testTransientRegistration(self) -> None:
10
- """
11
- Tests the transient registration of a service in the container.
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.
31
- """
32
-
33
- # Create a new container instance
34
- container = Container()
35
-
36
- # Register ICar as a transient binding to Car
37
- container.transient(ICar, Car)
38
-
39
- # Resolve two instances of ICar (should be different objects)
40
- instance1 = container.make(ICar)
41
- instance2 = container.make(ICar)
42
-
43
- # Assert both instances are of type Car
44
- self.assertIsInstance(instance1, Car)
45
- self.assertIsInstance(instance2, Car)
46
-
47
- # Assert that the instances are not the same object (transient behavior)
48
- self.assertIsNot(instance1, instance2)
49
-
50
- # Clean up registration
51
- container.drop(abstract=ICar)
52
-
53
- async def testSingletonRegistration(self) -> None:
54
- """
55
- Tests singleton registration and resolution from the container.
56
-
57
- This method ensures:
58
- - A class (`Car`) can be registered as a singleton implementation of an interface (`ICar`).
59
- - The container returns an instance of the registered implementation.
60
- - Multiple requests for the same interface return the same instance, confirming singleton behavior.
61
-
62
- Parameters
63
- ----------
64
- self : TestContainer
65
- The test case instance.
66
-
67
- Returns
68
- -------
69
- None
70
- This method does not return any value. Assertions are used to validate expected behavior.
71
-
72
- Notes
73
- -----
74
- The registration for `ICar` is dropped after the test.
75
- """
76
-
77
- # Create a new container instance
78
- container = Container()
79
-
80
- # Register ICar as a singleton binding to Car
81
- container.singleton(ICar, Car)
82
-
83
- # Resolve two instances of ICar (should be the same object)
84
- instance1 = container.make(ICar)
85
- instance2 = container.make(ICar)
86
-
87
- # Assert both instances are of type Car
88
- self.assertIsInstance(instance1, Car)
89
- self.assertIsInstance(instance2, Car)
90
-
91
- # Assert that both instances are the same object (singleton behavior)
92
- self.assertIs(instance1, instance2)
93
-
94
- # Clean up registration
95
- container.drop(abstract=ICar)
96
-
97
- async def testScopedRegistration(self) -> None:
98
- """
99
- Tests the scoped registration functionality of the container.
100
-
101
- This method verifies:
102
- - Within a single context, scoped registrations return the same instance when the same interface is requested multiple times.
103
- - Different contexts produce different instances of the same registration.
104
-
105
- Parameters
106
- ----------
107
- self : TestContainer
108
- The test case instance.
109
-
110
- Returns
111
- -------
112
- None
113
- This method does not return any value. Assertions are used to validate expected behavior.
114
-
115
- Notes
116
- -----
117
- The registration for `ICar` is dropped after the test.
118
- """
119
-
120
- # Create a new container instance
121
- container = Container()
122
-
123
- # First context: instances should be the same
124
- with container.createContext():
125
- container.scoped(ICar, Car)
126
- instance1 = container.make(ICar)
127
- instance2 = container.make(ICar)
128
-
129
- self.assertIsInstance(instance1, Car)
130
- self.assertIsInstance(instance2, Car)
131
- self.assertIs(instance1, instance2)
132
-
133
- # Second context: instance should be different from previous context
134
- with container.createContext():
135
- container.scoped(ICar, Car)
136
- instance3 = container.make(ICar)
137
- self.assertIsNot(instance1, instance3)
138
-
139
- # Clean up registration
140
- container.drop(abstract=ICar)
141
-
142
- async def testInstanceRegistration(self) -> None:
143
- """
144
- Tests instance registration in the container.
145
-
146
- This method ensures:
147
- - When an instance is registered to a service in the container, the container returns exactly the same instance when resolving that service.
148
-
149
- Parameters
150
- ----------
151
- self : TestContainer
152
- The test case instance.
153
-
154
- Returns
155
- -------
156
- None
157
- This method does not return any value. Assertions are used to validate expected behavior.
158
-
159
- Notes
160
- -----
161
- The registration for `ICar` is dropped after the test.
162
- """
163
-
164
- # Create a specific instance of Car
165
- car_instance = Car()
166
- container = Container()
167
-
168
- # Register a specific instance of Car to ICar
169
- container.instance(ICar, car_instance)
170
-
171
- # Resolve ICar and check that it returns the same instance
172
- resolved = container.make(ICar)
173
- self.assertIs(resolved, car_instance)
174
-
175
- # Clean up registration
176
- container.drop(abstract=ICar)
177
-
178
- async def testCallableRegistration(self) -> None:
179
- """
180
- Tests that callables can be registered and resolved from the container.
181
-
182
- This method verifies:
183
- - Functions can be registered in the container using the `callable()` method.
184
- - Registered functions can be resolved and executed using the `make()` method.
185
- - Arguments can be passed to the resolved functions as positional and keyword arguments.
186
-
187
- Parameters
188
- ----------
189
- self : TestContainer
190
- The test case instance.
191
-
192
- Returns
193
- -------
194
- None
195
- This method does not return any value. Assertions are used to validate expected behavior.
196
-
197
- Notes
198
- -----
199
- The registrations for 'add' and 'multiply' are dropped after the test.
200
- """
201
-
202
- # Define some simple functions to register
203
- def add(a: int, b: int) -> int:
204
- return a + b
205
-
206
-
207
- # Define another function to register
208
- def multiply(a: int, b: int) -> int:
209
- return a * b
210
-
211
- # Create a new container instance
212
- container = Container()
213
-
214
- # Register callables
215
- container.callable('add', add)
216
- container.callable('multiply', multiply)
217
-
218
- # Test resolution and execution with positional and keyword arguments
219
- self.assertEqual(container.make('add', 1, 2), 3)
220
- self.assertEqual(container.make('multiply', 3, 4), 12)
221
- self.assertEqual(container.make('add', a=5, b=7), 12)
222
-
223
- # Clean up registrations
224
- container.drop(alias='add')
225
- container.drop(alias='multiply')
226
-
227
- async def testTransientFacade(self) -> None:
228
- """
229
- Tests transient instance resolution using the Facade pattern.
230
-
231
- This method validates:
232
- - The container can register a transient binding between an interface and a class.
233
- - The Facade pattern correctly resolves instances of the registered interface.
234
- - Multiple calls to the Facade's `resolve()` method return different instances, confirming transient behavior.
235
-
236
- Parameters
237
- ----------
238
- self : TestContainer
239
- The test case instance.
240
-
241
- Returns
242
- -------
243
- None
244
- This method does not return any value. Assertions are used to validate expected behavior.
245
-
246
- Notes
247
- -----
248
- The registration for `ICar` is dropped after the test.
249
- """
250
-
251
- # Create a new container instance
252
- container = Application()
253
-
254
- # Register ICar as a transient binding to Car
255
- container.transient(ICar, Car)
256
-
257
- # Define a Facade class to access the ICar binding
258
- class CarFacade(Facade):
259
- @classmethod
260
- def getFacadeAccessor(cls):
261
- return ICar
262
-
263
- # Resolve two instances via Facade (should be different objects)
264
- instance1 = CarFacade.resolve()
265
- instance2 = CarFacade.resolve()
266
-
267
- self.assertIsInstance(instance1, Car)
268
- self.assertIsInstance(instance2, Car)
269
- self.assertIsNot(instance1, instance2)
270
-
271
- # Clean up registration
272
- container.drop(abstract=ICar)
273
-
274
- async def testSingletonFacade(self) -> None:
275
- """
276
- Tests singleton instance resolution using the Facade pattern.
277
-
278
- This method verifies:
279
- - A singleton binding can be registered in the container.
280
- - A Facade class can be created to access this binding.
281
- - Multiple resolutions through the Facade return the same instance, confirming singleton behavior.
282
- - The resolved instances are of the correct type (`Car`).
283
-
284
- Parameters
285
- ----------
286
- self : TestContainer
287
- The test case instance.
288
-
289
- Returns
290
- -------
291
- None
292
- This method does not return any value. Assertions are used to validate expected behavior.
293
-
294
- Notes
295
- -----
296
- The registration for `ICar` is dropped after the test.
297
- """
298
-
299
- # Create a new container instance
300
- container = Application()
301
-
302
- # Register ICar as a singleton binding to Car
303
- container.singleton(ICar, Car)
304
-
305
- # Define a Facade class to access the ICar binding
306
- class CarFacade(Facade):
307
- @classmethod
308
- def getFacadeAccessor(cls):
309
- return ICar
310
-
311
- # Resolve two instances via Facade (should be the same object)
312
- instance1 = CarFacade.resolve()
313
- instance2 = CarFacade.resolve()
314
-
315
- # Assert both instances are of type Car and are the same object
316
- self.assertIsInstance(instance1, Car)
317
- self.assertIsInstance(instance2, Car)
318
- self.assertIs(instance1, instance2)
319
-
320
- # Clean up registration
321
- container.drop(abstract=ICar)
322
-
323
- async def testScopedFacade(self) -> None:
324
- """
325
- Tests the functionality of a Facade accessing a scoped service within a container context.
326
-
327
- This method verifies:
328
- - The Facade can properly resolve a scoped service.
329
- - Multiple resolves within the same scope return the same instance, confirming scoped behavior.
330
- - The resolved instance is of the correct type (`Car`).
331
-
332
- Parameters
333
- ----------
334
- self : TestContainer
335
- The test case instance.
336
-
337
- Returns
338
- -------
339
- None
340
- This method does not return any value. Assertions are used to validate expected behavior.
341
-
342
- Notes
343
- -----
344
- The registration for `ICar` is dropped after the test.
345
- """
346
-
347
- # Create a new container instance
348
- container = Application()
349
-
350
- # Create a new scope/context
351
- with container.createContext():
352
-
353
- # Register ICar as a scoped binding to Car
354
- container.scoped(ICar, Car)
355
-
356
- # Define a Facade class to access the ICar binding
357
- class CarFacade(Facade):
358
- @classmethod
359
- def getFacadeAccessor(cls):
360
- return ICar
361
-
362
- # Resolve two instances via Facade (should be the same object within the scope)
363
- instance1 = CarFacade.resolve()
364
- instance2 = CarFacade.resolve()
365
-
366
- # Assert both instances are of type Car and are the same object
367
- self.assertIsInstance(instance1, Car)
368
- self.assertIsInstance(instance2, Car)
369
- self.assertIs(instance1, instance2)
370
-
371
- # Clean up registration
372
- container.drop(abstract=ICar)
373
-
374
- async def testResolvingUnregisteredType(self) -> None:
375
- """
376
- Tests that attempting to resolve an unregistered type from the container raises an exception.
377
-
378
- This method ensures:
379
- - The container correctly validates that a type is registered before attempting to resolve it.
380
- - An exception is raised when attempting to resolve an unregistered type.
381
-
382
- Parameters
383
- ----------
384
- self : TestContainer
385
- The test case instance.
386
-
387
- Returns
388
- -------
389
- None
390
- This method does not return any value. Assertions are used to validate expected behavior.
391
-
392
- Raises
393
- ------
394
- Exception
395
- Raised when attempting to resolve an unregistered type.
396
- """
397
-
398
- # Create a new container instance
399
- container = Container()
400
-
401
- # Attempt to resolve an unregistered type; should raise Exception
402
- with self.assertRaises(Exception):
403
- container.make('ICar')
404
-
405
- async def testOverridingRegistration(self) -> None:
406
- """
407
- Tests the ability of the container to override existing registrations.
408
-
409
- This method verifies:
410
- - When a class is registered as a singleton for an interface.
411
- - A different class can later be registered for the same interface.
412
- - The container returns the new class when resolving the interface.
413
- - The new instance is different from the previous instance, confirming the override.
414
-
415
- Parameters
416
- ----------
417
- self : TestContainer
418
- The test case instance.
419
-
420
- Returns
421
- -------
422
- None
423
- This method does not return any value. Assertions are used to validate expected behavior.
424
-
425
- Notes
426
- -----
427
- The registration for `ICar` is dropped after the test.
428
- """
429
-
430
- # Create a new container instance
431
- class SportsCar(Car):
432
- def start(self):
433
- return f"{self.brand} {self.model} is starting."
434
- def stop(self):
435
- return f"{self.brand} {self.model} is stopping."
436
-
437
- # Create a new container instance
438
- container = Container()
439
-
440
- # Register ICar as a singleton binding to Car
441
- container.singleton(ICar, Car)
442
- first = container.make(ICar)
443
- self.assertIsInstance(first, Car)
444
- self.assertNotIsInstance(first, SportsCar)
445
-
446
- # Override registration: register ICar as a singleton binding to SportsCar
447
- container.singleton(ICar, SportsCar)
448
- second = container.make(ICar)
449
- self.assertIsInstance(second, SportsCar)
450
- self.assertIsNot(first, second)
451
-
452
- # Clean up registration
453
- container.drop(abstract=ICar)
@@ -1,122 +0,0 @@
1
- import threading
2
- import time
3
- from orionis.foundation.application import Application as Orionis
4
- from orionis.container.container import Container
5
- from orionis.test.cases.asynchronous import AsyncTestCase
6
-
7
- class TestSingleton(AsyncTestCase):
8
-
9
- async def testSingletonBasicFunctionality(self) -> None:
10
- """
11
- Tests the fundamental behavior of the singleton pattern for `Container` and `Orionis` classes.
12
-
13
- This method verifies the following:
14
- - Multiple instances of `Container` refer to the same object.
15
- - Multiple instances of `Orionis` refer to the same object.
16
- - The singleton instances of `Container` and `Orionis` are distinct from each other.
17
-
18
- Returns
19
- -------
20
- None
21
- This method does not return any value. Assertions are used to validate singleton behavior.
22
- """
23
-
24
- # Create multiple instances of Container and Orionis
25
- container1 = Container()
26
- container2 = Container()
27
- orionis1 = Orionis()
28
- orionis2 = Orionis()
29
-
30
- # Assert that all Container instances are the same object
31
- self.assertIs(container1, container2)
32
- self.assertEqual(id(container1), id(container2))
33
-
34
- # Assert that all Orionis instances are the same object
35
- self.assertIs(orionis1, orionis2)
36
- self.assertEqual(id(orionis1), id(orionis2))
37
-
38
- # Assert that Container and Orionis are different singleton instances
39
- self.assertIsNot(container1, orionis1)
40
-
41
- async def testSingletonThreadingSafety(self) -> None:
42
- """
43
- Validates the thread safety of the singleton pattern for `Container` and `Orionis` classes.
44
-
45
- This method ensures that, even when multiple threads attempt to instantiate
46
- `Container` and `Orionis` simultaneously, only one instance of each class is created.
47
-
48
- Returns
49
- -------
50
- None
51
- This method does not return any value. Assertions are used to validate thread-safe singleton behavior.
52
- """
53
-
54
- # List to hold instances created in threads
55
- container_instances = []
56
- orionis_instances = []
57
-
58
- def create_container():
59
- """Create and append a Container instance in a thread."""
60
- time.sleep(0.01) # Increase chance of race condition
61
- container_instances.append(Container())
62
-
63
- def create_orionis():
64
- """Create and append an Orionis instance in a thread."""
65
- time.sleep(0.01) # Increase chance of race condition
66
- orionis_instances.append(Orionis())
67
-
68
- # Create threads for concurrent instantiation
69
- threads = []
70
- for i in range(10):
71
- t1 = threading.Thread(target=create_container)
72
- t2 = threading.Thread(target=create_orionis)
73
- threads.extend([t1, t2])
74
-
75
- # Start all threads
76
- for t in threads:
77
- t.start()
78
-
79
- # Wait for all threads to complete
80
- for t in threads:
81
- t.join()
82
-
83
- # Collect instance IDs for verification
84
- container_ids = [id(c) for c in container_instances]
85
- orionis_ids = [id(o) for o in orionis_instances]
86
-
87
- # Assert that only one unique instance exists for each class
88
- self.assertEqual(len(set(container_ids)), 1)
89
- self.assertEqual(len(set(orionis_ids)), 1)
90
- self.assertEqual(len(container_instances), 10)
91
- self.assertEqual(len(orionis_instances), 10)
92
-
93
- async def testInheritanceSeparation(self) -> None:
94
- """
95
- Ensures that singleton instances are maintained separately for `Container` and `Orionis` classes.
96
-
97
- This method checks that:
98
- - Each class maintains its own singleton instance.
99
- - Data added to one singleton does not affect the other.
100
- - Both classes correctly implement the singleton pattern independently.
101
-
102
- Returns
103
- -------
104
- None
105
- This method does not return any value. Assertions are used to validate singleton separation.
106
- """
107
-
108
- # Create instances of Container and Orionis
109
- container = Container()
110
- orionis = Orionis()
111
-
112
- # Add a callable to the Container singleton
113
- container.callable("test_container", lambda: "container_value")
114
-
115
- # Verify that Container and Orionis are distinct singletons
116
- self.assertEqual(type(container).__name__, "Container")
117
- self.assertEqual(type(orionis).__name__, "Application")
118
- self.assertIsNot(container, orionis)
119
-
120
- # Check that the callable is bound only to Container
121
- self.assertTrue(container.bound('test_container'))
122
- self.assertFalse(orionis.bound('test_container'))
@@ -1,90 +0,0 @@
1
- import time
2
- import random
3
- from concurrent.futures import ThreadPoolExecutor, as_completed
4
- from orionis.foundation.application import Application as Orionis
5
- from orionis.container.container import Container
6
- from orionis.test.cases.asynchronous import AsyncTestCase
7
-
8
- class TestThreadSafety(AsyncTestCase):
9
-
10
- async def testStressSingleton(self) -> None:
11
- """
12
- Stress test singleton behavior under extreme concurrent conditions.
13
-
14
- This method creates a large number of threads that simultaneously attempt to
15
- instantiate singleton objects (`Container` and `Orionis`). It verifies that
16
- only one unique instance of each singleton exists, regardless of concurrent
17
- access, and that the singleton instances are distinct from each other.
18
-
19
- Parameters
20
- ----------
21
- None
22
-
23
- Returns
24
- -------
25
- None
26
- This method does not return any value. Assertions are used to validate
27
- singleton behavior under stress.
28
-
29
- Notes
30
- -----
31
- - Random delays are introduced to increase the likelihood of race conditions.
32
- - ThreadPoolExecutor is used to simulate high concurrency.
33
- - The test ensures that singleton integrity is maintained even under heavy load.
34
- """
35
-
36
- # Create lists to hold instances created in threads
37
- container_instances = []
38
- orionis_instances = []
39
-
40
- def create_container_with_delay():
41
- """Create a Container instance after a random delay to simulate real-world concurrency."""
42
- # Random delay to increase chance of race conditions
43
- time.sleep(random.uniform(0.001, 0.01))
44
- container = Container()
45
- container_instances.append(container)
46
- return id(container)
47
-
48
- def create_orionis_with_delay():
49
- """Create an Orionis instance after a random delay to simulate real-world concurrency."""
50
- # Random delay to increase chance of race conditions
51
- time.sleep(random.uniform(0.001, 0.01))
52
- orionis = Orionis()
53
- orionis_instances.append(orionis)
54
- return id(orionis)
55
-
56
- # Number of concurrent threads to simulate
57
- num_threads = 100
58
-
59
- # Use ThreadPoolExecutor to run tasks concurrently
60
- with ThreadPoolExecutor(max_workers=50) as executor:
61
- # Submit container creation tasks
62
- container_futures = [
63
- executor.submit(create_container_with_delay)
64
- for _ in range(num_threads)
65
- ]
66
-
67
- # Submit orionis creation tasks
68
- orionis_futures = [
69
- executor.submit(create_orionis_with_delay)
70
- for _ in range(num_threads)
71
- ]
72
-
73
- # Wait for all tasks to complete and collect instance IDs
74
- container_ids = [future.result() for future in as_completed(container_futures)]
75
- orionis_ids = [future.result() for future in as_completed(orionis_futures)]
76
-
77
- # Verify all instances are the same (singleton property)
78
- unique_container_ids = set(container_ids)
79
- unique_orionis_ids = set(orionis_ids)
80
-
81
- self.assertEqual(len(container_instances), num_threads)
82
- self.assertEqual(len(unique_container_ids), 1)
83
- self.assertEqual(len(orionis_instances), num_threads)
84
- self.assertEqual(len(unique_orionis_ids), 1)
85
-
86
- # Verify that Container and Orionis are different singletons
87
- container_id = list(unique_container_ids)[0] if unique_container_ids else None
88
- orionis_id = list(unique_orionis_ids)[0] if unique_orionis_ids else None
89
-
90
- self.assertNotEqual(container_id, orionis_id)
File without changes