Coverage for tests/test_000_accretive/test_300_namespaces.py: 100%

161 statements  

« prev     ^ index     » next       coverage.py v7.5.4, created at 2024-07-06 17:17 +0000

1# vim: set filetype=python fileencoding=utf-8: 

2# -*- coding: utf-8 -*- 

3 

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#============================================================================# 

19 

20 

21''' Assert correct function of namespaces. ''' 

22 

23# mypy: ignore-errors 

24# pylint: disable=attribute-defined-outside-init 

25# pylint: disable=invalid-name,magic-value-comparison,protected-access 

26 

27 

28import pytest 

29 

30from itertools import product 

31 

32from . import ( 

33 CONCEALMENT_PACKAGES_NAMES, 

34 MODULES_QNAMES, 

35 PACKAGE_NAME, 

36 PROTECTION_PACKAGES_NAMES, 

37 cache_import_module, 

38) 

39 

40 

41THESE_MODULE_QNAMES = tuple( 

42 name for name in MODULES_QNAMES if name.endswith( '.namespaces' ) ) 

43THESE_CONCEALMENT_MODULE_QNAMES = tuple( 

44 name for name in THESE_MODULE_QNAMES 

45 if name.startswith( CONCEALMENT_PACKAGES_NAMES ) ) 

46THESE_NONCONCEALMENT_MODULE_QNAMES = tuple( 

47 name for name in THESE_MODULE_QNAMES 

48 if not name.startswith( CONCEALMENT_PACKAGES_NAMES ) ) 

49THESE_PROTECTION_MODULE_QNAMES = tuple( 

50 name for name in THESE_MODULE_QNAMES 

51 if name.startswith( PROTECTION_PACKAGES_NAMES ) ) 

52THESE_NONPROTECTION_MODULE_QNAMES = tuple( 

53 name for name in THESE_MODULE_QNAMES 

54 if not name.startswith( PROTECTION_PACKAGES_NAMES ) ) 

55THESE_CLASSES_NAMES = ( 'Namespace', ) 

56 

57base = cache_import_module( f"{PACKAGE_NAME}.__" ) 

58exceptions = cache_import_module( f"{PACKAGE_NAME}.exceptions" ) 

59 

60 

61@pytest.mark.parametrize( 

62 'module_qname, class_name', 

63 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

64) 

65def test_100_instantiation( module_qname, class_name ): 

66 ''' Class instantiates. ''' 

67 module = cache_import_module( module_qname ) 

68 Namespace = getattr( module, class_name ) 

69 ns1 = Namespace( ) 

70 assert isinstance( ns1, Namespace ) 

71 ns2 = Namespace( 

72 ( ( 'foo', 1 ), ( 'bar', 2 ) ), { 'unicorn': True }, orb = False ) 

73 assert isinstance( ns2, Namespace ) 

74 assert 1 == ns2.foo 

75 assert 2 == ns2.bar 

76 assert ns2.unicorn 

77 assert not ns2.orb 

78 assert ( 'foo', 'bar', 'unicorn', 'orb' ) == tuple( ns2.__dict__.keys( ) ) 

79 assert ( 1, 2, True, False ) == tuple( ns2.__dict__.values( ) ) 

80 

81 

82@pytest.mark.parametrize( 

83 'module_qname, class_name', 

84 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

85) 

86def test_101_accretion( module_qname, class_name ): 

87 ''' Namespace accretes attributes. ''' 

88 module = cache_import_module( module_qname ) 

89 Object = getattr( module, class_name ) 

90 obj = Object( ) 

91 obj.attr = 42 

92 with pytest.raises( exceptions.IndelibleAttributeError ): 

93 obj.attr = -1 

94 assert 42 == obj.attr 

95 with pytest.raises( exceptions.IndelibleAttributeError ): 

96 del obj.attr 

97 assert 42 == obj.attr 

98 

99 

100@pytest.mark.parametrize( 

101 'module_qname, class_name', 

102 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

103) 

104def test_102_string_representation( module_qname, class_name ): 

