1#!/usr/bin/env python3 2# Copyright 2016 Google Inc. All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS-IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16from absl.testing import parameterized 17from fruit_test_common import * 18 19COMMON_DEFINITIONS = ''' 20 #include "test_common.h" 21 22 struct X {}; 23 struct Y {}; 24 25 struct Annotation1 {}; 26 using IntAnnot1 = fruit::Annotated<Annotation1, int>; 27 using XAnnot1 = fruit::Annotated<Annotation1, X>; 28 29 struct Annotation2 {}; 30 using IntAnnot2 = fruit::Annotated<Annotation2, int>; 31 using XAnnot2 = fruit::Annotated<Annotation2, X>; 32 ''' 33 34class TestComponentAndInjectorParams(parameterized.TestCase): 35 @multiple_parameters([ 36 ('X', 'X'), 37 ('X', 'const X'), 38 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'), 39 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'), 40 ], [ 41 'Component', 42 'NormalizedComponent', 43 'Injector', 44 ]) 45 def test_duplicate_type(self, XAnnot, MaybeConstXAnnot, Class): 46 source = ''' 47 InstantiateType(fruit::Class<MaybeConstXAnnot, MaybeConstXAnnot>) 48 ''' 49 expect_compile_error( 50 'RepeatedTypesError<XAnnot,XAnnot>', 51 'A type was specified more than once.', 52 COMMON_DEFINITIONS, 53 source, 54 locals()) 55 56 @multiple_parameters([ 57 ('X', 'const X'), 58 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'), 59 ], [ 60 'Component', 61 'NormalizedComponent', 62 'Injector', 63 ]) 64 def test_duplicate_type_different_constness(self, XAnnot, ConstXAnnot, Class): 65 source = ''' 66 InstantiateType(fruit::Class<XAnnot, ConstXAnnot>) 67 ''' 68 expect_compile_error( 69 'RepeatedTypesError<XAnnot,XAnnot>', 70 'A type was specified more than once.', 71 COMMON_DEFINITIONS, 72 source, 73 locals()) 74 75 def test_duplicate_type_with_different_annotation_ok(self): 76 source = ''' 77 fruit::Component<XAnnot1, XAnnot2> getComponent() { 78 return fruit::createComponent() 79 .registerConstructor<XAnnot1()>() 80 .registerConstructor<XAnnot2()>(); 81 } 82 83 int main() { 84 fruit::Injector<XAnnot1, XAnnot2> injector1(getComponent); 85 injector1.get<XAnnot1>(); 86 injector1.get<XAnnot2>(); 87 88 fruit::NormalizedComponent<XAnnot1, XAnnot2> normalizedComponent(getComponent); 89 fruit::Injector<XAnnot1, XAnnot2> injector2(getComponent); 90 injector2.get<XAnnot1>(); 91 injector2.get<XAnnot2>(); 92 } 93 ''' 94 expect_success( 95 COMMON_DEFINITIONS, 96 source) 97 98 @multiple_parameters([ 99 ('X', 'X'), 100 ('X', 'const X'), 101 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'), 102 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'), 103 ], [ 104 'Component', 105 'NormalizedComponent', 106 ]) 107 def test_duplicate_type_in_required(self, XAnnot, MaybeConstXAnnot, Class): 108 source = ''' 109 InstantiateType(fruit::Class<fruit::Required<MaybeConstXAnnot, MaybeConstXAnnot>>) 110 ''' 111 expect_compile_error( 112 'RepeatedTypesError<XAnnot,XAnnot>', 113 'A type was specified more than once.', 114 COMMON_DEFINITIONS, 115 source, 116 locals()) 117 118 @multiple_parameters([ 119 'Component', 120 'NormalizedComponent', 121 ], [ 122 ('X', 'const X'), 123 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'), 124 ]) 125 def test_component_duplicate_type_in_required_different_constness(self, Class, XAnnot, ConstXAnnot): 126 source = ''' 127 InstantiateType(fruit::Class<fruit::Required<XAnnot, ConstXAnnot>>) 128 ''' 129 expect_compile_error( 130 'RepeatedTypesError<XAnnot,XAnnot>', 131 'A type was specified more than once.', 132 COMMON_DEFINITIONS, 133 source, 134 locals()) 135 136 @multiple_parameters([ 137 ('X', 'X'), 138 ('X', 'const X'), 139 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'), 140 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'), 141 ], [ 142 'Component', 143 'NormalizedComponent', 144 ]) 145 def test_same_type_in_required_and_provided(self, XAnnot, MaybeConstXAnnot, Class): 146 source = ''' 147 InstantiateType(fruit::Class<fruit::Required<MaybeConstXAnnot>, MaybeConstXAnnot>) 148 ''' 149 expect_compile_error( 150 'RepeatedTypesError<XAnnot,XAnnot>', 151 'A type was specified more than once.', 152 COMMON_DEFINITIONS, 153 source, 154 locals()) 155 156 @multiple_parameters([ 157 ('X', 'X', 'const X'), 158 ('X', 'const X', 'X'), 159 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'), 160 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X>'), 161 ], [ 162 'Component', 163 'NormalizedComponent', 164 ]) 165 def test_same_type_in_required_and_provided_different_constness(self, XAnnot, XAnnotInRequirements, XAnnotInProvides, Class): 166 source = ''' 167 InstantiateType(fruit::Class<fruit::Required<XAnnotInRequirements>, XAnnotInProvides>) 168 ''' 169 expect_compile_error( 170 'RepeatedTypesError<XAnnot,XAnnot>', 171 'A type was specified more than once.', 172 COMMON_DEFINITIONS, 173 source, 174 locals()) 175 176 def test_same_type_in_required_and_provided_different_annotation_ok(self): 177 source = ''' 178 fruit::Component<fruit::Required<XAnnot1>, XAnnot2> getComponent() { 179 return fruit::createComponent() 180 .registerConstructor<XAnnot2()>(); 181 } 182 183 fruit::Component<XAnnot1, XAnnot2> getRootComponent() { 184 return fruit::createComponent() 185 .install(getComponent) 186 .registerConstructor<XAnnot1()>(); 187 } 188 189 fruit::Component<> getEmptyComponent() { 190 return fruit::createComponent(); 191 } 192 193 int main() { 194 fruit::Injector<XAnnot1, XAnnot2> injector1(getRootComponent); 195 injector1.get<XAnnot1>(); 196 injector1.get<XAnnot2>(); 197 198 fruit::NormalizedComponent<XAnnot1, XAnnot2> normalizedComponent(getRootComponent); 199 fruit::Injector<XAnnot1, XAnnot2> injector2(normalizedComponent, getEmptyComponent); 200 injector2.get<XAnnot1>(); 201 injector2.get<XAnnot2>(); 202 } 203 ''' 204 expect_success( 205 COMMON_DEFINITIONS, 206 source) 207 208 @multiple_parameters([ 209 ('X*', r'X\*'), 210 ('const X*', r'const X\*'), 211 ('X&', r'X&'), 212 ('const X&', r'const X&'), 213 ('std::shared_ptr<X>', r'std::shared_ptr<X>'), 214 ('fruit::Annotated<Annotation1, X*>', r'X\*'), 215 ('fruit::Annotated<Annotation1, const X*>', r'const X\*'), 216 ('fruit::Annotated<Annotation1, X&>', r'X&'), 217 ('fruit::Annotated<Annotation1, const X&>', r'const X&'), 218 ('fruit::Annotated<Annotation1, std::shared_ptr<X>>', r'std::shared_ptr<X>'), 219 ], [ 220 'Component', 221 'NormalizedComponent', 222 'Injector', 223 ]) 224 def test_error_non_class_type(self, XVariantAnnot, XVariantRegexp, Class): 225 source = ''' 226 InstantiateType(fruit::Class<XVariantAnnot>) 227 ''' 228 expect_compile_error( 229 'NonClassTypeError<XVariantRegexp,X>', 230 'A non-class type T was specified. Use C instead.', 231 COMMON_DEFINITIONS, 232 source, 233 locals()) 234 235 @multiple_parameters([ 236 ('const X', 'const X'), 237 ('fruit::Annotated<Annotation1, const X>', 'const X'), 238 ], [ 239 'Component', 240 'NormalizedComponent', 241 'Injector', 242 ]) 243 def test_const_provided_type_ok(self, XVariantAnnot, XVariantRegexp, Class): 244 source = ''' 245 InstantiateType(fruit::Class<XVariantAnnot>) 246 ''' 247 expect_success( 248 COMMON_DEFINITIONS, 249 source, 250 locals()) 251 252 @multiple_parameters([ 253 ('X*', r'X\*'), 254 ('const X*', r'const X\*'), 255 ('X&', r'X&'), 256 ('const X&', r'const X&'), 257 ('std::shared_ptr<X>', r'std::shared_ptr<X>'), 258 ('fruit::Annotated<Annotation1, X*>', r'X\*'), 259 ('fruit::Annotated<Annotation1, const X*>', r'const X\*'), 260 ('fruit::Annotated<Annotation1, X&>', r'X&'), 261 ('fruit::Annotated<Annotation1, const X&>', r'const X&'), 262 ('fruit::Annotated<Annotation1, std::shared_ptr<X>>', r'std::shared_ptr<X>'), 263 ], [ 264 'Component', 265 'NormalizedComponent', 266 ]) 267 def test_error_non_class_type_in_requirements(self, XVariantAnnot, XVariantRegexp, Class): 268 source = ''' 269 InstantiateType(fruit::Class<fruit::Required<XVariantAnnot>>) 270 ''' 271 expect_compile_error( 272 'NonClassTypeError<XVariantRegexp,X>', 273 'A non-class type T was specified. Use C instead.', 274 COMMON_DEFINITIONS, 275 source, 276 locals()) 277 278 @parameterized.parameters([ 279 ('const Z', 'Z'), 280 ('fruit::Annotated<Annotation1, const Z>', 'fruit::Annotated<Annotation1, Z>'), 281 ]) 282 def test_const_class_type_ok(self, ConstZAnnot, ZAnnot): 283 source = ''' 284 struct Z {}; 285 286 const Z z{}; 287 288 fruit::Component<ConstZAnnot> getComponent() { 289 return fruit::createComponent() 290 .bindInstance<ZAnnot, Z>(z); 291 } 292 293 fruit::Component<> getEmptyComponent() { 294 return fruit::createComponent(); 295 } 296 297 int main() { 298 fruit::NormalizedComponent<ConstZAnnot> normalizedComponent(getComponent); 299 fruit::Injector<ConstZAnnot> injector(normalizedComponent, getEmptyComponent); 300 injector.get<ZAnnot>(); 301 } 302 ''' 303 expect_success( 304 COMMON_DEFINITIONS, 305 source, 306 locals()) 307 308 @parameterized.parameters([ 309 ('const Z', 'Z'), 310 ('fruit::Annotated<Annotation1, const Z>', 'fruit::Annotated<Annotation1, Z>'), 311 ]) 312 def test_const_class_type_in_requirements_ok(self, ConstZAnnot, ZAnnot): 313 source = ''' 314 struct Z {}; 315 316 fruit::Component<fruit::Required<ConstZAnnot>> getComponent() { 317 return fruit::createComponent(); 318 } 319 320 const Z z{}; 321 322 fruit::Component<ConstZAnnot> getEmptyComponent() { 323 return fruit::createComponent() 324 .bindInstance<ZAnnot, Z>(z); 325 } 326 327 int main() { 328 fruit::NormalizedComponent<fruit::Required<ConstZAnnot>> normalizedComponent(getComponent); 329 fruit::Injector<ConstZAnnot> injector(normalizedComponent, getEmptyComponent); 330 injector.get<ZAnnot>(); 331 } 332 ''' 333 expect_success( 334 COMMON_DEFINITIONS, 335 source, 336 locals()) 337 338 @parameterized.parameters([ 339 'Component', 340 'NormalizedComponent', 341 ]) 342 def test_two_required_lists_error(self, Class): 343 source = ''' 344 InstantiateType(fruit::Class<fruit::Required<X>, fruit::Required<Y>>) 345 ''' 346 expect_compile_error( 347 'RequiredTypesInComponentArgumentsError<fruit::Required<Y>>', 348 'A Required<...> type was passed as a non-first template parameter to fruit::Component or fruit::NormalizedComponent', 349 COMMON_DEFINITIONS, 350 source, 351 locals()) 352 353 @parameterized.parameters([ 354 'Component', 355 'NormalizedComponent', 356 ]) 357 def test_required_list_not_first_argument_error(self, Class): 358 source = ''' 359 InstantiateType(fruit::Class<X, fruit::Required<Y>>) 360 ''' 361 expect_compile_error( 362 'RequiredTypesInComponentArgumentsError<fruit::Required<Y>>', 363 'A Required<...> type was passed as a non-first template parameter to fruit::Component or fruit::NormalizedComponent', 364 COMMON_DEFINITIONS, 365 source, 366 locals()) 367 368 def test_multiple_required_types_ok(self): 369 source = ''' 370 fruit::Component<fruit::Required<X, Y>> getEmptyComponent() { 371 return fruit::createComponent(); 372 } 373 374 fruit::Component<X, Y> getComponent() { 375 return fruit::createComponent() 376 .install(getEmptyComponent) 377 .registerConstructor<X()>() 378 .registerConstructor<Y()>(); 379 } 380 381 int main() { 382 fruit::NormalizedComponent<fruit::Required<X, Y>> normalizedComponent(getEmptyComponent); 383 fruit::Injector<X> injector(normalizedComponent, getComponent); 384 injector.get<X>(); 385 } 386 ''' 387 expect_success( 388 COMMON_DEFINITIONS, 389 source) 390 391 @parameterized.parameters([ 392 ('X', 'Y'), 393 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, Y>'), 394 ]) 395 def test_error_requirements_in_injector(self, XAnnot, YAnnot): 396 source = ''' 397 InstantiateType(fruit::Injector<fruit::Required<YAnnot>, XAnnot>) 398 ''' 399 expect_compile_error( 400 'InjectorWithRequirementsError<YAnnot>', 401 'Injectors can.t have requirements.', 402 COMMON_DEFINITIONS, 403 source, 404 locals()) 405 406 @parameterized.parameters([ 407 ('X', 'Y'), 408 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, Y>'), 409 ]) 410 def test_error_requirements_in_injector_second_argument(self, XAnnot, YAnnot): 411 source = ''' 412 InstantiateType(fruit::Injector<XAnnot, fruit::Required<YAnnot>>) 413 ''' 414 expect_compile_error( 415 'InjectorWithRequirementsError<YAnnot>', 416 'Injectors can.t have requirements.', 417 COMMON_DEFINITIONS, 418 source, 419 locals()) 420 421if __name__ == '__main__': 422 absltest.main() 423