Coverage for tests/test_000_accretive/test_010_internals.py: 100%
130 statements
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-04 22:31 +0000
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-04 22:31 +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 internals. '''
23# mypy: ignore-errors
24# pylint: disable=magic-value-comparison,protected-access
27import pytest
29from types import MappingProxyType as DictionaryProxy
31from . import PACKAGE_NAME, cache_import_module
34MODULE_QNAME = f"{PACKAGE_NAME}.__"
35CONCEALER_EXTENSIONS_NAMES = (
36 'ClassConcealerExtension',
37 'ConcealerExtension',
38)
39MODULE_ATTRIBUTE_NAMES = (
40 *CONCEALER_EXTENSIONS_NAMES,
41 'CoreDictionary',
42 'Docstring',
43 'discover_fqname',
44 'discover_public_attributes',
45 'generate_docstring',
46 'reclassify_modules',
47)
49exceptions = cache_import_module( f"{PACKAGE_NAME}.exceptions" )
50module = cache_import_module( MODULE_QNAME )
52dictionary_posargs = ( ( ( 'foo', 1 ), ( 'bar', 2 ) ), { 'unicorn': True } )
53dictionary_nomargs = DictionaryProxy( dict( orb = False ) )
56@pytest.mark.parametrize( 'class_name', CONCEALER_EXTENSIONS_NAMES )
57def test_100_concealer_extension_instantiation( class_name ):
58 ''' Class instantiantes. '''
59 factory = getattr( module, class_name )
60 posargs = ( 'Object', ( ), { } ) if issubclass( factory, type ) else ( )
61 obj = factory( *posargs )
62 assert isinstance( obj, factory )
65@pytest.mark.parametrize( 'class_name', CONCEALER_EXTENSIONS_NAMES )
66def test_102_concealer_extension_attribute_concealment( class_name ):
67 ''' Class conceals attributes. '''
68 factory = getattr( module, class_name )
69 posargs = ( 'Object', ( ), { } ) if issubclass( factory, type ) else ( )
70 concealer_name = (
71 '_class_attribute_visibility_includes_'
72 if issubclass( factory, type )
73 else '_attribute_visibility_includes_' )
74 obj = factory( *posargs )
75 assert not dir( obj )
76 obj.public = 42
77 assert 'public' in dir( obj )
78 obj._nonpublic = 3.1415926535
79 assert '_nonpublic' not in dir( obj )
80 setattr( obj, concealer_name, frozenset( ( '_nonpublic', ) ) )
81 assert '_nonpublic' in dir( obj )
82 assert concealer_name not in dir( obj )
85def test_103_class_concealer_extension_creates_classes( ):
86 ''' Class factory class instances are classes. '''
87 from inspect import isclass
88 factory = module.ClassConcealerExtension
89 assert issubclass( factory, type )
90 obj = factory( 'Object', ( ), { } )
91 assert isclass( obj )
94def test_200_core_dictionary_instantiation( ):
95 ''' Class instantiates. '''
96 factory = module.CoreDictionary
97 dct1 = factory( )
98 assert isinstance( dct1, factory )
99 dct2 = factory( *dictionary_posargs, **dictionary_nomargs )
100 assert isinstance( dct2, factory )
101 assert 1 == dct2[ 'foo' ]
102 assert 2 == dct2[ 'bar' ]
103 assert dct2[ 'unicorn' ]
104 assert not dct2[ 'orb' ]
105 assert ( 'foo', 'bar', 'unicorn', 'orb' ) == tuple( dct2.keys( ) )
106 assert ( 1, 2, True, False ) == tuple( dct2.values( ) )
109def test_201_core_dictionary_duplication( ):
110 ''' Dictionary is duplicable. '''
111 factory = module.CoreDictionary
112 odct = factory( *dictionary_posargs, **dictionary_nomargs )
113 ddct = odct.copy( )
114 assert odct == ddct
115 odct[ 'baz' ] = 42
116 assert odct != ddct
119def test_210_core_dictionary_entry_accretion( ):
120 ''' Dictionary accretes entries. '''
121 factory = module.CoreDictionary
122 dct = factory( *dictionary_posargs, **dictionary_nomargs )
123 with pytest.raises( exceptions.IndelibleEntryError ):
124 dct[ 'foo' ] = 42
125 with pytest.raises( exceptions.IndelibleEntryError ):
126 del dct[ 'foo' ]
127 dct[ 'baz' ] = 3.1415926535
128 with pytest.raises( exceptions.IndelibleEntryError ):
129 dct[ 'baz' ] = -1
130 with pytest.raises( exceptions.IndelibleEntryError ):
131 del dct[ 'baz' ]
134def test_211_core_dictionary_entry_accretion_via_update( ):
135 ''' Dictionary accretes entries via update. '''
136 factory = module.CoreDictionary
137 dct = factory( )
138 dct.update( *dictionary_posargs, **dictionary_nomargs )
139 with pytest.raises( exceptions.IndelibleEntryError ):
140 dct[ 'foo' ] = 42
141 with pytest.raises( exceptions.IndelibleEntryError ):
142 del dct[ 'foo' ]
143 dct[ 'baz' ] = 3.1415926535
144 with pytest.raises( exceptions.IndelibleEntryError ):
145 dct[ 'baz' ] = -1
146 with pytest.raises( exceptions.IndelibleEntryError ):
147 del dct[ 'baz' ]
150def test_220_core_dictionary_operation_prevention( ):
151 ''' Dictionary cannot perform entry deletions and mutations. '''
152 factory = module.CoreDictionary
153 dct = factory( *dictionary_posargs, **dictionary_nomargs )
154 with pytest.raises( exceptions.InvalidOperationError ):
155 dct.clear( )
156 with pytest.raises( exceptions.InvalidOperationError ):
157 dct.pop( 'foo' )
158 with pytest.raises( exceptions.InvalidOperationError ):
159 dct.pop( 'foo', default = -1 )
160 with pytest.raises( exceptions.InvalidOperationError ):
161 dct.pop( 'baz' )
162 with pytest.raises( exceptions.InvalidOperationError ):
163 dct.popitem( )
166def test_300_fqname_discovery( ):
167 ''' Fully-qualified name of object is discovered. '''
168 assert 'builtins.NoneType' == module.discover_fqname( None )
169 assert (
170 'builtins.type'
171 == module.discover_fqname( module.ConcealerExtension ) )
172 obj = module.ConcealerExtension( )
173 assert (
174 f"{MODULE_QNAME}.ConcealerExtension" == module.discover_fqname( obj ) )
177@pytest.mark.parametrize(
178 'provided, expected',
179 (
180 ( { 'foo': 12 }, ( ) ),
181 ( { '_foo': cache_import_module }, ( ) ),
182 (
183 { name: getattr( module, name )
184 for name in MODULE_ATTRIBUTE_NAMES },
185 MODULE_ATTRIBUTE_NAMES
186 ),
187 )
188)
189def test_400_public_attribute_discovery( provided, expected ):
190 ''' Public attributes are discovered from dictionary. '''
191 assert expected == module.discover_public_attributes( provided )
194def test_500_docstring_generation_argument_acceptance( ):
195 ''' Docstring generator errors on invalid arguments. '''
196 class Foo: pass # pylint: disable=missing-class-docstring
197 with pytest.raises( KeyError ):
198 module.generate_docstring( 1 )
199 with pytest.raises( KeyError ):
200 module.generate_docstring( '8-bit theater' )
201 assert not module.generate_docstring( Foo )
202 assert module.generate_docstring( 'instance attributes accretion' )
203 assert module.generate_docstring( module.Docstring( 'foo bar' ) )
206def test_501_docstring_generation_validity( ):
207 ''' Generated docstrings are correctly formatted. '''
208 from inspect import getdoc
210 class Foo:
211 ''' headline
213 additional information
214 '''
216 docstring_generated = module.generate_docstring(
217 Foo,
218 module.Docstring( 'foo bar' ),
219 'class attributes accretion' )
220 docstring_expected = '\n\n'.join( (
221 getdoc( Foo ),
222 'foo bar',
223 module.generate_docstring( 'class attributes accretion' ) ) )
224 assert docstring_expected == docstring_generated
227def test_600_module_reclassification( ):
228 ''' Modules are correctly reclassified. '''
229 from types import ModuleType as Module
230 m1 = Module( 'm1' )
231 m2 = Module( 'm2' )
233 class FooModule( Module ):
234 ''' test '''
236 m3 = FooModule( 'm3' )
237 attrs = { 'bar': 42, 'orb': True, 'm1': m1, 'm2': m2, 'm3': m3 }
238 assert not isinstance( m1, FooModule )
239 assert not isinstance( m2, FooModule )
240 assert isinstance( m3, FooModule )
241 module.reclassify_modules( attrs, FooModule )
242 assert isinstance( m1, FooModule )
243 assert isinstance( m2, FooModule )
244 assert isinstance( m3, FooModule )