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 if re.search('MSVC', CXX_COMPILER_NAME) is not None: 182 # MSVC allows to construct the type X(int*) but SignatureType<Type<X(int*)>> doesn't find the 183 # specialization. 184 return 185 source = ''' 186 struct X { 187 X(int*) {} 188 189 virtual void foo() = 0; 190 }; 191 192 fruit::Component<X> getComponent() { 193 return fruit::createComponent() 194 .registerConstructor<fruit::Annotated<Annotation1, X>(int*)>(); 195 } 196 ''' 197 # Some compilers give a generic compile error, some don't and then Fruit reports the error. 198 try: 199 expect_generic_compile_error( 200 'invalid abstract return type' 201 '|.X.: cannot instantiate abstract class', 202 COMMON_DEFINITIONS, 203 source) 204 except: 205 expect_compile_error( 206 'CannotConstructAbstractClassError<X>', 207 'The specified class can.t be constructed because it.s an abstract class', 208 COMMON_DEFINITIONS, 209 source) 210 211 def test_register_constructor_error_malformed_signature(self): 212 source = ''' 213 struct X { 214 X(int) {} 215 }; 216 217 fruit::Component<X> getComponent() { 218 return fruit::createComponent() 219 .registerConstructor<X[]>(); 220 } 221 ''' 222 expect_compile_error( 223 r'NotASignatureError<X\[\]>', 224 r'CandidateSignature was specified as parameter, but it.s not a signature. Signatures are of the form', 225 COMMON_DEFINITIONS, 226 source) 227 228 def test_register_constructor_error_malformed_signature_autoinject(self): 229 source = ''' 230 struct X { 231 using Inject = X[]; 232 X(int) {} 233 }; 234 235 fruit::Component<X> getComponent() { 236 return fruit::createComponent(); 237 } 238 ''' 239 expect_compile_error( 240 r'InjectTypedefNotASignatureError<X,X\[\]>', 241 r'C::Inject should be a typedef to a signature', 242 COMMON_DEFINITIONS, 243 source) 244 245 @parameterized.parameters([ 246 'char*', 247 'fruit::Annotated<Annotation1, char*>', 248 ]) 249 def test_register_constructor_does_not_exist_error(self, charPtrAnnot): 250 source = ''' 251 struct X { 252 X(int*) {} 253 }; 254 255 fruit::Component<X> getComponent() { 256 return fruit::createComponent() 257 .registerConstructor<X(charPtrAnnot)>(); 258 } 259 ''' 260 expect_compile_error( 261 r'NoConstructorMatchingInjectSignatureError<X,X\(char\*\)>', 262 r'contains an Inject typedef but it.s not constructible with the specified types', 263 COMMON_DEFINITIONS, 264 source, 265 locals()) 266 267 @parameterized.parameters([ 268 'char*', 269 'fruit::Annotated<Annotation1, char*>', 270 ]) 271 def test_autoinject_constructor_does_not_exist_error(self, charPtrAnnot): 272 source = ''' 273 struct X { 274 using Inject = X(charPtrAnnot); 275 X(int*) {} 276 }; 277 278 fruit::Component<X> getComponent() { 279 return fruit::createComponent(); 280 } 281 ''' 282 expect_compile_error( 283 r'NoConstructorMatchingInjectSignatureError<X,X\(char\*\)>', 284 r'contains an Inject typedef but it.s not constructible with the specified types', 285 COMMON_DEFINITIONS, 286 source, 287 locals()) 288 289 def test_autoinject_abstract_class_error(self): 290 source = ''' 291 struct X { 292 using Inject = fruit::Annotated<Annotation1, X>(); 293 294 virtual void scale() = 0; 295 // Note: here we "forgot" to implement scale() (on purpose, for this test) so X is an abstract class. 296 }; 297 298 fruit::Component<fruit::Annotated<Annotation1, X>> getComponent() { 299 return fruit::createComponent(); 300 } 301 ''' 302 expect_compile_error( 303 'CannotConstructAbstractClassError<X>', 304 'The specified class can.t be constructed because it.s an abstract class.', 305 COMMON_DEFINITIONS, 306 source) 307 308 @multiple_parameters([ 309 'WithNoAnnotation', 310 'WithAnnotation1', 311 ], [ 312 'Y', 313 'const Y', 314 'Y*', 315 'const Y*', 316 'Y&', 317 'const Y&', 318 'std::shared_ptr<Y>', 319 'fruit::Provider<Y>', 320 'fruit::Provider<const Y>', 321 ]) 322 def test_register_constructor_with_param_success(self, WithAnnotation, YVariant): 323 source = ''' 324 struct Y {}; 325 struct X { 326 X(YVariant) { 327 } 328 }; 329 330 fruit::Component<WithAnnotation<Y>> getYComponent() { 331 return fruit::createComponent() 332 .registerConstructor<WithAnnotation<Y>()>(); 333 } 334 335 fruit::Component<X> getComponent() { 336 return fruit::createComponent() 337 .install(getYComponent) 338 .registerConstructor<X(WithAnnotation<YVariant>)>(); 339 } 340 341 int main() { 342 fruit::Injector<X> injector(getComponent); 343 injector.get<X>(); 344 } 345 ''' 346 expect_success( 347 COMMON_DEFINITIONS, 348 source, 349 locals()) 350 351 @multiple_parameters([ 352 'WithNoAnnotation', 353 'WithAnnotation1', 354 ], [ 355 'Y', 356 'const Y', 357 'const Y*', 358 'const Y&', 359 'fruit::Provider<const Y>', 360 ]) 361 def test_register_constructor_with_param_const_binding_success(self, WithAnnotation, YVariant): 362 source = ''' 363 struct Y {}; 364 struct X { 365 X(YVariant) { 366 } 367 }; 368 369 const Y y{}; 370 371 fruit::Component<WithAnnotation<const Y>> getYComponent() { 372 return fruit::createComponent() 373 .bindInstance<WithAnnotation<Y>, Y>(y); 374 } 375 376 fruit::Component<X> getComponent() { 377 return fruit::createComponent() 378 .install(getYComponent) 379 .registerConstructor<X(WithAnnotation<YVariant>)>(); 380 } 381 382 int main() { 383 fruit::Injector<X> injector(getComponent); 384 injector.get<X>(); 385 } 386 ''' 387 expect_success( 388 COMMON_DEFINITIONS, 389 source, 390 locals()) 391 392 @multiple_parameters([ 393 ('WithNoAnnotation', 'Y'), 394 ('WithAnnotation1', 'fruit::Annotated<Annotation1,Y>'), 395 ], [ 396 'Y*', 397 'Y&', 398 'std::shared_ptr<Y>', 399 'fruit::Provider<Y>', 400 ]) 401 def test_register_constructor_with_param_error_nonconst_param_required(self, WithAnnotation, YAnnotRegex, YVariant): 402 source = ''' 403 struct Y {}; 404 struct X { 405 X(YVariant); 406 }; 407 408 fruit::Component<WithAnnotation<const Y>> getYComponent(); 409 410 fruit::Component<> getComponent() { 411 return fruit::createComponent() 412 .install(getYComponent) 413 .registerConstructor<X(WithAnnotation<YVariant>)>(); 414 } 415 ''' 416 expect_compile_error( 417 'NonConstBindingRequiredButConstBindingProvidedError<YAnnotRegex>', 418 'The type T was provided as constant, however one of the constructors/providers/factories in this component', 419 COMMON_DEFINITIONS, 420 source, 421 locals()) 422 423 @multiple_parameters([ 424 ('WithNoAnnotation', 'Y'), 425 ('WithAnnotation1', 'fruit::Annotated<Annotation1, Y>'), 426 ], [ 427 'Y*', 428 'Y&', 429 'std::shared_ptr<Y>', 430 'fruit::Provider<Y>', 431 ]) 432 def test_register_constructor_with_param_error_nonconst_param_required_install_after(self, WithAnnotation, YAnnotRegex, YVariant): 433 source = ''' 434 struct Y {}; 435 struct X { 436 X(YVariant); 437 }; 438 439 fruit::Component<WithAnnotation<const Y>> getYComponent(); 440 441 fruit::Component<> getComponent() { 442 return fruit::createComponent() 443 .registerConstructor<X(WithAnnotation<YVariant>)>() 444 .install(getYComponent); 445 } 446 ''' 447 expect_compile_error( 448 'NonConstBindingRequiredButConstBindingProvidedError<YAnnotRegex>', 449 'The type T was provided as constant, however one of the constructors/providers/factories in this component', 450 COMMON_DEFINITIONS, 451 source, 452 locals()) 453 454 def test_register_constructor_requiring_nonconst_then_requiring_const_ok(self): 455 source = ''' 456 struct X {}; 457 458 struct Y { 459 Y(X&) {} 460 }; 461 462 struct Z { 463 Z(const X&) {} 464 }; 465 466 fruit::Component<Y, Z> getRootComponent() { 467 return fruit::createComponent() 468 .registerConstructor<Y(X&)>() 469 .registerConstructor<Z(const X&)>() 470 .registerConstructor<X()>(); 471 } 472 473 int main() { 474 fruit::Injector<Y, Z> injector(getRootComponent); 475 injector.get<Y>(); 476 injector.get<Z>(); 477 } 478 ''' 479 expect_success( 480 COMMON_DEFINITIONS, 481 source, 482 locals()) 483 484 def test_register_constructor_requiring_nonconst_then_requiring_const_declaring_const_requirement_error(self): 485 source = ''' 486 struct X {}; 487 488 struct Y { 489 Y(X&) {} 490 }; 491 492 struct Z { 493 Z(const X&) {} 494 }; 495 496 fruit::Component<fruit::Required<const X>, Y, Z> getRootComponent() { 497 return fruit::createComponent() 498 .registerConstructor<Y(X&)>() 499 .registerConstructor<Z(const X&)>(); 500 } 501 ''' 502 expect_compile_error( 503 'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<X>', 504 'The type T was declared as a const Required type in the returned Component, however', 505 COMMON_DEFINITIONS, 506 source, 507 locals()) 508 509 def test_register_constructor_requiring_const_then_requiring_nonconst_ok(self): 510 source = ''' 511 struct X {}; 512 513 struct Y { 514 Y(const X&) {} 515 }; 516 517 struct Z { 518 Z(X&) {} 519 }; 520 521 fruit::Component<Y, Z> getRootComponent() { 522 return fruit::createComponent() 523 .registerConstructor<Y(const X&)>() 524 .registerConstructor<Z(X&)>() 525 .registerConstructor<X()>(); 526 } 527 528 int main() { 529 fruit::Injector<Y, Z> injector(getRootComponent); 530 injector.get<Y>(); 531 injector.get<Z>(); 532 } 533 ''' 534 expect_success( 535 COMMON_DEFINITIONS, 536 source, 537 locals()) 538 539 def test_register_constructor_requiring_const_then_requiring_nonconst_declaring_const_requirement_error(self): 540 source = ''' 541 struct X {}; 542 543 struct Y { 544 Y(const X&) {} 545 }; 546 547 struct Z { 548 Z(X&) {} 549 }; 550 551 fruit::Component<fruit::Required<const X>, Y, Z> getRootComponent() { 552 return fruit::createComponent() 553 .registerConstructor<Y(const X&)>() 554 .registerConstructor<Z(X&)>(); 555 } 556 ''' 557 expect_compile_error( 558 'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<X>', 559 'The type T was declared as a const Required type in the returned Component, however', 560 COMMON_DEFINITIONS, 561 source, 562 locals()) 563 564 @parameterized.parameters([ 565 ('Y**', r'Y\*\*'), 566 ('std::shared_ptr<Y>*', r'std::shared_ptr<Y>\*'), 567 ('std::nullptr_t', r'(std::)?nullptr(_t)?'), 568 ('Y*&', r'Y\*&'), 569 ('Y(*)()', r'Y(\((__cdecl)?\*\))?\((void)?\)'), 570 ('fruit::Annotated<Annotation1, Y**>', r'Y\*\*'), 571 ]) 572 def test_register_constructor_with_param_error_type_not_injectable(self, YVariant, YVariantRegex): 573 source = ''' 574 struct Y {}; 575 struct X { 576 X(YVariant); 577 }; 578 579 fruit::Component<> getComponent() { 580 return fruit::createComponent() 581 .registerConstructor<X(YVariant)>(); 582 } 583 ''' 584 expect_compile_error( 585 'NonInjectableTypeError<YVariantRegex>', 586 'The type T is not injectable.', 587 COMMON_DEFINITIONS, 588 source, 589 locals()) 590 591 def test_register_constructor_error_assisted_param(self): 592 source = ''' 593 struct X { 594 INJECT(X(ASSISTED(double) factor)) { 595 (void) factor; 596 } 597 }; 598 599 fruit::Component<X> getComponent() { 600 return fruit::createComponent() 601 .registerConstructor<X(fruit::Assisted<double>)>(); 602 } 603 ''' 604 expect_compile_error( 605 'AssistedParamInRegisterConstructorSignatureError<X\\(fruit::Assisted<double>\\)>', 606 'CandidateSignature was used as signature for a registerConstructor.* but it contains an assisted parameter.', 607 COMMON_DEFINITIONS, 608 source, 609 locals()) 610 611 def test_implicit_register_constructor_error_assisted_param(self): 612 source = ''' 613 struct X { 614 INJECT(X(ASSISTED(double) factor)) { 615 (void) factor; 616 } 617 }; 618 619 fruit::Component<X> getComponent() { 620 return fruit::createComponent(); 621 } 622 ''' 623 expect_compile_error( 624 'AssistedParamInRegisterConstructorSignatureError<X\\(fruit::Assisted<double>\\)>', 625 'CandidateSignature was used as signature for a registerConstructor.* but it contains an assisted parameter.', 626 COMMON_DEFINITIONS, 627 source, 628 locals()) 629 630 631 632if __name__ == '__main__': 633 absltest.main() 634