105 ''' Namespace has expected string representations. ''' 

106 module = cache_import_module( module_qname ) 

107 factory = getattr( module, class_name ) 

108 obj = factory( ) 

109 assert base.discover_fqname( obj ) in repr( obj ) 

110 obj.a = 1 

111 obj.b = 2 

112 assert 'a = 1, b = 2' in repr( obj ) 

113 

114 

115@pytest.mark.parametrize( 

116 'module_qname, class_name', 

117 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

118) 

119def test_105_dictionary_equality( module_qname, class_name ): 

120 ''' Dictionary is equivalent to another dictionary with same values. ''' 

121 from types import SimpleNamespace 

122 module = cache_import_module( module_qname ) 

123 factory = getattr( module, class_name ) 

124 ns1 = factory( foo = 1, bar = 2 ) 

125 ns2 = factory( ns1.__dict__ ) 

126 ns3 = SimpleNamespace( **ns1.__dict__ ) 

127 assert ns1 == ns2 

128 assert ns2 == ns1 

129 assert ns1 == ns3 

130 assert ns3 == ns1 

131 assert not ( ns1 == -1 ) # pylint: disable=superfluous-parens 

132 assert ns1 != -1 

133 assert ns1 != ( ) 

134 ns2.baz = 43 

135 assert ns1 != ns2 

136 assert ns2 != ns1 

137 

138 

