orionis 0.405.0__py3-none-any.whl → 0.406.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. orionis/console/base/command.py +57 -50
  2. orionis/console/base/contracts/command.py +68 -0
  3. orionis/console/dynamic/contracts/progress_bar.py +3 -3
  4. orionis/console/dynamic/progress_bar.py +8 -8
  5. orionis/console/output/console.py +8 -2
  6. orionis/console/output/contracts/console.py +1 -1
  7. orionis/container/container.py +2 -2
  8. orionis/container/context/scope.py +4 -1
  9. orionis/container/contracts/service_provider.py +2 -2
  10. orionis/container/entities/binding.py +31 -44
  11. orionis/container/enums/lifetimes.py +22 -1
  12. orionis/container/facades/facade.py +1 -2
  13. orionis/container/providers/service_provider.py +2 -2
  14. orionis/foundation/application.py +542 -248
  15. orionis/foundation/config/app/entities/app.py +107 -90
  16. orionis/foundation/config/auth/entities/auth.py +4 -33
  17. orionis/foundation/config/cache/entities/cache.py +18 -41
  18. orionis/foundation/config/cache/entities/file.py +8 -35
  19. orionis/foundation/config/cache/entities/stores.py +17 -38
  20. orionis/foundation/config/cors/entities/cors.py +41 -54
  21. orionis/foundation/config/database/entities/connections.py +40 -56
  22. orionis/foundation/config/database/entities/database.py +11 -38
  23. orionis/foundation/config/database/entities/mysql.py +48 -76
  24. orionis/foundation/config/database/entities/oracle.py +30 -57
  25. orionis/foundation/config/database/entities/pgsql.py +45 -61
  26. orionis/foundation/config/database/entities/sqlite.py +26 -53
  27. orionis/foundation/config/filesystems/entitites/aws.py +28 -49
  28. orionis/foundation/config/filesystems/entitites/disks.py +27 -47
  29. orionis/foundation/config/filesystems/entitites/filesystems.py +15 -37
  30. orionis/foundation/config/filesystems/entitites/local.py +9 -35
  31. orionis/foundation/config/filesystems/entitites/public.py +14 -41
  32. orionis/foundation/config/logging/entities/channels.py +56 -86
  33. orionis/foundation/config/logging/entities/chunked.py +9 -9
  34. orionis/foundation/config/logging/entities/daily.py +8 -8
  35. orionis/foundation/config/logging/entities/hourly.py +6 -6
  36. orionis/foundation/config/logging/entities/logging.py +12 -18
  37. orionis/foundation/config/logging/entities/monthly.py +7 -7
  38. orionis/foundation/config/logging/entities/stack.py +5 -5
  39. orionis/foundation/config/logging/entities/weekly.py +6 -6
  40. orionis/foundation/config/mail/entities/file.py +9 -36
  41. orionis/foundation/config/mail/entities/mail.py +22 -40
  42. orionis/foundation/config/mail/entities/mailers.py +29 -44
  43. orionis/foundation/config/mail/entities/smtp.py +47 -48
  44. orionis/foundation/config/queue/entities/brokers.py +19 -41
  45. orionis/foundation/config/queue/entities/database.py +24 -46
  46. orionis/foundation/config/queue/entities/queue.py +28 -40
  47. orionis/foundation/config/roots/paths.py +272 -468
  48. orionis/foundation/config/session/entities/session.py +23 -53
  49. orionis/foundation/config/startup.py +165 -135
  50. orionis/foundation/config/testing/entities/testing.py +137 -122
  51. orionis/foundation/config/testing/enums/__init__.py +6 -2
  52. orionis/foundation/config/testing/enums/drivers.py +16 -0
  53. orionis/foundation/config/testing/enums/verbosity.py +18 -0
  54. orionis/foundation/contracts/application.py +152 -362
  55. orionis/foundation/providers/console_provider.py +24 -2
  56. orionis/foundation/providers/dumper_provider.py +24 -2
  57. orionis/foundation/providers/logger_provider.py +24 -2
  58. orionis/foundation/providers/path_resolver_provider.py +25 -2
  59. orionis/foundation/providers/progress_bar_provider.py +24 -2
  60. orionis/foundation/providers/testing_provider.py +39 -0
  61. orionis/foundation/providers/workers_provider.py +24 -2
  62. orionis/metadata/framework.py +1 -1
  63. orionis/services/environment/helpers/functions.py +1 -2
  64. orionis/services/environment/key/__init__.py +0 -0
  65. orionis/services/environment/key/key_generator.py +37 -0
  66. orionis/support/entities/__init__.py +0 -0
  67. orionis/support/entities/base.py +104 -0
  68. orionis/support/facades/testing.py +15 -0
  69. orionis/support/facades/workers.py +1 -1
  70. orionis/test/cases/asynchronous.py +0 -11
  71. orionis/test/cases/synchronous.py +0 -9
  72. orionis/test/contracts/dumper.py +11 -4
  73. orionis/test/contracts/kernel.py +5 -110
  74. orionis/test/contracts/logs.py +27 -65
  75. orionis/test/contracts/printer.py +16 -128
  76. orionis/test/contracts/test_result.py +100 -0
  77. orionis/test/contracts/unit_test.py +87 -150
  78. orionis/test/core/unit_test.py +608 -554
  79. orionis/test/entities/result.py +22 -2
  80. orionis/test/enums/__init__.py +0 -2
  81. orionis/test/enums/status.py +14 -9
  82. orionis/test/exceptions/config.py +9 -1
  83. orionis/test/exceptions/failure.py +34 -11
  84. orionis/test/exceptions/persistence.py +10 -2
  85. orionis/test/exceptions/runtime.py +9 -1
  86. orionis/test/exceptions/value.py +13 -1
  87. orionis/test/kernel.py +87 -289
  88. orionis/test/output/dumper.py +82 -18
  89. orionis/test/output/printer.py +399 -156
  90. orionis/test/records/logs.py +203 -82
  91. orionis/test/validators/__init__.py +33 -0
  92. orionis/test/validators/base_path.py +45 -0
  93. orionis/test/validators/execution_mode.py +45 -0
  94. orionis/test/validators/fail_fast.py +37 -0
  95. orionis/test/validators/folder_path.py +34 -0
  96. orionis/test/validators/module_name.py +31 -0
  97. orionis/test/validators/name_pattern.py +40 -0
  98. orionis/test/validators/pattern.py +36 -0
  99. orionis/test/validators/persistent.py +42 -0
  100. orionis/test/validators/persistent_driver.py +43 -0
  101. orionis/test/validators/print_result.py +37 -0
  102. orionis/test/validators/tags.py +37 -0
  103. orionis/test/validators/throw_exception.py +39 -0
  104. orionis/test/validators/verbosity.py +37 -0
  105. orionis/test/validators/web_report.py +35 -0
  106. orionis/test/validators/workers.py +31 -0
  107. orionis/test/view/render.py +48 -54
  108. {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/METADATA +1 -1
  109. {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/RECORD +149 -98
  110. tests/container/__init__.py +0 -0
  111. tests/container/context/__init__.py +0 -0
  112. tests/container/context/test_manager.py +27 -0
  113. tests/container/context/test_scope.py +23 -0
  114. tests/container/entities/__init__.py +0 -0
  115. tests/container/entities/test_binding.py +133 -0
  116. tests/container/enums/__init__.py +0 -0
  117. tests/container/enums/test_lifetimes.py +63 -0
  118. tests/container/facades/__init__.py +0 -0
  119. tests/container/facades/test_facade.py +61 -0
  120. tests/container/mocks/__init__.py +0 -0
  121. tests/container/mocks/mock_complex_classes.py +482 -0
  122. tests/container/mocks/mock_simple_classes.py +32 -0
  123. tests/container/providers/__init__.py +0 -0
  124. tests/container/providers/test_providers.py +48 -0
  125. tests/container/resolver/__init__.py +0 -0
  126. tests/container/resolver/test_resolver.py +55 -0
  127. tests/container/test_container.py +254 -0
  128. tests/container/test_singleton.py +98 -0
  129. tests/container/test_thread_safety.py +217 -0
  130. tests/container/validators/__init__.py +0 -0
  131. tests/container/validators/test_implements.py +140 -0
  132. tests/container/validators/test_is_abstract_class.py +99 -0
  133. tests/container/validators/test_is_callable.py +73 -0
  134. tests/container/validators/test_is_concrete_class.py +97 -0
  135. tests/container/validators/test_is_instance.py +105 -0
  136. tests/container/validators/test_is_not_subclass.py +117 -0
  137. tests/container/validators/test_is_subclass.py +115 -0
  138. tests/container/validators/test_is_valid_alias.py +113 -0
  139. tests/container/validators/test_lifetime.py +75 -0
  140. tests/foundation/config/testing/test_foundation_config_testing.py +1 -1
  141. tests/metadata/test_metadata_framework.py +18 -18
  142. tests/testing/test_testing_result.py +117 -117
  143. tests/testing/test_testing_unit.py +209 -209
  144. orionis/foundation/config/base.py +0 -112
  145. orionis/test/arguments/parser.py +0 -187
  146. orionis/test/contracts/parser.py +0 -43
  147. orionis/test/entities/arguments.py +0 -38
  148. orionis/test/enums/execution_mode.py +0 -16
  149. /orionis/{test/arguments → console/base/contracts}/__init__.py +0 -0
  150. /orionis/foundation/config/testing/enums/{test_mode.py → mode.py} +0 -0
  151. {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/WHEEL +0 -0
  152. {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/licenses/LICENCE +0 -0
  153. {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/top_level.txt +0 -0
  154. {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/zip-safe +0 -0
@@ -0,0 +1,140 @@
1
+ from abc import ABC, abstractmethod
2
+ from orionis.test.cases.asynchronous import AsyncTestCase
3
+ from orionis.container.validators.implements import ImplementsAbstractMethods
4
+ from orionis.container.exceptions.exception import OrionisContainerException
5
+
6
+ class TestImplementsAbstractMethods(AsyncTestCase):
7
+ """
8
+ Test cases for the ImplementsAbstractMethods validator in orionis.container.validators.implements.
9
+
10
+ Notes
11
+ -----
12
+ This test suite validates the functionality of the ImplementsAbstractMethods validator
13
+ which ensures that concrete classes correctly implement abstract methods.
14
+ """
15
+
16
+ async def asyncSetUp(self) -> None:
17
+ """
18
+ Set up test fixtures.
19
+ """
20
+ # Define abstract classes for testing
21
+ class AbstractBase(ABC):
22
+ @abstractmethod
23
+ def abstract_method(self) -> None:
24
+ pass
25
+
26
+ @abstractmethod
27
+ def another_abstract_method(self) -> str:
28
+ pass
29
+
30
+ class ConcreteCorrect(AbstractBase):
31
+ def abstract_method(self) -> None:
32
+ pass
33
+
34
+ def another_abstract_method(self) -> str:
35
+ return "implemented"
36
+
37
+ class ConcreteIncomplete(AbstractBase):
38
+ def abstract_method(self) -> None:
39
+ pass
40
+
41
+ class NonAbstractBase:
42
+ def regular_method(self) -> None:
43
+ pass
44
+
45
+ self.AbstractBase = AbstractBase
46
+ self.ConcreteCorrect = ConcreteCorrect
47
+ self.ConcreteIncomplete = ConcreteIncomplete
48
+ self.NonAbstractBase = NonAbstractBase
49
+
50
+ async def testValidImplementation(self) -> None:
51
+ """
52
+ Test that validation passes when all abstract methods are implemented.
53
+ """
54
+ # Test with class
55
+ ImplementsAbstractMethods(
56
+ abstract=self.AbstractBase,
57
+ concrete=self.ConcreteCorrect
58
+ )
59
+
60
+ # Test with instance
61
+ instance = self.ConcreteCorrect()
62
+ ImplementsAbstractMethods(
63
+ abstract=self.AbstractBase,
64
+ instance=instance
65
+ )
66
+
67
+ async def testIncompleteImplementation(self) -> None:
68
+ """
69
+ Test that validation fails when not all abstract methods are implemented.
70
+ """
71
+ # Test with class
72
+ with self.assertRaises(OrionisContainerException) as context:
73
+ ImplementsAbstractMethods(
74
+ abstract=self.AbstractBase,
75
+ concrete=self.ConcreteIncomplete
76
+ )
77
+
78
+ self.assertIn("does not implement the following abstract methods", str(context.exception))
79
+ self.assertIn("another_abstract_method", str(context.exception))
80
+
81
+ # Test with instance
82
+ with self.assertRaises(TypeError):
83
+ ImplementsAbstractMethods(
84
+ abstract=self.AbstractBase,
85
+ instance=self.ConcreteIncomplete()
86
+ )
87
+
88
+ async def testMissingAbstractClass(self) -> None:
89
+ """
90
+ Test that validation fails when no abstract class is provided.
91
+ """
92
+ with self.assertRaises(OrionisContainerException) as context:
93
+ ImplementsAbstractMethods(
94
+ concrete=self.ConcreteCorrect
95
+ )
96
+
97
+ self.assertIn("Abstract class must be provided", str(context.exception))
98
+
99
+ async def testMissingConcreteImplementation(self) -> None:
100
+ """
101
+ Test that validation fails when neither concrete class nor instance is provided.
102
+ """
103
+ with self.assertRaises(OrionisContainerException) as context:
104
+ ImplementsAbstractMethods(
105
+ abstract=self.AbstractBase
106
+ )
107
+
108
+ self.assertIn("Either concrete class or instance must be provided", str(context.exception))
109
+
110
+ async def testNonAbstractClass(self) -> None:
111
+ """
112
+ Test that validation fails when the provided abstract class has no abstract methods.
113
+ """
114
+ with self.assertRaises(OrionisContainerException) as context:
115
+ ImplementsAbstractMethods(
116
+ abstract=self.NonAbstractBase,
117
+ concrete=self.ConcreteCorrect
118
+ )
119
+
120
+ self.assertIn("does not define any abstract methods", str(context.exception))
121
+
122
+ async def testRenamedAbstractMethods(self) -> None:
123
+ """
124
+ Test handling of renamed abstract methods with class name prefixes.
125
+ """
126
+ # Define classes with renamed methods
127
+ class AbstractWithPrefix(ABC):
128
+ @abstractmethod
129
+ def _AbstractWithPrefix_method(self) -> None:
130
+ pass
131
+
132
+ class ConcreteWithPrefix:
133
+ def _ConcreteWithPrefix_method(self) -> None:
134
+ pass
135
+
136
+ # Should pass validation because the method is renamed according to class name
137
+ ImplementsAbstractMethods(
138
+ abstract=AbstractWithPrefix,
139
+ concrete=ConcreteWithPrefix
140
+ )
@@ -0,0 +1,99 @@
1
+ from abc import ABC, abstractmethod
2
+ import unittest.mock
3
+ from orionis.container.validators.is_abstract_class import IsAbstractClass
4
+ from orionis.container.exceptions.type import OrionisContainerTypeError
5
+ from orionis.test.cases.asynchronous import AsyncTestCase
6
+
7
+ class TestIsAbstractClass(AsyncTestCase):
8
+ """
9
+ Test cases for the IsAbstractClass validator in orionis.container.validators.is_abstract_class.
10
+
11
+ Notes
12
+ -----
13
+ This test suite validates the functionality of the IsAbstractClass validator
14
+ which ensures that a provided class is an abstract class.
15
+ """
16
+
17
+ async def testValidAbstractClass(self) -> None:
18
+ """
19
+ Test that validation passes for valid abstract classes.
20
+ """
21
+ # Create abstract class
22
+ class AbstractBase(ABC):
23
+ @abstractmethod
24
+ def abstract_method(self):
25
+ pass
26
+
27
+ # Should pass without raising an exception
28
+ with unittest.mock.patch('orionis.services.introspection.abstract.reflection.ReflectionAbstract.ensureIsAbstractClass') as mock_ensure:
29
+ IsAbstractClass(AbstractBase, "singleton")
30
+ mock_ensure.assert_called_once_with(AbstractBase)
31
+
32
+ async def testNonAbstractClass(self) -> None:
33
+ """
34
+ Test that validation fails for non-abstract classes.
35
+ """
36
+ class ConcreteClass:
37
+ def some_method(self):
38
+ pass
39
+
40
+ # Mock the ensureIsAbstractClass to raise an exception
41
+ with unittest.mock.patch('orionis.services.introspection.abstract.reflection.ReflectionAbstract.ensureIsAbstractClass',
42
+ side_effect=ValueError("Not an abstract class")) as mock_ensure:
43
+ with self.assertRaises(OrionisContainerTypeError) as context:
44
+ IsAbstractClass(ConcreteClass, "scoped")
45
+
46
+ self.assertIn("Unexpected error registering scoped service", str(context.exception))
47
+ mock_ensure.assert_called_once_with(ConcreteClass)
48
+
49
+ async def testWithInheritedAbstractClass(self) -> None:
50
+ """
51
+ Test validation with classes that inherit from abstract classes but are still abstract.
52
+ """
53
+ class BaseAbstract(ABC):
54
+ @abstractmethod
55
+ def method1(self):
56
+ pass
57
+
58
+ class DerivedAbstract(BaseAbstract):
59
+ @abstractmethod
60
+ def method2(self):
61
+ pass
62
+
63
+ # Should pass if the derived class is still abstract
64
+ with unittest.mock.patch('orionis.services.introspection.abstract.reflection.ReflectionAbstract.ensureIsAbstractClass') as mock_ensure:
65
+ IsAbstractClass(DerivedAbstract, "transient")
66
+ mock_ensure.assert_called_once_with(DerivedAbstract)
67
+
68
+ async def testWithConcreteImplementation(self) -> None:
69
+ """
70
+ Test validation with concrete implementations of abstract classes.
71
+ """
72
+ class BaseAbstract(ABC):
73
+ @abstractmethod
74
+ def method(self):
75
+ pass
76
+
77
+ class ConcreteImplementation(BaseAbstract):
78
+ def method(self):
79
+ return "Implemented"
80
+
81
+ # Should fail since ConcreteImplementation is not abstract
82
+ with unittest.mock.patch('orionis.services.introspection.abstract.reflection.ReflectionAbstract.ensureIsAbstractClass',
83
+ side_effect=TypeError("Not an abstract class")) as mock_ensure:
84
+ with self.assertRaises(OrionisContainerTypeError) as context:
85
+ IsAbstractClass(ConcreteImplementation, "singleton")
86
+
87
+ self.assertIn("Unexpected error registering singleton service", str(context.exception))
88
+ mock_ensure.assert_called_once_with(ConcreteImplementation)
89
+
90
+ async def testWithNonClassTypes(self) -> None:
91
+ """
92
+ Test validation with values that aren't classes at all.
93
+ """
94
+ # Test with primitive types
95
+ for invalid_value in [1, "string", [], {}, lambda: None]:
96
+ with unittest.mock.patch('orionis.services.introspection.abstract.reflection.ReflectionAbstract.ensureIsAbstractClass',
97
+ side_effect=TypeError(f"{type(invalid_value)} is not a class")) as mock_ensure:
98
+ with self.assertRaises(OrionisContainerTypeError):
99
+ IsAbstractClass(invalid_value, "transient")
@@ -0,0 +1,73 @@
1
+ from orionis.container.validators.is_callable import IsCallable
2
+ from orionis.container.exceptions.type import OrionisContainerTypeError
3
+ from orionis.test.cases.asynchronous import AsyncTestCase
4
+
5
+ class TestIsCallable(AsyncTestCase):
6
+ """
7
+ Test cases for the IsCallable validator in orionis.container.validators.is_callable.
8
+
9
+ Notes
10
+ -----
11
+ This test suite validates the functionality of the IsCallable validator
12
+ which ensures that a provided value is callable.
13
+ """
14
+
15
+ async def testValidCallables(self) -> None:
16
+ """
17
+ Test that validation passes for valid callable objects.
18
+ """
19
+ def simple_function():
20
+ pass
21
+
22
+ class ClassWithCall:
23
+ def __call__(self):
24
+ pass
25
+
26
+ lambda_func = lambda x: x
27
+
28
+ # These should not raise exceptions
29
+ IsCallable(simple_function)
30
+ IsCallable(ClassWithCall())
31
+ IsCallable(lambda_func)
32
+ IsCallable(len)
33
+ IsCallable(print)
34
+
35
+ async def testNonCallables(self) -> None:
36
+ """
37
+ Test that validation fails for non-callable objects.
38
+ """
39
+ non_callables = [
40
+ 42,
41
+ "string",
42
+ [1, 2, 3],
43
+ {"key": "value"},
44
+ None,
45
+ True,
46
+ (1, 2, 3)
47
+ ]
48
+
49
+ for value in non_callables:
50
+ with self.assertRaises(OrionisContainerTypeError) as context:
51
+ IsCallable(value)
52
+ expected_message = f"Expected a callable type, but got {type(value).__name__} instead."
53
+ self.assertEqual(str(context.exception), expected_message)
54
+
55
+ async def testClassesAsCallables(self) -> None:
56
+ """
57
+ Test that classes themselves are considered callable (since they can be instantiated).
58
+ """
59
+ class SimpleClass:
60
+ pass
61
+
62
+ # This should not raise an exception
63
+ IsCallable(SimpleClass)
64
+
65
+ async def testBuiltinFunctions(self) -> None:
66
+ """
67
+ Test that built-in functions are properly identified as callable.
68
+ """
69
+ # These should not raise exceptions
70
+ IsCallable(sum)
71
+ IsCallable(map)
72
+ IsCallable(filter)
73
+ IsCallable(sorted)
@@ -0,0 +1,97 @@
1
+ from abc import ABC, abstractmethod
2
+ from orionis.container.validators.is_concrete_class import IsConcreteClass
3
+ from orionis.container.exceptions.type import OrionisContainerTypeError
4
+ from orionis.test.cases.asynchronous import AsyncTestCase
5
+
6
+ class TestIsConcreteClass(AsyncTestCase):
7
+ """
8
+ Test cases for the IsConcreteClass validator in orionis.container.validators.is_concrete_class.
9
+
10
+ Notes
11
+ -----
12
+ This test suite validates the functionality of the IsConcreteClass validator
13
+ which ensures that a provided class is a concrete (non-abstract) class.
14
+ """
15
+
16
+ async def testValidConcreteClasses(self) -> None:
17
+ """
18
+ Test that validation passes for valid concrete classes.
19
+ """
20
+ class SimpleClass:
21
+ pass
22
+
23
+ class ClassWithInit:
24
+ def __init__(self, value):
25
+ self.value = value
26
+
27
+ # These should not raise exceptions
28
+ IsConcreteClass(SimpleClass, "singleton")
29
+ IsConcreteClass(ClassWithInit, "transient")
30
+
31
+ async def testAbstractClasses(self) -> None:
32
+ """
33
+ Test that validation fails for abstract classes.
34
+ """
35
+ class AbstractBase(ABC):
36
+ @abstractmethod
37
+ def abstract_method(self):
38
+ pass
39
+
40
+ with self.assertRaises(OrionisContainerTypeError) as context:
41
+ IsConcreteClass(AbstractBase, "scoped")
42
+ self.assertIn("Unexpected error registering scoped service", str(context.exception))
43
+
44
+ async def testNonClassTypes(self) -> None:
45
+ """
46
+ Test that validation fails for non-class types.
47
+ """
48
+ with self.assertRaises(OrionisContainerTypeError) as context:
49
+ IsConcreteClass(42, "singleton")
50
+ self.assertIn("Unexpected error registering singleton service", str(context.exception))
51
+
52
+ with self.assertRaises(OrionisContainerTypeError) as context:
53
+ IsConcreteClass("string", "scoped")
54
+ self.assertIn("Unexpected error registering scoped service", str(context.exception))
55
+
56
+ with self.assertRaises(OrionisContainerTypeError) as context:
57
+ IsConcreteClass(lambda x: x, "transient")
58
+ self.assertIn("Unexpected error registering transient service", str(context.exception))
59
+
60
+ async def testInheritedConcreteClasses(self) -> None:
61
+ """
62
+ Test that validation passes for concrete classes that inherit from abstract classes.
63
+ """
64
+ class AbstractBase(ABC):
65
+ @abstractmethod
66
+ def abstract_method(self):
67
+ pass
68
+
69
+ class ConcreteImplementation(AbstractBase):
70
+ def abstract_method(self):
71
+ return "Implemented"
72
+
73
+ # This should not raise an exception
74
+ IsConcreteClass(ConcreteImplementation, "singleton")
75
+
76
+ async def testPartialImplementations(self) -> None:
77
+ """
78
+ Test that validation fails for classes that don't implement all abstract methods.
79
+ """
80
+ class AbstractBase(ABC):
81
+ @abstractmethod
82
+ def method1(self):
83
+ pass
84
+
85
+ @abstractmethod
86
+ def method2(self):
87
+ pass
88
+
89
+ class PartialImplementation(AbstractBase):
90
+ def method1(self):
91
+ return "Implemented"
92
+
93
+ # method2 is not implemented
94
+
95
+ with self.assertRaises(OrionisContainerTypeError) as context:
96
+ IsConcreteClass(PartialImplementation, "scoped")
97
+ self.assertIn("Unexpected error registering scoped service", str(context.exception))
@@ -0,0 +1,105 @@
1
+ from abc import ABC, abstractmethod
2
+ from orionis.container.validators.is_instance import IsInstance
3
+ from orionis.container.exceptions.type import OrionisContainerTypeError
4
+ from orionis.test.cases.asynchronous import AsyncTestCase
5
+
6
+ class TestIsInstance(AsyncTestCase):
7
+ """
8
+ Test cases for the IsInstance validator in orionis.container.validators.is_instance.
9
+
10
+ Notes
11
+ -----
12
+ This test suite validates the functionality of the IsInstance validator
13
+ which ensures that a provided object is a valid instance (not a class or abstract type).
14
+ """
15
+
16
+ async def testValidInstances(self) -> None:
17
+ """
18
+ Test that validation passes for valid instances.
19
+ """
20
+
21
+ # Custom class instances
22
+ class SimpleClass:
23
+ pass
24
+
25
+ # Class with __init__ method
26
+ class ClassWithInit:
27
+ def __init__(self, value):
28
+ self.value = value
29
+
30
+ IsInstance(SimpleClass())
31
+ IsInstance(ClassWithInit(42))
32
+
33
+ async def testInvalidClasses(self) -> None:
34
+ """
35
+ Test that validation fails when provided with classes instead of instances.
36
+ """
37
+ with self.assertRaises(OrionisContainerTypeError) as context:
38
+ IsInstance(str)
39
+ self.assertIn("Error registering instance", str(context.exception))
40
+
41
+ class TestClass:
42
+ pass
43
+
44
+ with self.assertRaises(OrionisContainerTypeError) as context:
45
+ IsInstance(TestClass)
46
+ self.assertIn("Error registering instance", str(context.exception))
47
+
48
+ async def testAbstractClasses(self) -> None:
49
+ """
50
+ Test that validation fails for abstract classes and their types.
51
+ """
52
+ class AbstractBase(ABC):
53
+ @abstractmethod
54
+ def abstract_method(self):
55
+ pass
56
+
57
+ class ConcreteImplementation(AbstractBase):
58
+ def abstract_method(self):
59
+ return "Implemented"
60
+
61
+ # Abstract class should fail
62
+ with self.assertRaises(OrionisContainerTypeError) as context:
63
+ IsInstance(AbstractBase)
64
+ self.assertIn("Error registering instance", str(context.exception))
65
+
66
+ # But instance of concrete implementation should pass
67
+ IsInstance(ConcreteImplementation())
68
+
69
+ async def testTypeObjects(self) -> None:
70
+ """
71
+ Test validation with various type objects.
72
+ """
73
+ with self.assertRaises(OrionisContainerTypeError):
74
+ IsInstance(type)
75
+
76
+ with self.assertRaises(OrionisContainerTypeError):
77
+ IsInstance(int)
78
+
79
+ with self.assertRaises(OrionisContainerTypeError):
80
+ IsInstance(list)
81
+
82
+ async def testNoneValue(self) -> None:
83
+ """
84
+ Test validation with None value.
85
+ """
86
+ # None is a valid instance in Python
87
+ with self.assertRaises(OrionisContainerTypeError):
88
+ IsInstance(None)
89
+
90
+ async def testCallables(self) -> None:
91
+ """
92
+ Test validation with callable objects.
93
+ """
94
+ # Functions and lambdas are valid instances
95
+ def test_function():
96
+ pass
97
+
98
+ # Lambda functions are also valid instances
99
+ with self.assertRaises(OrionisContainerTypeError):
100
+ IsInstance(test_function)
101
+ IsInstance(lambda x: x * 2)
102
+
103
+ # But their types are not
104
+ with self.assertRaises(OrionisContainerTypeError):
105
+ IsInstance(type(test_function))
@@ -0,0 +1,117 @@
1
+ from abc import ABC
2
+ from orionis.container.validators.is_not_subclass import IsNotSubclass
3
+ from orionis.container.exceptions.exception import OrionisContainerException
4
+ from orionis.test.cases.asynchronous import AsyncTestCase
5
+
6
+ class TestIsNotSubclass(AsyncTestCase):
7
+ """
8
+ Test cases for the IsNotSubclass validator in orionis.container.validators.is_not_subclass.
9
+
10
+ Notes
11
+ -----
12
+ This test suite validates the functionality of the IsNotSubclass validator
13
+ which ensures that a concrete class is NOT a subclass of an abstract class.
14
+ """
15
+
16
+ async def testValidNonSubclass(self) -> None:
17
+ """
18
+ Test that validation passes when concrete class is not a subclass.
19
+ """
20
+ # Define test classes
21
+ class AbstractClass1(ABC):
22
+ pass
23
+
24
+ class AbstractClass2(ABC):
25
+ pass
26
+
27
+ class ConcreteClass1(AbstractClass1):
28
+ pass
29
+
30
+ class ConcreteClass2(AbstractClass2):
31
+ pass
32
+
33
+ # These should not raise exceptions
34
+ IsNotSubclass(AbstractClass1, AbstractClass2)
35
+ IsNotSubclass(AbstractClass1, ConcreteClass2)
36
+ IsNotSubclass(ConcreteClass1, AbstractClass1)
37
+ IsNotSubclass(int, str)
38
+ IsNotSubclass(list, dict)
39
+
40
+ async def testInvalidNonSubclass(self) -> None:
41
+ """
42
+ Test that validation fails when concrete class IS a subclass.
43
+ """
44
+ # Define test classes
45
+ class AbstractClass(ABC):
46
+ pass
47
+
48
+ class ConcreteClass(AbstractClass):
49
+ pass
50
+
51
+ class SubConcreteClass(ConcreteClass):
52
+ pass
53
+
54
+ # These should raise exceptions
55
+ with self.assertRaises(OrionisContainerException) as context:
56
+ IsNotSubclass(AbstractClass, ConcreteClass)
57
+ self.assertIn("must NOT inherit", str(context.exception))
58
+
59
+ with self.assertRaises(OrionisContainerException) as context:
60
+ IsNotSubclass(AbstractClass, SubConcreteClass)
61
+ self.assertIn("must NOT inherit", str(context.exception))
62
+
63
+ with self.assertRaises(OrionisContainerException) as context:
64
+ IsNotSubclass(ConcreteClass, SubConcreteClass)
65
+ self.assertIn("must NOT inherit", str(context.exception))
66
+
67
+ async def testSameClass(self) -> None:
68
+ """
69
+ Test validation when abstract and concrete are the same class.
70
+ """
71
+ class TestClass:
72
+ pass
73
+
74
+ # A class is considered a subclass of itself, so this should raise an exception
75
+ with self.assertRaises(OrionisContainerException) as context:
76
+ IsNotSubclass(TestClass, TestClass)
77
+ self.assertIn("must NOT inherit", str(context.exception))
78
+
79
+ async def testBuiltinTypes(self) -> None:
80
+ """
81
+ Test validation with built-in types.
82
+ """
83
+ # Valid non-subclass relationships
84
+ IsNotSubclass(ValueError, Exception)
85
+ IsNotSubclass(int, str)
86
+ IsNotSubclass(list, dict)
87
+
88
+ # Invalid non-subclass relationships (are actually subclasses)
89
+ with self.assertRaises(OrionisContainerException):
90
+ IsNotSubclass(Exception, ValueError)
91
+
92
+ with self.assertRaises(OrionisContainerException):
93
+ IsNotSubclass(BaseException, Exception)
94
+
95
+ async def testNonClassArguments(self) -> None:
96
+ """
97
+ Test validation with non-class arguments which should raise TypeError.
98
+ """
99
+ class TestClass:
100
+ pass
101
+
102
+ # These should raise TypeError when passed to issubclass()
103
+ non_class_args = [
104
+ None,
105
+ 123,
106
+ "string",
107
+ [],
108
+ {},
109
+ lambda x: x
110
+ ]
111
+
112
+ for arg in non_class_args:
113
+ with self.assertRaises(TypeError):
114
+ IsNotSubclass(TestClass, arg)
115
+
116
+ with self.assertRaises(TypeError):
117
+ IsNotSubclass(arg, TestClass)