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 fruit_test_common import * 17 18COMMON_DEFINITIONS = ''' 19 #include "test_common.h" 20 21 struct Listener; 22 23 struct X {}; 24 25 struct Annotation {}; 26 struct Annotation1 {}; 27 using ListenerAnnot = fruit::Annotated<Annotation, Listener>; 28 ''' 29 30def test_get_none(): 31 source = ''' 32 fruit::Component<> getComponent() { 33 return fruit::createComponent(); 34 } 35 36 int main() { 37 fruit::Injector<> injector(getComponent); 38 39 std::vector<X*> multibindings = injector.getMultibindings<X>(); 40 (void) multibindings; 41 Assert(multibindings.empty()); 42 } 43 ''' 44 expect_success( 45 COMMON_DEFINITIONS, 46 source) 47 48def test_multiple_various_kinds(): 49 source = ''' 50 static int numNotificationsToListener1 = 0; 51 static int numNotificationsToListener2 = 0; 52 static int numNotificationsToListener3 = 0; 53 54 struct Listener { 55 public: 56 virtual ~Listener() = default; 57 58 virtual void notify() = 0; 59 }; 60 61 struct Listener1 : public Listener { 62 public: 63 INJECT(Listener1()) = default; 64 65 virtual ~Listener1() = default; 66 67 void notify() override { 68 ++numNotificationsToListener1; 69 } 70 }; 71 72 struct Writer { 73 public: 74 virtual void write(std::string s) = 0; 75 }; 76 77 struct StdoutWriter : public Writer { 78 public: 79 INJECT(StdoutWriter()) = default; 80 81 void write(std::string s) override { 82 std::cout << s << std::endl; 83 } 84 }; 85 86 struct Listener2 : public Listener { 87 private: 88 Writer* writer; 89 90 public: 91 INJECT(Listener2(Writer* writer)) 92 : writer(writer) { 93 } 94 95 virtual ~Listener2() = default; 96 97 void notify() override { 98 (void) writer; 99 ++numNotificationsToListener2; 100 } 101 }; 102 103 struct Listener3 : public Listener { 104 private: 105 Writer* writer; 106 107 public: 108 INJECT(Listener3(Writer* writer)) 109 : writer(writer) { 110 } 111 112 virtual ~Listener3() = default; 113 114 void notify() override { 115 (void) writer; 116 ++numNotificationsToListener3; 117 } 118 }; 119 120 fruit::Component<> getListenersComponent() { 121 return fruit::createComponent() 122 .bind<Writer, StdoutWriter>() 123 // Note: this is just to exercise the other method, but in real code you should split this in 124 // an addMultibinding<Listener, Listener1> and a registerProvider with the lambda. 125 .addMultibindingProvider([]() { 126 Listener1* listener1 = new Listener1(); 127 return static_cast<Listener*>(listener1); 128 }) 129 .addMultibinding<Listener, Listener2>() 130 .addMultibinding<ListenerAnnot, Listener3>(); 131 } 132 133 int main() { 134 fruit::Injector<> injector(getListenersComponent); 135 std::vector<Listener*> listeners = injector.getMultibindings<Listener>(); 136 for (Listener* listener : listeners) { 137 listener->notify(); 138 } 139 140 std::vector<Listener*> listeners2 = injector.getMultibindings<Listener>(); 141 Assert(listeners == listeners2); 142 143 if (numNotificationsToListener1 != 1 || numNotificationsToListener2 != 1 144 || numNotificationsToListener3 != 0) { 145 abort(); 146 } 147 148 std::vector<Listener*> listenersWithAnnotation = injector.getMultibindings<ListenerAnnot>(); 149 for (Listener* listener : listenersWithAnnotation) { 150 listener->notify(); 151 } 152 153 if (numNotificationsToListener1 != 1 || numNotificationsToListener2 != 1 154 || numNotificationsToListener3 != 1) { 155 abort(); 156 } 157 } 158 ''' 159 expect_success( 160 COMMON_DEFINITIONS, 161 source) 162 163def test_order(): 164 source = ''' 165 std::vector<int> numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; 166 // * 167 // |-- 0 168 // |-- A 169 // | |-- 1 170 // | |-- B 171 // | | |-- 2 172 // | | `-- 3 173 // | |-- 4 174 // | |-- C 175 // | | |-- 5 176 // | | |-- 6 177 // | | |-- D 178 // | | | |-- 7 179 // | | | |-- E 180 // | | | | |-- 8 181 // | | | | `-- 9 182 // | | | `-- 10 183 // | | |-- 11 184 // | | |-- F 185 // | | | |-- 12 186 // | | | `-- 13 187 // | | `-- 14 188 // | |-- 15 189 // | |-- C (won't be expanded) 190 // | `-- 16 191 // |-- 17 192 // |-- C (won't be expanded) 193 // `-- 18 194 195 fruit::Component<> getRootComponent(); 196 fruit::Component<> getComponentA(); 197 fruit::Component<> getComponentB(); 198 fruit::Component<> getComponentC(); 199 fruit::Component<> getComponentD(); 200 fruit::Component<> getComponentE(); 201 fruit::Component<> getComponentF(); 202 203 fruit::Component<> getRootComponent() { 204 return fruit::createComponent() 205 .addInstanceMultibinding(numbers[0]) 206 .install(getComponentA) 207 .addInstanceMultibinding(numbers[17]) 208 .install(getComponentC) 209 .addInstanceMultibinding(numbers[18]); 210 } 211 212 fruit::Component<> getComponentA() { 213 return fruit::createComponent() 214 .addInstanceMultibinding(numbers[1]) 215 .install(getComponentB) 216 .addInstanceMultibinding(numbers[4]) 217 .install(getComponentC) 218 .addInstanceMultibinding(numbers[15]) 219 .install(getComponentC) 220 .addInstanceMultibinding(numbers[16]); 221 } 222 223 fruit::Component<> getComponentB() { 224 return fruit::createComponent() 225 .addInstanceMultibinding(numbers[2]) 226 .addInstanceMultibinding(numbers[3]); 227 } 228 229 fruit::Component<> getComponentC() { 230 return fruit::createComponent() 231 .addInstanceMultibinding(numbers[5]) 232 .addInstanceMultibinding(numbers[6]) 233 .install(getComponentD) 234 .addInstanceMultibinding(numbers[11]) 235 .install(getComponentF) 236 .addInstanceMultibinding(numbers[14]); 237 } 238 239 fruit::Component<> getComponentD() { 240 return fruit::createComponent() 241 .addInstanceMultibinding(numbers[7]) 242 .install(getComponentE) 243 .addInstanceMultibinding(numbers[10]); 244 } 245 246 fruit::Component<> getComponentE() { 247 return fruit::createComponent() 248 .addInstanceMultibinding(numbers[8]) 249 .addInstanceMultibinding(numbers[9]); 250 } 251 252 fruit::Component<> getComponentF() { 253 return fruit::createComponent() 254 .addInstanceMultibinding(numbers[12]) 255 .addInstanceMultibinding(numbers[13]); 256 } 257 258 int main() { 259 fruit::Injector<> injector(getRootComponent); 260 std::vector<int*> result_ptrs = injector.getMultibindings<int>(); 261 std::vector<int> results; 262 std::cout << "Results: "; 263 for (int* result : result_ptrs) { 264 std::cout << *result << ", "; 265 results.push_back(*result); 266 } 267 std::cout << std::endl; 268 Assert(results == numbers); 269 } 270 ''' 271 expect_success( 272 COMMON_DEFINITIONS, 273 source) 274 275 276def test_order_with_normalized_component(): 277 source = ''' 278 std::vector<int> numbers = { 279 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 280 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37}; 281 // root1 282 // |-- 0 283 // |-- A 284 // | |-- 1 285 // | |-- B 286 // | | |-- 2 287 // | | `-- 3 288 // | |-- 4 289 // | |-- C 290 // | | |-- 5 291 // | | |-- 6 292 // | | |-- D 293 // | | | |-- 7 294 // | | | |-- E 295 // | | | | |-- 8 296 // | | | | `-- 9 297 // | | | `-- 10 298 // | | |-- 11 299 // | | |-- F 300 // | | | |-- 12 301 // | | | `-- 13 302 // | | `-- 14 303 // | |-- 15 304 // | |-- C (won't be expanded) 305 // | `-- 16 306 // |-- 17 307 // |-- C (won't be expanded) 308 // `-- 18 309 310 // root2 311 // |-- 19 312 // |-- A2 313 // | |-- 20 314 // | |-- B2 315 // | | |-- 21 316 // | | `-- 22 317 // | |-- 23 318 // | |-- C2 319 // | | |-- 24 320 // | | |-- 25 321 // | | |-- D2 322 // | | | |-- 26 323 // | | | |-- E2 324 // | | | | |-- 27 325 // | | | | `-- 28 326 // | | | `-- 29 327 // | | |-- 30 328 // | | |-- F2 329 // | | | |-- 31 330 // | | | `-- 32 331 // | | `-- 33 332 // | |-- 34 333 // | |-- C2 (won't be expanded) 334 // | `-- 35 335 // |-- 36 336 // |-- C2 (won't be expanded) 337 // `-- 37 338 339 fruit::Component<> getRootComponent(); 340 fruit::Component<> getComponentA(); 341 fruit::Component<> getComponentB(); 342 fruit::Component<> getComponentC(); 343 fruit::Component<> getComponentD(); 344 fruit::Component<> getComponentE(); 345 fruit::Component<> getComponentF(); 346 347 fruit::Component<> getRootComponent2(); 348 fruit::Component<> getComponentA2(); 349 fruit::Component<> getComponentB2(); 350 fruit::Component<> getComponentC2(); 351 fruit::Component<> getComponentD2(); 352 fruit::Component<> getComponentE2(); 353 fruit::Component<> getComponentF2(); 354 355 fruit::Component<> getRootComponent() { 356 return fruit::createComponent() 357 .addInstanceMultibinding(numbers[0]) 358 .install(getComponentA) 359 .addInstanceMultibinding(numbers[17]) 360 .install(getComponentC) 361 .addInstanceMultibinding(numbers[18]); 362 } 363 364 fruit::Component<> getComponentA() { 365 return fruit::createComponent() 366 .addInstanceMultibinding(numbers[1]) 367 .install(getComponentB) 368 .addInstanceMultibinding(numbers[4]) 369 .install(getComponentC) 370 .addInstanceMultibinding(numbers[15]) 371 .install(getComponentC) 372 .addInstanceMultibinding(numbers[16]); 373 } 374 375 fruit::Component<> getComponentB() { 376 return fruit::createComponent() 377 .addInstanceMultibinding(numbers[2]) 378 .addInstanceMultibinding(numbers[3]); 379 } 380 381 fruit::Component<> getComponentC() { 382 return fruit::createComponent() 383 .addInstanceMultibinding(numbers[5]) 384 .addInstanceMultibinding(numbers[6]) 385 .install(getComponentD) 386 .addInstanceMultibinding(numbers[11]) 387 .install(getComponentF) 388 .addInstanceMultibinding(numbers[14]); 389 } 390 391 fruit::Component<> getComponentD() { 392 return fruit::createComponent() 393 .addInstanceMultibinding(numbers[7]) 394 .install(getComponentE) 395 .addInstanceMultibinding(numbers[10]); 396 } 397 398 fruit::Component<> getComponentE() { 399 return fruit::createComponent() 400 .addInstanceMultibinding(numbers[8]) 401 .addInstanceMultibinding(numbers[9]); 402 } 403 404 fruit::Component<> getComponentF() { 405 return fruit::createComponent() 406 .addInstanceMultibinding(numbers[12]) 407 .addInstanceMultibinding(numbers[13]); 408 } 409 410 fruit::Component<> getRootComponent2() { 411 return fruit::createComponent() 412 .addInstanceMultibinding(numbers[19]) 413 .install(getComponentA2) 414 .addInstanceMultibinding(numbers[36]) 415 .install(getComponentC2) 416 .addInstanceMultibinding(numbers[37]); 417 } 418 419 fruit::Component<> getComponentA2() { 420 return fruit::createComponent() 421 .addInstanceMultibinding(numbers[20]) 422 .install(getComponentB2) 423 .addInstanceMultibinding(numbers[23]) 424 .install(getComponentC2) 425 .addInstanceMultibinding(numbers[34]) 426 .install(getComponentC2) 427 .addInstanceMultibinding(numbers[35]); 428 } 429 430 fruit::Component<> getComponentB2() { 431 return fruit::createComponent() 432 .addInstanceMultibinding(numbers[21]) 433 .addInstanceMultibinding(numbers[22]); 434 } 435 436 fruit::Component<> getComponentC2() { 437 return fruit::createComponent() 438 .addInstanceMultibinding(numbers[24]) 439 .addInstanceMultibinding(numbers[25]) 440 .install(getComponentD2) 441 .addInstanceMultibinding(numbers[30]) 442 .install(getComponentF2) 443 .addInstanceMultibinding(numbers[33]); 444 } 445 446 fruit::Component<> getComponentD2() { 447 return fruit::createComponent() 448 .addInstanceMultibinding(numbers[26]) 449 .install(getComponentE2) 450 .addInstanceMultibinding(numbers[29]); 451 } 452 453 fruit::Component<> getComponentE2() { 454 return fruit::createComponent() 455 .addInstanceMultibinding(numbers[27]) 456 .addInstanceMultibinding(numbers[28]); 457 } 458 459 fruit::Component<> getComponentF2() { 460 return fruit::createComponent() 461 .addInstanceMultibinding(numbers[31]) 462 .addInstanceMultibinding(numbers[32]); 463 } 464 465 int main() { 466 fruit::NormalizedComponent<> normalizedComponent(getRootComponent); 467 fruit::Injector<> injector(normalizedComponent, getRootComponent2); 468 std::vector<int*> result_ptrs = injector.getMultibindings<int>(); 469 std::vector<int> results; 470 std::cout << "Results: "; 471 for (int* result : result_ptrs) { 472 std::cout << *result << ", "; 473 results.push_back(*result); 474 } 475 std::cout << std::endl; 476 Assert(results == numbers); 477 } 478 ''' 479 expect_success( 480 COMMON_DEFINITIONS, 481 source) 482 483def test_with_normalized_component_lazy_components_not_deduped_across(): 484 source = ''' 485 std::vector<int> numbers = {0, 1, 2, 3, 4}; 486 487 // * 488 // |-- 0 489 // |-- A (lazy) 490 // | |-- 1 491 // | `-- 2 492 // |-- 3 493 // |-- A (lazy, won't be expanded) 494 // `-- 4 495 496 fruit::Component<> getRootComponent(); 497 fruit::Component<> getComponentA(); 498 499 fruit::Component<> getRootComponent() { 500 return fruit::createComponent() 501 .addInstanceMultibinding(numbers[0]) 502 .install(getComponentA) 503 .addInstanceMultibinding(numbers[3]) 504 .install(getComponentA) 505 .addInstanceMultibinding(numbers[4]); 506 } 507 508 fruit::Component<> getComponentA() { 509 return fruit::createComponent() 510 .addInstanceMultibinding(numbers[1]) 511 .addInstanceMultibinding(numbers[2]); 512 } 513 514 int main() { 515 fruit::NormalizedComponent<> normalizedComponent(getRootComponent); 516 fruit::Injector<> injector(normalizedComponent, getRootComponent); 517 std::vector<int*> result_ptrs = injector.getMultibindings<int>(); 518 std::vector<int> results; 519 std::cout << "Results: "; 520 for (int* result : result_ptrs) { 521 std::cout << *result << ", "; 522 results.push_back(*result); 523 } 524 std::cout << std::endl; 525 std::vector<int> expected_numbers = {0, 1, 2, 3, 4}; 526 Assert(results == expected_numbers); 527 } 528 ''' 529 expect_success( 530 COMMON_DEFINITIONS, 531 source) 532 533@pytest.mark.parametrize('XVariantAnnot,XVariantRegexp', [ 534 ('const X', 'const X'), 535 ('X*', 'X\*'), 536 ('const X*', 'const X\*'), 537 ('std::shared_ptr<X>', 'std::shared_ptr<X>'), 538 ('fruit::Annotated<Annotation1, const X>', 'const X'), 539 ('fruit::Annotated<Annotation1, X*>', 'X\*'), 540 ('fruit::Annotated<Annotation1, const X*>', 'const X\*'), 541 ('fruit::Annotated<Annotation1, std::shared_ptr<X>>', 'std::shared_ptr<X>'), 542]) 543def test_multibindings_get_error_non_class_type(XVariantAnnot, XVariantRegexp): 544 source = ''' 545 void f(fruit::Injector<> injector) { 546 injector.getMultibindings<XVariantAnnot>(); 547 } 548 ''' 549 expect_compile_error( 550 'NonClassTypeError<XVariantRegexp,X>', 551 'A non-class type T was specified. Use C instead.', 552 COMMON_DEFINITIONS, 553 source, 554 locals()) 555 556@pytest.mark.parametrize('XVariantAnnot,XVariantRegexp', [ 557 ('X&', 'X&'), 558 ('const X&', 'const X&'), 559 ('fruit::Annotated<Annotation1, X&>', 'X&'), 560 ('fruit::Annotated<Annotation1, const X&>', 'const X&'), 561]) 562def test_multibindings_get_error_reference_type(XVariantAnnot, XVariantRegexp): 563 source = ''' 564 void f(fruit::Injector<> injector) { 565 injector.getMultibindings<XVariantAnnot>(); 566 } 567 ''' 568 expect_generic_compile_error( 569 'declared as a pointer to a reference of type' 570 '|forming pointer to reference type' 571 '|fruit::Injector<.*>::getMultibindings.: no matching overloaded function found', 572 COMMON_DEFINITIONS, 573 source, 574 locals()) 575 576if __name__== '__main__': 577 main(__file__) 578