139@pytest.mark.parametrize( 

140 'module_qname, class_name', 

141 product( THESE_CONCEALMENT_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

142) 

143def test_110_attribute_concealment( module_qname, class_name ): 

144 ''' Namespace conceals attributes. ''' 

145 module = cache_import_module( module_qname ) 

146 Object = getattr( module, class_name ) 

147 

148 class Concealer( Object ): 

149 ''' test ''' 

150 _attribute_visibility_includes_ = frozenset( ( '_private', ) ) 

151 

152 obj = Concealer( ) 

153 assert not dir( obj ) 

154 obj.public = 42 

155 assert 'public' in dir( obj ) 

156 obj._nonpublic = 3.1415926535 

157 assert '_nonpublic' not in dir( obj ) 

158 assert '_private' not in dir( obj ) 

159 obj._private = 'foo' 

160 assert '_private' in dir( obj ) 

161 

162 

163@pytest.mark.parametrize( 

164 'module_qname, class_name', 

165 product( THESE_NONCONCEALMENT_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

166) 

167def test_111_attribute_nonconcealment( module_qname, class_name ): 

168 ''' Namespace does not conceal attributes. ''' 

169 module = cache_import_module( module_qname ) 

170 Object = getattr( module, class_name ) 

171 

172 class Concealer( Object ): 

173 ''' test ''' 

174 _attribute_visibility_includes_ = frozenset( ( '_private', ) ) 

175 

176 obj = Concealer( ) 

177 assert '_attribute_visibility_includes_' in dir( obj ) 

178 obj.public = 42 

179 assert 'public' in dir( obj ) 

180 obj._nonpublic = 3.1415926535 

181 assert '_nonpublic' in dir( obj ) 

182 assert '_private' not in dir( obj ) 

183 obj._private = 'foo' 

184 assert '_private' in dir( obj ) 

185 

186 

187@pytest.mark.parametrize( 

188 'module_qname, class_name', 

189 product( THESE_PROTECTION_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

190) 

191def test_150_class_attribute_protection( module_qname, class_name ): 

192 ''' Class attributes are protected. ''' 

193 module = cache_import_module( module_qname ) 

194 Object = getattr( module, class_name ) 

195 with pytest.raises( exceptions.IndelibleAttributeError ): 

196 Object.__setattr__ = None 

197 with pytest.raises( exceptions.IndelibleAttributeError ): 

198 del Object.__setattr__ 

199 Object.foo = 42 

200 with pytest.raises( exceptions.IndelibleAttributeError ): 

201 Object.foo = -1 

202 with pytest.raises( exceptions.IndelibleAttributeError ): 

203 del Object.foo 

204 # Cleanup. 

205 type.__delattr__( Object, 'foo' ) 

206 

207 

208@pytest.mark.parametrize( 

209 'module_qname, class_name', 

210 product( THESE_NONPROTECTION_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

211) 

212def test_151_class_attribute_nonprotection( module_qname, class_name ): 

213 ''' Class attributes are not protected. ''' 

214 module = cache_import_module( module_qname ) 

215 Object = getattr( module, class_name ) 

216 Object.foo = 42 

217 assert 42 == Object.foo 

218 Object.foo = -1 

219 assert -1 == Object.foo 

220 del Object.foo 

221 assert not hasattr( Object, 'foo' ) 

222 

223 

224@pytest.mark.parametrize( 

225 'module_qname, class_name', 

226 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

227) 

228def test_900_docstring_sanity( module_qname, class_name ): 

229 ''' Class has valid docstring. ''' 

230 module = cache_import_module( module_qname ) 

231 Object = getattr( module, class_name ) 

232 assert hasattr( Object, '__doc__' ) 

233 assert isinstance( Object.__doc__, str ) 

234 assert Object.__doc__ 

235 

236 

237@pytest.mark.parametrize( 

238 'module_qname, class_name', 

239 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

240) 

241def test_901_docstring_describes_namespace( module_qname, class_name ): 

242 ''' Class docstring describes namespace. ''' 

243 module = cache_import_module( module_qname ) 

244 Object = getattr( module, class_name ) 

245 fragment = base.generate_docstring( 'description of namespace' ) 

246 assert fragment in Object.__doc__ 

247 

248 

249@pytest.mark.parametrize( 

250 'module_qname, class_name', 

251 product( THESE_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

252) 

253def test_902_docstring_mentions_accretion( module_qname, class_name ): 

254 ''' Class docstring mentions accretion. ''' 

255 module = cache_import_module( module_qname ) 

256 Object = getattr( module, class_name ) 

257 fragment = base.generate_docstring( 'instance attributes accretion' ) 

258 assert fragment in Object.__doc__ 

259 

260 

261@pytest.mark.parametrize( 

262 'module_qname, class_name', 

263 product( THESE_CONCEALMENT_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

264) 

265def test_910_docstring_mentions_concealment( module_qname, class_name ): 

266 ''' Class docstring mentions concealment. ''' 

267 module = cache_import_module( module_qname ) 

268 Object = getattr( module, class_name ) 

269 fragment = base.generate_docstring( 'instance attributes concealment' ) 

270 assert fragment in Object.__doc__ 

271 

272 

273@pytest.mark.parametrize( 

274 'module_qname, class_name', 

275 product( THESE_NONCONCEALMENT_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

276) 

277def test_911_docstring_not_mentions_concealment( module_qname, class_name ): 

278 ''' Class docstring does not mention concealment. ''' 

279 module = cache_import_module( module_qname ) 

280 Object = getattr( module, class_name ) 

281 fragment = base.generate_docstring( 'instance attributes concealment' ) 

282 assert fragment not in Object.__doc__ 

283 

284 

285@pytest.mark.parametrize( 

286 'module_qname, class_name', 

287 product( THESE_PROTECTION_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

288) 

289def test_930_docstring_mentions_protection( module_qname, class_name ): 

290 ''' Class docstring mentions protection. ''' 

291 module = cache_import_module( module_qname ) 

292 Object = getattr( module, class_name ) 

293 fragment = base.generate_docstring( 'protection of class' ) 

294 assert fragment in Object.__doc__ 

295 

296 

297@pytest.mark.parametrize( 

298 'module_qname, class_name', 

299 product( THESE_NONPROTECTION_MODULE_QNAMES, THESE_CLASSES_NAMES ) 

300) 

301def test_931_docstring_not_mentions_protection( module_qname, class_name ): 

302 ''' Class docstring does not mention protection. ''' 

303 module = cache_import_module( module_qname ) 

304 Object = getattr( module, class_name ) 

305 fragment = base.generate_docstring( 'protection of class' ) 

306 assert fragment not in Object.__doc__