Coverage for tests/test_000_frigid/test_400_modules.py: 100%
147 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-24 04:09 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-24 04:09 +0000
1# vim: set filetype=python fileencoding=utf-8:
2# -*- coding: utf-8 -*-
4#============================================================================#
5# #
6# Licensed under the Apache License, Version 2.0 (the "License"); #
7# you may not use this file except in compliance with the License. #
8# You may obtain a copy of the License at #
9# #
10# http://www.apache.org/licenses/LICENSE-2.0 #
11# #
12# Unless required by applicable law or agreed to in writing, software #
13# distributed under the License is distributed on an "AS IS" BASIS, #
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15# See the License for the specific language governing permissions and #
16# limitations under the License. #
17# #
18#============================================================================#
21''' Assert correct function of modules. '''
23# mypy: ignore-errors
24# pylint: disable=attribute-defined-outside-init
25# pylint: disable=invalid-name,magic-value-comparison,no-member
26# pylint: disable=protected-access
29import pytest
31from itertools import product
33from . import (
34 MODULES_QNAMES,
35 PACKAGE_NAME,
36 cache_import_module,
37)
40THESE_MODULE_QNAMES = tuple(
41 name for name in MODULES_QNAMES if name.endswith( '.modules' ) )
42THESE_CLASSES_NAMES = ( 'Module', )
44base = cache_import_module( f"{PACKAGE_NAME}.__" )
45exceptions = cache_import_module( f"{PACKAGE_NAME}.exceptions" )
48@pytest.mark.parametrize(
49 'module_qname, class_name',
50 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES )
51)
52def test_100_instantiation( module_qname, class_name ):
53 ''' Class instantiates with name. '''
54 module = cache_import_module( module_qname )
55 Module = getattr( module, class_name )
56 obj = Module( 'foo' )
57 assert isinstance( obj, Module )
58 assert 'foo' == obj.__name__
61@pytest.mark.parametrize(
62 'module_qname, class_name',
63 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES )
64)
65def test_101_immutability( module_qname, class_name ):
66 ''' Module prevents attribute modification. '''
67 module = cache_import_module( module_qname )
68 Module = getattr( module, class_name )
69 obj = Module( 'foo' )
70 with pytest.raises( exceptions.AttributeImmutabilityError ):
71 obj.attr = 42
72 with pytest.raises( exceptions.AttributeImmutabilityError ):
73 obj.__name__ = 'bar'
74 assert 'foo' == obj.__name__
75 with pytest.raises( exceptions.AttributeImmutabilityError ):
76 del obj.__name__
79@pytest.mark.parametrize(
80 'module_qname, class_name',
81 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES )
82)
83def test_500_module_reclassification_by_dict( module_qname, class_name ):
84 ''' Modules are correctly reclassified as immutable from dictionary. '''
85 module = cache_import_module( module_qname )
86 Module = getattr( module, class_name )
87 from types import ModuleType
88 m1 = ModuleType( f"{PACKAGE_NAME}.test1" )
89 m2 = ModuleType( f"{PACKAGE_NAME}.test2" )
90 m3 = ModuleType( "other.module" )
91 attrs = {
92 '__package__': PACKAGE_NAME,
93 'module1': m1,
94 'module2': m2,
95 'external': m3,
96 'other': 42,
97 }
98 assert not isinstance( m1, Module )
99 assert not isinstance( m2, Module )
100 assert not isinstance( m3, Module )
101 module.reclassify_modules( attrs )
102 assert isinstance( m1, Module )
103 assert isinstance( m2, Module )
104 assert not isinstance( m3, Module )
105 with pytest.raises( exceptions.AttributeImmutabilityError ):
106 m1.new_attr = 42
107 with pytest.raises( exceptions.AttributeImmutabilityError ):
108 m2.new_attr = 42
109 m3.new_attr = 42 # Should work
112@pytest.mark.parametrize(
113 'module_qname, class_name',
114 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES )
115)
116def test_501_module_reclassification_by_name( module_qname, class_name ):
117 ''' Modules are correctly reclassified as immutable from name. '''
118 module = cache_import_module( module_qname )
119 Module = getattr( module, class_name )
120 from types import ModuleType
121 from sys import modules
122 test_module = ModuleType( f"{PACKAGE_NAME}.test" )
123 test_module.__package__ = PACKAGE_NAME
124 modules[ test_module.__name__ ] = test_module
125 assert not isinstance( test_module, Module )
126 module.reclassify_modules( test_module.__name__ )
127 assert isinstance( test_module, Module )
128 with pytest.raises( exceptions.AttributeImmutabilityError ):
129 test_module.new_attr = 42
130 modules.pop( test_module.__name__ ) # Cleanup
133@pytest.mark.parametrize(
134 'module_qname, class_name',
135 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES )
136)
137def test_502_module_reclassification_by_object( module_qname, class_name ):
138 ''' Modules are correctly reclassified as immutable from object. '''
139 module = cache_import_module( module_qname )
140 Module = getattr( module, class_name )
141 from types import ModuleType
142 test_module = ModuleType( f"{PACKAGE_NAME}.test" )
143 test_module.__package__ = PACKAGE_NAME
144 assert not isinstance( test_module, Module )
145 module.reclassify_modules( test_module )
146 assert isinstance( test_module, Module )
147 with pytest.raises( exceptions.AttributeImmutabilityError ):
148 test_module.new_attr = 42
151@pytest.mark.parametrize(
152 'module_qname, class_name',
153 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES )
154)
155def test_503_recursive_module_reclassification( module_qname, class_name ):
156 ''' Recursive module reclassification works correctly. '''
157 module = cache_import_module( module_qname )
158 Module = getattr( module, class_name )
159 from types import ModuleType
160 root = ModuleType( f"{PACKAGE_NAME}.test" )
161 root.__package__ = PACKAGE_NAME
162 sub1 = ModuleType( f"{PACKAGE_NAME}.test.sub1" )
163 sub2 = ModuleType( f"{PACKAGE_NAME}.test.sub2" )
164 root.sub1 = sub1
165 root.sub2 = sub2
166 assert not isinstance( root, Module )
167 assert not isinstance( sub1, Module )
168 assert not isinstance( sub2, Module )
169 module.reclassify_modules( root, recursive = True )
170 assert isinstance( root, Module )
171 assert isinstance( sub1, Module )
172 assert isinstance( sub2, Module )
173 with pytest.raises( exceptions.AttributeImmutabilityError ):
174 root.new_attr = 42
175 with pytest.raises( exceptions.AttributeImmutabilityError ):
176 sub1.new_attr = 42
177 with pytest.raises( exceptions.AttributeImmutabilityError ):
178 sub2.new_attr = 42
181@pytest.mark.parametrize(
182 'module_qname, class_name',
183 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES )
184)
185def test_504_module_reclassification_respects_package(
186 module_qname, class_name
187):
188 ''' Module reclassification only affects package modules. '''
189 module = cache_import_module( module_qname )
190 Module = getattr( module, class_name )
191 from types import ModuleType
192 root = ModuleType( f"{PACKAGE_NAME}.test" )
193 root.__package__ = PACKAGE_NAME
194 external = ModuleType( "other_package.module" )
195 root.external = external
196 assert not isinstance( root, Module )
197 assert not isinstance( external, Module )
198 module.reclassify_modules( root )
199 assert isinstance( root, Module )
200 assert not isinstance( external, Module )
201 with pytest.raises( exceptions.AttributeImmutabilityError ):
202 root.new_attr = 42
203 external.new_attr = 42 # Should work
204 assert 42 == external.new_attr
207@pytest.mark.parametrize(
208 'module_qname, class_name',
209 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES )
210)
211def test_505_module_reclassification_requires_package(
212 module_qname, class_name
213):
214 ''' Module reclassification requires package name. '''
215 module = cache_import_module( module_qname )
216 Module = getattr( module, class_name )
217 from types import ModuleType
218 m1 = ModuleType( f"{PACKAGE_NAME}.test1" )
219 attrs = { 'module1': m1 } # Missing __package__ or __name__
220 assert not isinstance( m1, Module )
221 module.reclassify_modules( attrs )
222 assert not isinstance( m1, Module )
223 m1.new_attr = 42 # Should work
224 assert 42 == m1.new_attr
227@pytest.mark.parametrize(
228 'module_qname, class_name',
229 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES )
230)
231def test_900_docstring_sanity( module_qname, class_name ):
232 ''' Class has valid docstring. '''
233 module = cache_import_module( module_qname )
234 Object = getattr( module, class_name )
235 assert hasattr( Object, '__doc__' )
236 assert isinstance( Object.__doc__, str )
237 assert Object.__doc__
240@pytest.mark.parametrize(
241 'module_qname, class_name',
242 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES )
243)
244def test_901_docstring_describes_module( module_qname, class_name ):
245 ''' Class docstring describes module. '''
246 module = cache_import_module( module_qname )
247 Object = getattr( module, class_name )
248 fragment = base.generate_docstring( 'description of module' )
249 assert fragment in Object.__doc__
252@pytest.mark.parametrize(
253 'module_qname, class_name',
254 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES )
255)
256def test_902_docstring_mentions_immutability( module_qname, class_name ):
257 ''' Class docstring mentions immutability. '''
258 module = cache_import_module( module_qname )
259 Object = getattr( module, class_name )
260 fragment = base.generate_docstring( 'module attributes immutability' )
261 assert fragment in Object.__doc__