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.
- orionis/console/base/command.py +57 -50
- orionis/console/base/contracts/command.py +68 -0
- orionis/console/dynamic/contracts/progress_bar.py +3 -3
- orionis/console/dynamic/progress_bar.py +8 -8
- orionis/console/output/console.py +8 -2
- orionis/console/output/contracts/console.py +1 -1
- orionis/container/container.py +2 -2
- orionis/container/context/scope.py +4 -1
- orionis/container/contracts/service_provider.py +2 -2
- orionis/container/entities/binding.py +31 -44
- orionis/container/enums/lifetimes.py +22 -1
- orionis/container/facades/facade.py +1 -2
- orionis/container/providers/service_provider.py +2 -2
- orionis/foundation/application.py +542 -248
- orionis/foundation/config/app/entities/app.py +107 -90
- orionis/foundation/config/auth/entities/auth.py +4 -33
- orionis/foundation/config/cache/entities/cache.py +18 -41
- orionis/foundation/config/cache/entities/file.py +8 -35
- orionis/foundation/config/cache/entities/stores.py +17 -38
- orionis/foundation/config/cors/entities/cors.py +41 -54
- orionis/foundation/config/database/entities/connections.py +40 -56
- orionis/foundation/config/database/entities/database.py +11 -38
- orionis/foundation/config/database/entities/mysql.py +48 -76
- orionis/foundation/config/database/entities/oracle.py +30 -57
- orionis/foundation/config/database/entities/pgsql.py +45 -61
- orionis/foundation/config/database/entities/sqlite.py +26 -53
- orionis/foundation/config/filesystems/entitites/aws.py +28 -49
- orionis/foundation/config/filesystems/entitites/disks.py +27 -47
- orionis/foundation/config/filesystems/entitites/filesystems.py +15 -37
- orionis/foundation/config/filesystems/entitites/local.py +9 -35
- orionis/foundation/config/filesystems/entitites/public.py +14 -41
- orionis/foundation/config/logging/entities/channels.py +56 -86
- orionis/foundation/config/logging/entities/chunked.py +9 -9
- orionis/foundation/config/logging/entities/daily.py +8 -8
- orionis/foundation/config/logging/entities/hourly.py +6 -6
- orionis/foundation/config/logging/entities/logging.py +12 -18
- orionis/foundation/config/logging/entities/monthly.py +7 -7
- orionis/foundation/config/logging/entities/stack.py +5 -5
- orionis/foundation/config/logging/entities/weekly.py +6 -6
- orionis/foundation/config/mail/entities/file.py +9 -36
- orionis/foundation/config/mail/entities/mail.py +22 -40
- orionis/foundation/config/mail/entities/mailers.py +29 -44
- orionis/foundation/config/mail/entities/smtp.py +47 -48
- orionis/foundation/config/queue/entities/brokers.py +19 -41
- orionis/foundation/config/queue/entities/database.py +24 -46
- orionis/foundation/config/queue/entities/queue.py +28 -40
- orionis/foundation/config/roots/paths.py +272 -468
- orionis/foundation/config/session/entities/session.py +23 -53
- orionis/foundation/config/startup.py +165 -135
- orionis/foundation/config/testing/entities/testing.py +137 -122
- orionis/foundation/config/testing/enums/__init__.py +6 -2
- orionis/foundation/config/testing/enums/drivers.py +16 -0
- orionis/foundation/config/testing/enums/verbosity.py +18 -0
- orionis/foundation/contracts/application.py +152 -362
- orionis/foundation/providers/console_provider.py +24 -2
- orionis/foundation/providers/dumper_provider.py +24 -2
- orionis/foundation/providers/logger_provider.py +24 -2
- orionis/foundation/providers/path_resolver_provider.py +25 -2
- orionis/foundation/providers/progress_bar_provider.py +24 -2
- orionis/foundation/providers/testing_provider.py +39 -0
- orionis/foundation/providers/workers_provider.py +24 -2
- orionis/metadata/framework.py +1 -1
- orionis/services/environment/helpers/functions.py +1 -2
- orionis/services/environment/key/__init__.py +0 -0
- orionis/services/environment/key/key_generator.py +37 -0
- orionis/support/entities/__init__.py +0 -0
- orionis/support/entities/base.py +104 -0
- orionis/support/facades/testing.py +15 -0
- orionis/support/facades/workers.py +1 -1
- orionis/test/cases/asynchronous.py +0 -11
- orionis/test/cases/synchronous.py +0 -9
- orionis/test/contracts/dumper.py +11 -4
- orionis/test/contracts/kernel.py +5 -110
- orionis/test/contracts/logs.py +27 -65
- orionis/test/contracts/printer.py +16 -128
- orionis/test/contracts/test_result.py +100 -0
- orionis/test/contracts/unit_test.py +87 -150
- orionis/test/core/unit_test.py +608 -554
- orionis/test/entities/result.py +22 -2
- orionis/test/enums/__init__.py +0 -2
- orionis/test/enums/status.py +14 -9
- orionis/test/exceptions/config.py +9 -1
- orionis/test/exceptions/failure.py +34 -11
- orionis/test/exceptions/persistence.py +10 -2
- orionis/test/exceptions/runtime.py +9 -1
- orionis/test/exceptions/value.py +13 -1
- orionis/test/kernel.py +87 -289
- orionis/test/output/dumper.py +82 -18
- orionis/test/output/printer.py +399 -156
- orionis/test/records/logs.py +203 -82
- orionis/test/validators/__init__.py +33 -0
- orionis/test/validators/base_path.py +45 -0
- orionis/test/validators/execution_mode.py +45 -0
- orionis/test/validators/fail_fast.py +37 -0
- orionis/test/validators/folder_path.py +34 -0
- orionis/test/validators/module_name.py +31 -0
- orionis/test/validators/name_pattern.py +40 -0
- orionis/test/validators/pattern.py +36 -0
- orionis/test/validators/persistent.py +42 -0
- orionis/test/validators/persistent_driver.py +43 -0
- orionis/test/validators/print_result.py +37 -0
- orionis/test/validators/tags.py +37 -0
- orionis/test/validators/throw_exception.py +39 -0
- orionis/test/validators/verbosity.py +37 -0
- orionis/test/validators/web_report.py +35 -0
- orionis/test/validators/workers.py +31 -0
- orionis/test/view/render.py +48 -54
- {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/METADATA +1 -1
- {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/RECORD +149 -98
- tests/container/__init__.py +0 -0
- tests/container/context/__init__.py +0 -0
- tests/container/context/test_manager.py +27 -0
- tests/container/context/test_scope.py +23 -0
- tests/container/entities/__init__.py +0 -0
- tests/container/entities/test_binding.py +133 -0
- tests/container/enums/__init__.py +0 -0
- tests/container/enums/test_lifetimes.py +63 -0
- tests/container/facades/__init__.py +0 -0
- tests/container/facades/test_facade.py +61 -0
- tests/container/mocks/__init__.py +0 -0
- tests/container/mocks/mock_complex_classes.py +482 -0
- tests/container/mocks/mock_simple_classes.py +32 -0
- tests/container/providers/__init__.py +0 -0
- tests/container/providers/test_providers.py +48 -0
- tests/container/resolver/__init__.py +0 -0
- tests/container/resolver/test_resolver.py +55 -0
- tests/container/test_container.py +254 -0
- tests/container/test_singleton.py +98 -0
- tests/container/test_thread_safety.py +217 -0
- tests/container/validators/__init__.py +0 -0
- tests/container/validators/test_implements.py +140 -0
- tests/container/validators/test_is_abstract_class.py +99 -0
- tests/container/validators/test_is_callable.py +73 -0
- tests/container/validators/test_is_concrete_class.py +97 -0
- tests/container/validators/test_is_instance.py +105 -0
- tests/container/validators/test_is_not_subclass.py +117 -0
- tests/container/validators/test_is_subclass.py +115 -0
- tests/container/validators/test_is_valid_alias.py +113 -0
- tests/container/validators/test_lifetime.py +75 -0
- tests/foundation/config/testing/test_foundation_config_testing.py +1 -1
- tests/metadata/test_metadata_framework.py +18 -18
- tests/testing/test_testing_result.py +117 -117
- tests/testing/test_testing_unit.py +209 -209
- orionis/foundation/config/base.py +0 -112
- orionis/test/arguments/parser.py +0 -187
- orionis/test/contracts/parser.py +0 -43
- orionis/test/entities/arguments.py +0 -38
- orionis/test/enums/execution_mode.py +0 -16
- /orionis/{test/arguments → console/base/contracts}/__init__.py +0 -0
- /orionis/foundation/config/testing/enums/{test_mode.py → mode.py} +0 -0
- {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/WHEEL +0 -0
- {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/top_level.txt +0 -0
- {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)
|