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