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