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 Annotation1 {}; 23 struct Annotation2 {}; 24 25 template <typename T> 26 using WithNoAnnot = T; 27 28 template <typename T> 29 using WithAnnot1 = fruit::Annotated<Annotation1, T>; 30 ''' 31 32class TestMultibindingsBindProvider(parameterized.TestCase): 33 @parameterized.parameters([ 34 'X()', 35 'new X()', 36 ]) 37 def test_bind_multibinding_provider_success(self, ConstructX): 38 source = ''' 39 struct X : public ConstructionTracker<X> { 40 INJECT(X()) = default; 41 }; 42 43 fruit::Component<> getComponent() { 44 return fruit::createComponent() 45 .addMultibindingProvider([](){return ConstructX;}); 46 } 47 48 int main() { 49 fruit::Injector<> injector(getComponent); 50 51 Assert(X::num_objects_constructed == 0); 52 Assert(injector.getMultibindings<X>().size() == 1); 53 Assert(X::num_objects_constructed == 1); 54 } 55 ''' 56 expect_success( 57 COMMON_DEFINITIONS, 58 source, 59 locals()) 60 61 @parameterized.parameters([ 62 'WithNoAnnot', 63 'WithAnnot1', 64 ]) 65 def test_bind_multibinding_provider_abstract_class_success(self, WithAnnot): 66 source = ''' 67 struct I { 68 virtual int foo() = 0; 69 virtual ~I() = default; 70 }; 71 72 struct X : public I { 73 int foo() override { 74 return 5; 75 } 76 }; 77 78 fruit::Component<> getComponent() { 79 return fruit::createComponent() 80 .addMultibindingProvider<WithAnnot<I*>()>([](){return static_cast<I*>(new X());}); 81 } 82 83 int main() { 84 fruit::Injector<> injector(getComponent); 85 86 Assert(injector.getMultibindings<WithAnnot<I>>().size() == 1); 87 Assert(injector.getMultibindings<WithAnnot<I>>()[0]->foo() == 5); 88 } 89 ''' 90 expect_success( 91 COMMON_DEFINITIONS, 92 source, 93 locals()) 94 95 @parameterized.parameters([ 96 'WithNoAnnot', 97 'WithAnnot1', 98 ]) 99 def test_bind_multibinding_provider_abstract_class_with_no_virtual_destructor_error(self, WithAnnot): 100 source = ''' 101 struct I { 102 virtual int foo() = 0; 103 }; 104 105 struct X : public I { 106 int foo() override { 107 return 5; 108 } 109 }; 110 111 fruit::Component<> getComponent() { 112 return fruit::createComponent() 113 .addMultibindingProvider<WithAnnot<I*>()>([](){return static_cast<I*>(new X());}); 114 } 115 ''' 116 expect_compile_error( 117 'MultibindingProviderReturningPointerToAbstractClassWithNoVirtualDestructorError<I>', 118 r'registerMultibindingProvider\(\) was called with a lambda that returns a pointer to T, but T is an abstract class with no virtual destructor', 119 COMMON_DEFINITIONS, 120 source, 121 locals()) 122 123 @multiple_parameters([ 124 ('X()', 'X'), 125 ('new X()', 'X*'), 126 ], [ 127 'WithNoAnnot', 128 'WithAnnot1', 129 ], [ 130 'Y', 131 'const Y', 132 'Y*', 133 'const Y*', 134 'Y&', 135 'const Y&', 136 'std::shared_ptr<Y>', 137 'fruit::Provider<Y>', 138 'fruit::Provider<const Y>', 139 ]) 140 def test_bind_multibinding_provider_with_param_success(self, ConstructX, XPtr, WithAnnot, YVariant): 141 source = ''' 142 struct Y {}; 143 144 struct X : public ConstructionTracker<X> {}; 145 146 fruit::Component<WithAnnot<Y>> getYComponent() { 147 return fruit::createComponent() 148 .registerConstructor<WithAnnot<Y>()>(); 149 } 150 151 fruit::Component<> getComponent() { 152 return fruit::createComponent() 153 .install(getYComponent) 154 .addMultibindingProvider<XPtr(WithAnnot<YVariant>)>([](YVariant){ return ConstructX; }); 155 } 156 157 int main() { 158 fruit::Injector<> injector(getComponent); 159 160 Assert(X::num_objects_constructed == 0); 161 Assert(injector.getMultibindings<X>().size() == 1); 162 Assert(X::num_objects_constructed == 1); 163 } 164 ''' 165 expect_success( 166 COMMON_DEFINITIONS, 167 source, 168 locals()) 169 170 @multiple_parameters([ 171 ('X()', 'X'), 172 ('new X()', 'X*'), 173 ], [ 174 'WithNoAnnot', 175 'WithAnnot1', 176 ], [ 177 'Y', 178 'const Y', 179 'const Y*', 180 'const Y&', 181 'fruit::Provider<const Y>', 182 ]) 183 def test_bind_multibinding_provider_with_param_const_binding_success(self, ConstructX, XPtr, WithAnnot, YVariant): 184 source = ''' 185 struct Y {}; 186 187 struct X : public ConstructionTracker<X> {}; 188 189 const Y y{}; 190 191 fruit::Component<WithAnnot<const Y>> getYComponent() { 192 return fruit::createComponent() 193 .bindInstance<WithAnnot<Y>, Y>(y); 194 } 195 196 fruit::Component<> getComponent() { 197 return fruit::createComponent() 198 .install(getYComponent) 199 .addMultibindingProvider<XPtr(WithAnnot<YVariant>)>([](YVariant){ return ConstructX; }); 200 } 201 202 int main() { 203 fruit::Injector<> injector(getComponent); 204 205 Assert(X::num_objects_constructed == 0); 206 Assert(injector.getMultibindings<X>().size() == 1); 207 Assert(X::num_objects_constructed == 1); 208 } 209 ''' 210 expect_success( 211 COMMON_DEFINITIONS, 212 source, 213 locals()) 214 215 @multiple_parameters([ 216 ('X()', 'X'), 217 ('new X()', 'X*'), 218 ], [ 219 ('WithNoAnnot', 'Y'), 220 ('WithAnnot1', 'fruit::Annotated<Annotation1, Y>'), 221 ], [ 222 'Y*', 223 'Y&', 224 'std::shared_ptr<Y>', 225 'fruit::Provider<Y>', 226 ]) 227 def test_bind_multibinding_provider_with_param_error_nonconst_param_required(self, ConstructX, XPtr, WithAnnot, YAnnotRegex, YVariant): 228 source = ''' 229 struct Y {}; 230 struct X {}; 231 232 fruit::Component<WithAnnot<const Y>> getYComponent(); 233 234 fruit::Component<> getComponent() { 235 return fruit::createComponent() 236 .install(getYComponent) 237 .addMultibindingProvider<XPtr(WithAnnot<YVariant>)>([](YVariant){ return ConstructX; }); 238 } 239 ''' 240 expect_compile_error( 241 'NonConstBindingRequiredButConstBindingProvidedError<YAnnotRegex>', 242 'The type T was provided as constant, however one of the constructors/providers/factories in this component', 243 COMMON_DEFINITIONS, 244 source, 245 locals()) 246 247 @multiple_parameters([ 248 ('X()', 'X'), 249 ('new X()', 'X*'), 250 ], [ 251 ('WithNoAnnot', 'Y'), 252 ('WithAnnot1', 'fruit::Annotated<Annotation1, Y>'), 253 ], [ 254 'Y*', 255 'Y&', 256 'std::shared_ptr<Y>', 257 'fruit::Provider<Y>', 258 ]) 259 def test_bind_multibinding_provider_with_param_error_nonconst_param_required_install_after(self, ConstructX, XPtr, WithAnnot, YAnnotRegex, YVariant): 260 source = ''' 261 struct Y {}; 262 struct X {}; 263 264 fruit::Component<WithAnnot<const Y>> getYComponent(); 265 266 fruit::Component<> getComponent() { 267 return fruit::createComponent() 268 .addMultibindingProvider<XPtr(WithAnnot<YVariant>)>([](YVariant){ return ConstructX; }) 269 .install(getYComponent); 270 } 271 ''' 272 expect_compile_error( 273 'NonConstBindingRequiredButConstBindingProvidedError<YAnnotRegex>', 274 'The type T was provided as constant, however one of the constructors/providers/factories in this component', 275 COMMON_DEFINITIONS, 276 source, 277 locals()) 278 279 def test_bind_multibinding_provider_requiring_nonconst_then_requiring_const_ok(self): 280 source = ''' 281 struct X {}; 282 struct Y {}; 283 284 fruit::Component<> getRootComponent() { 285 return fruit::createComponent() 286 .addMultibindingProvider([](X&) { return Y(); }) 287 .addMultibindingProvider([](const X&) { return Y(); }) 288 .registerConstructor<X()>(); 289 } 290 291 int main() { 292 fruit::Injector<> injector(getRootComponent); 293 injector.getMultibindings<Y>(); 294 } 295 ''' 296 expect_success( 297 COMMON_DEFINITIONS, 298 source, 299 locals()) 300 301 def test_bind_multibinding_provider_requiring_nonconst_then_requiring_const_declaring_const_requirement_error(self): 302 source = ''' 303 struct X {}; 304 struct Y {}; 305 306 fruit::Component<fruit::Required<const X>> getRootComponent() { 307 return fruit::createComponent() 308 .addMultibindingProvider([](X&) { return Y(); }) 309 .addMultibindingProvider([](const X&) { return Y(); }); 310 } 311 ''' 312 expect_compile_error( 313 'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<X>', 314 'The type T was declared as a const Required type in the returned Component, however', 315 COMMON_DEFINITIONS, 316 source, 317 locals()) 318 319 def test_bind_multibinding_provider_requiring_const_then_requiring_nonconst_ok(self): 320 source = ''' 321 struct X {}; 322 struct Y {}; 323 324 fruit::Component<> getRootComponent() { 325 return fruit::createComponent() 326 .addMultibindingProvider([](const X&) { return Y(); }) 327 .addMultibindingProvider([](X&) { return Y(); }) 328 .registerConstructor<X()>(); 329 } 330 331 int main() { 332 fruit::Injector<> injector(getRootComponent); 333 injector.getMultibindings<Y>(); 334 } 335 ''' 336 expect_success( 337 COMMON_DEFINITIONS, 338 source, 339 locals()) 340 341 def test_bind_multibinding_provider_requiring_const_then_requiring_nonconst_declaring_const_requirement_error(self): 342 source = ''' 343 struct X {}; 344 struct Y {}; 345 346 fruit::Component<fruit::Required<const X>> getRootComponent() { 347 return fruit::createComponent() 348 .addMultibindingProvider([](const X&) { return Y(); }) 349 .addMultibindingProvider([](X&) { return Y(); }); 350 } 351 ''' 352 expect_compile_error( 353 'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<X>', 354 'The type T was declared as a const Required type in the returned Component, however', 355 COMMON_DEFINITIONS, 356 source, 357 locals()) 358 359 @multiple_parameters([ 360 ('X()', 'X'), 361 ('new X()', 'X*'), 362 ], [ 363 ('Y', 'Y', 'Y**', r'Y\*\*'), 364 ('Y', 'Y', 'std::shared_ptr<Y>*', r'std::shared_ptr<Y>\*'), 365 ('Y', 'const Y', 'Y**', r'Y\*\*'), 366 ('Y', 'const Y', 'std::shared_ptr<Y>*', r'std::shared_ptr<Y>\*'), 367 ('fruit::Annotated<Annotation1, Y>', 'fruit::Annotated<Annotation1, Y>', 'Y**', r'Y\*\*'), 368 ('fruit::Annotated<Annotation1, Y>', 'fruit::Annotated<Annotation1, const Y>', 'Y**', r'Y\*\*'), 369 ]) 370 def test_bind_multibinding_provider_with_param_error_type_not_injectable(self, ConstructX, XPtr, YAnnot, ConstYAnnot, YVariant, YVariantRegex): 371 source = ''' 372 struct Y {}; 373 struct X {}; 374 375 fruit::Component<> getComponent() { 376 return fruit::createComponent() 377 .addMultibindingProvider<XPtr(YVariant)>([](YVariant){ return ConstructX; }); 378 } 379 ''' 380 expect_compile_error( 381 'NonInjectableTypeError<YVariantRegex>', 382 'The type T is not injectable.', 383 COMMON_DEFINITIONS, 384 source, 385 locals()) 386 387 @parameterized.parameters([ 388 ('X()', 'X', 'X'), 389 ('X()', 'fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'), 390 ('new X()', 'X', 'X*'), 391 ('new X()', 'fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X*>'), 392 ]) 393 def test_bind_multibinding_provider_explicit_signature_success(self, ConstructX, XAnnot, XPtrAnnot): 394 source = ''' 395 struct X : public ConstructionTracker<X> { 396 INJECT(X()) = default; 397 398 static bool constructed; 399 }; 400 401 fruit::Component<> getComponent() { 402 return fruit::createComponent() 403 .addMultibindingProvider<XPtrAnnot()>([](){return ConstructX;}); 404 } 405 406 int main() { 407 fruit::Injector<> injector(getComponent); 408 409 Assert(X::num_objects_constructed == 0); 410 Assert(injector.getMultibindings<XAnnot>().size() == 1); 411 Assert(X::num_objects_constructed == 1); 412 } 413 ''' 414 expect_success( 415 COMMON_DEFINITIONS, 416 source, 417 locals()) 418 419 @parameterized.parameters([ 420 ('X()', 'X', 'X'), 421 ('X()', 'fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'), 422 ('new X()', 'X', 'X*'), 423 ('new X()', 'fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X*>'), 424 ]) 425 def test_bind_multibinding_provider_explicit_signature_with_normalized_component_success(self, ConstructX, XAnnot, XPtrAnnot): 426 source = ''' 427 struct X : public ConstructionTracker<X> { 428 INJECT(X()) = default; 429 430 static bool constructed; 431 }; 432 433 fruit::Component<> getComponent() { 434 return fruit::createComponent() 435 .addMultibindingProvider<XPtrAnnot()>([](){return ConstructX;}); 436 } 437 438 fruit::Component<> getEmptyComponent() { 439 return fruit::createComponent(); 440 } 441 442 int main() { 443 fruit::NormalizedComponent<> normalizedComponent(getComponent); 444 fruit::Injector<> injector(normalizedComponent, getEmptyComponent); 445 446 Assert(X::num_objects_constructed == 0); 447 Assert(injector.getMultibindings<XAnnot>().size() == 1); 448 Assert(X::num_objects_constructed == 1); 449 } 450 ''' 451 expect_success( 452 COMMON_DEFINITIONS, 453 source, 454 locals()) 455 456 @parameterized.parameters([ 457 ('X', 'X*', 'int'), 458 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X*>', 'fruit::Annotated<Annotation2, int>'), 459 ]) 460 def test_multiple_providers(self, XAnnot, XPtrAnnot, intAnnot): 461 source = ''' 462 struct X {}; 463 464 fruit::Component<> getComponent() { 465 return fruit::createComponent() 466 .registerProvider<intAnnot()>([](){return 42;}) 467 .addMultibindingProvider<XAnnot(intAnnot)>([](int){return X();}) 468 .addMultibindingProvider<XPtrAnnot(intAnnot)>([](int){return new X();}); 469 } 470 471 int main() { 472 fruit::Injector<> injector(getComponent); 473 474 std::vector<X*> multibindings = injector.getMultibindings<XAnnot>(); 475 Assert(multibindings.size() == 2); 476 } 477 ''' 478 expect_success( 479 COMMON_DEFINITIONS, 480 source, 481 locals()) 482 483 @multiple_parameters([ 484 'X()', 485 'new X()', 486 ], [ 487 'X', 488 'fruit::Annotated<Annotation1, X>', 489 ]) 490 def test_bind_multibinding_provider_malformed_signature(self, ConstructX, XAnnot): 491 source = ''' 492 struct X {}; 493 494 fruit::Component<> getComponent() { 495 return fruit::createComponent() 496 .addMultibindingProvider<XAnnot>([](){return ConstructX;}); 497 } 498 ''' 499 expect_compile_error( 500 'NotASignatureError<XAnnot>', 501 'CandidateSignature was specified as parameter, but it.s not a signature.', 502 COMMON_DEFINITIONS, 503 source, 504 locals()) 505 506 @multiple_parameters([ 507 'X(n)', 508 'new X(n)', 509 ], [ 510 'X', 511 'fruit::Annotated<Annotation1, X>', 512 ]) 513 def test_bind_multibinding_provider_lambda_with_captures_error(self, ConstructX, XAnnot): 514 source = ''' 515 struct X { 516 X(int) {} 517 }; 518 519 fruit::Component<> getComponent() { 520 int n = 3; 521 return fruit::createComponent() 522 .addMultibindingProvider<XAnnot()>([=]{return ConstructX;}); 523 } 524 ''' 525 expect_compile_error( 526 'FunctorUsedAsProviderError<.*>', 527 'A stateful lambda or a non-lambda functor was used as provider', 528 COMMON_DEFINITIONS, 529 source, 530 locals()) 531 532 # TODO: should XPtrAnnot be just XAnnot in the signature? 533 # Make sure the behavior here is consistent with registerProvider() and registerFactory(). 534 @parameterized.parameters([ 535 ('X', 'X*', '(struct )?X'), 536 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X*>', '(struct )?fruit::Annotated<(struct )?Annotation1, ?(struct )?X>'), 537 ]) 538 def test_provider_returns_nullptr_error(self, XAnnot, XPtrAnnot, XAnnotRegex): 539 source = ''' 540 struct X {}; 541 542 fruit::Component<> getComponent() { 543 return fruit::createComponent() 544 .addMultibindingProvider<XPtrAnnot()>([](){return (X*)nullptr;}); 545 } 546 547 int main() { 548 fruit::Injector<> injector(getComponent); 549 injector.getMultibindings<XAnnot>(); 550 } 551 ''' 552 expect_runtime_error( 553 'Fatal injection error: attempting to get an instance for the type XAnnotRegex but the provider returned nullptr', 554 COMMON_DEFINITIONS, 555 source, 556 locals()) 557 558if __name__ == '__main__': 559 absltest.main() 560