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