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 24 struct Annotation1 {}; 25 using XAnnot = fruit::Annotated<Annotation1, X>; 26 27 struct Annotation2 {}; 28 29 struct Annotation3 {}; 30 31 template <typename T> 32 using WithNoAnnotation = T; 33 34 template <typename T> 35 using WithAnnotation1 = fruit::Annotated<Annotation1, T>; 36 ''' 37 38class TestRegisterConstructor(parameterized.TestCase): 39 40 def test_register_constructor_success_copyable_and_movable(self): 41 source = ''' 42 struct X { 43 INJECT(X()) = default; 44 X(X&&) = default; 45 X(const X&) = default; 46 }; 47 48 fruit::Component<X> getComponent() { 49 return fruit::createComponent(); 50 } 51 52 int main() { 53 fruit::Injector<X> injector(getComponent); 54 injector.get<X*>(); 55 } 56 ''' 57 expect_success( 58 COMMON_DEFINITIONS, 59 source) 60 61 def test_register_constructor_success_movable_only(self): 62 source = ''' 63 struct X { 64 INJECT(X()) = default; 65 X(X&&) = default; 66 X(const X&) = delete; 67 }; 68 69 fruit::Component<X> getComponent() { 70 return fruit::createComponent(); 71 } 72 73 int main() { 74 fruit::Injector<X> injector(getComponent); 75 injector.get<X*>(); 76 } 77 ''' 78 expect_success( 79 COMMON_DEFINITIONS, 80 source) 81 82 def test_register_constructor_success_not_movable(self): 83 source = ''' 84 struct X { 85 INJECT(X()) = default; 86 X(X&&) = delete; 87 X(const X&) = delete; 88 }; 89 90 fruit::Component<X> getComponent() { 91 return fruit::createComponent(); 92 } 93 94 int main() { 95 fruit::Injector<X> injector(getComponent); 96 injector.get<X*>(); 97 } 98 ''' 99 expect_success( 100 COMMON_DEFINITIONS, 101 source) 102 103 # TODO: consider moving to test_normalized_component.py 104 @parameterized.parameters([ 105 ('X', 'Y', 'Y', 'Z'), 106 ('X', 'Y', 'const Y', 'Z'), 107 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, Y>', 'fruit::Annotated<Annotation2, const Y>', 'fruit::Annotated<Annotation3, Z>'), 108 ]) 109 def test_autoinject_with_annotation_success(self, XAnnot, YAnnot, MaybeConstYAnnot, ZAnnot): 110 source = ''' 111 struct X { 112 using Inject = X(); 113 }; 114 115 struct Y : public ConstructionTracker<Y> { 116 using Inject = Y(); 117 }; 118 119 struct Z { 120 using Inject = Z(); 121 }; 122 123 fruit::Component<ZAnnot, MaybeConstYAnnot, XAnnot> getComponent() { 124 return fruit::createComponent(); 125 } 126 127 fruit::Component<> getEmptyComponent() { 128 return fruit::createComponent(); 129 } 130 131 int main() { 132 fruit::NormalizedComponent<> normalizedComponent(getEmptyComponent); 133 fruit::Injector<MaybeConstYAnnot> injector(normalizedComponent, getComponent); 134 135 Assert(Y::num_objects_constructed == 0); 136 injector.get<YAnnot>(); 137 Assert(Y::num_objects_constructed == 1); 138 } 139 ''' 140 expect_success( 141 COMMON_DEFINITIONS, 142 source, 143 locals()) 144 145 def test_autoinject_annotation_in_signature_return_type(self): 146 source = ''' 147 struct X { 148 using Inject = XAnnot(); 149 }; 150 151 fruit::Component<XAnnot> getComponent() { 152 return fruit::createComponent(); 153 } 154 ''' 155 expect_compile_error( 156 'InjectTypedefWithAnnotationError<X>', 157 'C::Inject is a signature that returns an annotated type', 158 COMMON_DEFINITIONS, 159 source) 160 161 def test_autoinject_wrong_class_in_typedef(self): 162 source = ''' 163 struct X { 164 using Inject = X(); 165 }; 166 167 struct Y : public X { 168 }; 169 170 fruit::Component<Y> getComponent() { 171 return fruit::createComponent(); 172 } 173 ''' 174 expect_compile_error( 175 'InjectTypedefForWrongClassError<Y,X>', 176 'C::Inject is a signature, but does not return a C. Maybe the class C has no Inject typedef and', 177 COMMON_DEFINITIONS, 178 source) 179 180 def test_register_constructor_error_abstract_class(self): 181 source = ''' 182 struct X { 183 X(int*) {} 184 185 virtual void foo() = 0; 186 }; 187 188 fruit::Component<X> getComponent() { 189 return fruit::createComponent() 190 .registerConstructor<fruit::Annotated<Annotation1, X>(int*)>(); 191 } 192 ''' 193 if re.search('GNU|MSVC', CXX_COMPILER_NAME) is not None: 194 expect_generic_compile_error( 195 'invalid abstract return type' 196 '|.X.: cannot instantiate abstract class', 197 COMMON_DEFINITIONS, 198 source) 199 else: 200 expect_compile_error( 201 'CannotConstructAbstractClassError<X>', 202 'The specified class can.t be constructed because it.s an abstract class', 203 COMMON_DEFINITIONS, 204 source) 205 206 def test_register_constructor_error_malformed_signature(self): 207 source = ''' 208 struct X { 209 X(int) {} 210 }; 211 212 fruit::Component<X> getComponent() { 213 return fruit::createComponent() 214 .registerConstructor<X[]>(); 215 } 216 ''' 217 expect_compile_error( 218 r'NotASignatureError<X\[\]>', 219 r'CandidateSignature was specified as parameter, but it.s not a signature. Signatures are of the form', 220 COMMON_DEFINITIONS, 221 source) 222 223 def test_register_constructor_error_malformed_signature_autoinject(self): 224 source = ''' 225 struct X { 226 using Inject = X[]; 227 X(int) {} 228 }; 229 230 fruit::Component<X> getComponent() { 231 return fruit::createComponent(); 232 } 233 ''' 234 expect_compile_error( 235 r'InjectTypedefNotASignatureError<X,X\[\]>', 236 r'C::Inject should be a typedef to a signature', 237 COMMON_DEFINITIONS, 238 source) 239 240 @parameterized.parameters([ 241 'char*', 242 'fruit::Annotated<Annotation1, char*>', 243 ]) 244 def test_register_constructor_does_not_exist_error(self, charPtrAnnot): 245 source = ''' 246 struct X { 247 X(int*) {} 248 }; 249 250 fruit::Component<X> getComponent() { 251 return fruit::createComponent() 252 .registerConstructor<X(charPtrAnnot)>(); 253 } 254 ''' 255 expect_compile_error( 256 r'NoConstructorMatchingInjectSignatureError<X,X\(char\*\)>', 257 r'contains an Inject typedef but it.s not constructible with the specified types', 258 COMMON_DEFINITIONS, 259 source, 260 locals()) 261 262 @parameterized.parameters([ 263 'char*', 264 'fruit::Annotated<Annotation1, char*>', 265 ]) 266 def test_autoinject_constructor_does_not_exist_error(self, charPtrAnnot): 267 source = ''' 268 struct X { 269 using Inject = X(charPtrAnnot); 270 X(int*) {} 271 }; 272 273 fruit::Component<X> getComponent() { 274 return fruit::createComponent(); 275 } 276 ''' 277 expect_compile_error( 278 r'NoConstructorMatchingInjectSignatureError<X,X\(char\*\)>', 279 r'contains an Inject typedef but it.s not constructible with the specified types', 280 COMMON_DEFINITIONS, 281 source, 282 locals()) 283 284 def test_autoinject_abstract_class_error(self): 285 source = ''' 286 struct X { 287 using Inject = fruit::Annotated<Annotation1, X>(); 288 289 virtual void scale() = 0; 290 // Note: here we "forgot" to implement scale() (on purpose, for this test) so X is an abstract class. 291 }; 292 293 fruit::Component<fruit::Annotated<Annotation1, X>> getComponent() { 294 return fruit::createComponent(); 295 } 296 ''' 297 expect_compile_error( 298 'CannotConstructAbstractClassError<X>', 299 'The specified class can.t be constructed because it.s an abstract class.', 300 COMMON_DEFINITIONS, 301 source) 302 303 @multiple_parameters([ 304 'WithNoAnnotation', 305 'WithAnnotation1', 306 ], [ 307 'Y', 308 'const Y', 309 'Y*', 310 'const Y*', 311 'Y&', 312 'const Y&', 313 'std::shared_ptr<Y>', 314 'fruit::Provider<Y>', 315 'fruit::Provider<const Y>', 316 ]) 317 def test_register_constructor_with_param_success(self, WithAnnotation, YVariant): 318 source = ''' 319 struct Y {}; 320 struct X { 321 X(YVariant) { 322 } 323 }; 324 325 fruit::Component<WithAnnotation<Y>> getYComponent() { 326 return fruit::createComponent() 327 .registerConstructor<WithAnnotation<Y>()>(); 328 } 329 330 fruit::Component<X> getComponent() { 331 return fruit::createComponent() 332 .install(getYComponent) 333 .registerConstructor<X(WithAnnotation<YVariant>)>(); 334 } 335 336 int main() { 337 fruit::Injector<X> injector(getComponent); 338 injector.get<X>(); 339 } 340 ''' 341 expect_success( 342 COMMON_DEFINITIONS, 343 source, 344 locals()) 345 346 @multiple_parameters([ 347 'WithNoAnnotation', 348 'WithAnnotation1', 349 ], [ 350 'Y', 351 'const Y', 352 'const Y*', 353 'const Y&', 354 'fruit::Provider<const Y>', 355 ]) 356 def test_register_constructor_with_param_const_binding_success(self, WithAnnotation, YVariant): 357 source = ''' 358 struct Y {}; 359 struct X { 360 X(YVariant) { 361 } 362 }; 363 364 const Y y{}; 365 366 fruit::Component<WithAnnotation<const Y>> getYComponent() { 367 return fruit::createComponent() 368 .bindInstance<WithAnnotation<Y>, Y>(y); 369 } 370 371 fruit::Component<X> getComponent() { 372 return fruit::createComponent() 373 .install(getYComponent) 374 .registerConstructor<X(WithAnnotation<YVariant>)>(); 375 } 376 377 int main() { 378 fruit::Injector<X> injector(getComponent); 379 injector.get<X>(); 380 } 381 ''' 382 expect_success( 383 COMMON_DEFINITIONS, 384 source, 385 locals()) 386 387 @multiple_parameters([ 388 ('WithNoAnnotation', 'Y'), 389 ('WithAnnotation1', 'fruit::Annotated<Annotation1,Y>'), 390 ], [ 391 'Y*', 392 'Y&', 393 'std::shared_ptr<Y>', 394 'fruit::Provider<Y>', 395 ]) 396 def test_register_constructor_with_param_error_nonconst_param_required(self, WithAnnotation, YAnnotRegex, YVariant): 397 source = ''' 398 struct Y {}; 399 struct X { 400 X(YVariant); 401 }; 402 403 fruit::Component<WithAnnotation<const Y>> getYComponent(); 404 405 fruit::Component<> getComponent() { 406 return fruit::createComponent() 407 .install(getYComponent) 408 .registerConstructor<X(WithAnnotation<YVariant>)>(); 409 } 410 ''' 411 expect_compile_error( 412 'NonConstBindingRequiredButConstBindingProvidedError<YAnnotRegex>', 413 'The type T was provided as constant, however one of the constructors/providers/factories in this component', 414 COMMON_DEFINITIONS, 415 source, 416 locals()) 417 418 @multiple_parameters([ 419 ('WithNoAnnotation', 'Y'), 420 ('WithAnnotation1', 'fruit::Annotated<Annotation1, Y>'), 421 ], [ 422 'Y*', 423 'Y&', 424 'std::shared_ptr<Y>', 425 'fruit::Provider<Y>', 426 ]) 427 def test_register_constructor_with_param_error_nonconst_param_required_install_after(self, WithAnnotation, YAnnotRegex, YVariant): 428 source = ''' 429 struct Y {}; 430 struct X { 431 X(YVariant); 432 }; 433 434 fruit::Component<WithAnnotation<const Y>> getYComponent(); 435 436 fruit::Component<> getComponent() { 437 return fruit::createComponent() 438 .registerConstructor<X(WithAnnotation<YVariant>)>() 439 .install(getYComponent); 440 } 441 ''' 442 expect_compile_error( 443 'NonConstBindingRequiredButConstBindingProvidedError<YAnnotRegex>', 444 'The type T was provided as constant, however one of the constructors/providers/factories in this component', 445 COMMON_DEFINITIONS, 446 source, 447 locals()) 448 449 def test_register_constructor_requiring_nonconst_then_requiring_const_ok(self): 450 source = ''' 451 struct X {}; 452 453 struct Y { 454 Y(X&) {} 455 }; 456 457 struct Z { 458 Z(const X&) {} 459 }; 460 461 fruit::Component<Y, Z> getRootComponent() { 462 return fruit::createComponent() 463 .registerConstructor<Y(X&)>() 464 .registerConstructor<Z(const X&)>() 465 .registerConstructor<X()>(); 466 } 467 468 int main() { 469 fruit::Injector<Y, Z> injector(getRootComponent); 470 injector.get<Y>(); 471 injector.get<Z>(); 472 } 473 ''' 474 expect_success( 475 COMMON_DEFINITIONS, 476 source, 477 locals()) 478 479 def test_register_constructor_requiring_nonconst_then_requiring_const_declaring_const_requirement_error(self): 480 source = ''' 481 struct X {}; 482 483 struct Y { 484 Y(X&) {} 485 }; 486 487 struct Z { 488 Z(const X&) {} 489 }; 490 491 fruit::Component<fruit::Required<const X>, Y, Z> getRootComponent() { 492 return fruit::createComponent() 493 .registerConstructor<Y(X&)>() 494 .registerConstructor<Z(const X&)>(); 495 } 496 ''' 497 expect_compile_error( 498 'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<X>', 499 'The type T was declared as a const Required type in the returned Component, however', 500 COMMON_DEFINITIONS, 501 source, 502 locals()) 503 504 def test_register_constructor_requiring_const_then_requiring_nonconst_ok(self): 505 source = ''' 506 struct X {}; 507 508 struct Y { 509 Y(const X&) {} 510 }; 511 512 struct Z { 513 Z(X&) {} 514 }; 515 516 fruit::Component<Y, Z> getRootComponent() { 517 return fruit::createComponent() 518 .registerConstructor<Y(const X&)>() 519 .registerConstructor<Z(X&)>() 520 .registerConstructor<X()>(); 521 } 522 523 int main() { 524 fruit::Injector<Y, Z> injector(getRootComponent); 525 injector.get<Y>(); 526 injector.get<Z>(); 527 } 528 ''' 529 expect_success( 530 COMMON_DEFINITIONS, 531 source, 532 locals()) 533 534 def test_register_constructor_requiring_const_then_requiring_nonconst_declaring_const_requirement_error(self): 535 source = ''' 536 struct X {}; 537 538 struct Y { 539 Y(const X&) {} 540 }; 541 542 struct Z { 543 Z(X&) {} 544 }; 545 546 fruit::Component<fruit::Required<const X>, Y, Z> getRootComponent() { 547 return fruit::createComponent() 548 .registerConstructor<Y(const X&)>() 549 .registerConstructor<Z(X&)>(); 550 } 551 ''' 552 expect_compile_error( 553 'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<X>', 554 'The type T was declared as a const Required type in the returned Component, however', 555 COMMON_DEFINITIONS, 556 source, 557 locals()) 558 559 @parameterized.parameters([ 560 ('Y**', r'Y\*\*'), 561 ('std::shared_ptr<Y>*', r'std::shared_ptr<Y>\*'), 562 ('std::nullptr_t', r'(std::)?nullptr(_t)?'), 563 ('Y*&', r'Y\*&'), 564 ('Y(*)()', r'Y(\((__cdecl)?\*\))?\((void)?\)'), 565 ('fruit::Annotated<Annotation1, Y**>', r'Y\*\*'), 566 ]) 567 def test_register_constructor_with_param_error_type_not_injectable(self, YVariant, YVariantRegex): 568 source = ''' 569 struct Y {}; 570 struct X { 571 X(YVariant); 572 }; 573 574 fruit::Component<> getComponent() { 575 return fruit::createComponent() 576 .registerConstructor<X(YVariant)>(); 577 } 578 ''' 579 expect_compile_error( 580 'NonInjectableTypeError<YVariantRegex>', 581 'The type T is not injectable.', 582 COMMON_DEFINITIONS, 583 source, 584 locals()) 585 586if __name__ == '__main__': 587 absltest.main() 588