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    '''
23
24class TestComponentReplacement(parameterized.TestCase):
25    @multiple_parameters([
26        ('', 'getReplacedComponent'),
27        ('double', 'getReplacedComponent, 1.0'),
28    ], [
29        ('', 'getReplacementComponent'),
30        ('std::string', 'getReplacementComponent, std::string("Hello, world")'),
31    ])
32    def test_replace_component_success(self,
33            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
34        source = '''
35            fruit::Component<int> getReplacedComponent(ReplacedComponentParamTypes) {
36              static int n = 10;
37              return fruit::createComponent()
38                  .bindInstance(n);
39            }
40
41            fruit::Component<int> getReplacementComponent(ReplacementComponentParamTypes) {
42              static int n = 20;
43              return fruit::createComponent()
44                  .bindInstance(n);
45            }
46
47            fruit::Component<int> getRootComponent() {
48              return fruit::createComponent()
49                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
50                  .install(ReplacedComponentInstallation);
51            }
52
53            int main() {
54              fruit::Injector<int> injector(getRootComponent);
55              int n = injector.get<int>();
56              Assert(n == 20);
57            }
58            '''
59        expect_success(
60            COMMON_DEFINITIONS,
61            source,
62            locals())
63
64    @multiple_parameters([
65        ('', 'getReplacedComponent'),
66        ('double', 'getReplacedComponent, 1.0'),
67    ], [
68        ('', 'getReplacementComponent'),
69        ('std::string', 'getReplacementComponent, std::string("Hello, world")'),
70    ])
71    def test_replace_component_success_across_normalized_component(self,
72            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
73        source = '''
74            fruit::Component<int> getReplacedComponent(ReplacedComponentParamTypes) {
75              static int n = 10;
76              return fruit::createComponent()
77                  .bindInstance(n);
78            }
79
80            fruit::Component<int> getReplacementComponent(ReplacementComponentParamTypes) {
81              static int n = 20;
82              return fruit::createComponent()
83                  .bindInstance(n);
84            }
85
86            fruit::Component<> getRootComponent1() {
87              return fruit::createComponent()
88                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation);
89            }
90
91            fruit::Component<int> getRootComponent2() {
92              return fruit::createComponent()
93                  .install(ReplacedComponentInstallation);
94            }
95
96            int main() {
97              fruit::NormalizedComponent<> normalizedComponent(getRootComponent1);
98              fruit::Injector<int> injector(normalizedComponent, getRootComponent2);
99              int n = injector.get<int>();
100              Assert(n == 20);
101            }
102            '''
103        expect_success(
104            COMMON_DEFINITIONS,
105            source,
106            locals())
107
108    @multiple_parameters([
109        ('', 'getReplacedComponent'),
110        ('double', 'getReplacedComponent, 1.0'),
111    ], [
112        ('', 'getReplacementComponent'),
113        ('std::string', 'getReplacementComponent, std::string("Hello, world")'),
114    ])
115    def test_replace_component_installed_using_component_function_success(self,
116            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
117        source = '''
118            fruit::Component<int> getReplacedComponent(ReplacedComponentParamTypes) {
119              static int n = 10;
120              return fruit::createComponent()
121                  .bindInstance(n);
122            }
123
124            fruit::Component<int> getReplacementComponent(ReplacementComponentParamTypes) {
125              static int n = 20;
126              return fruit::createComponent()
127                  .bindInstance(n);
128            }
129
130            fruit::Component<int> getRootComponent() {
131              return fruit::createComponent()
132                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
133                  .installComponentFunctions(fruit::componentFunction(ReplacedComponentInstallation));
134            }
135
136            int main() {
137              fruit::Injector<int> injector(getRootComponent);
138              int n = injector.get<int>();
139              Assert(n == 20);
140            }
141            '''
142        expect_success(
143            COMMON_DEFINITIONS,
144            source,
145            locals())
146
147    def test_replace_component_success_with_conversion(self):
148        source = '''
149            fruit::Component<int> getReplacedComponent(std::string) {
150              static int n = 10;
151              return fruit::createComponent()
152                  .bindInstance(n);
153            }
154
155            fruit::Component<int> getReplacementComponent(double, std::string, int) {
156              static int n = 20;
157              return fruit::createComponent()
158                  .bindInstance(n);
159            }
160
161            fruit::Component<int> getRootComponent() {
162              return fruit::createComponent()
163                  .replace(getReplacedComponent, "Hi").with(getReplacementComponent, 2.0, "Hello", 12)
164                  .install(getReplacedComponent, "Hi");
165            }
166
167            int main() {
168              fruit::Injector<int> injector(getRootComponent);
169              int n = injector.get<int>();
170              Assert(n == 20);
171            }
172            '''
173        expect_success(
174            COMMON_DEFINITIONS,
175            source,
176            locals())
177
178    def test_replace_component_installed_using_component_function_success_with_conversion(self):
179        source = '''
180            fruit::Component<int> getReplacedComponent(std::string) {
181              static int n = 10;
182              return fruit::createComponent()
183                  .bindInstance(n);
184            }
185
186            fruit::Component<int> getReplacementComponent(double, std::string, int) {
187              static int n = 20;
188              return fruit::createComponent()
189                  .bindInstance(n);
190            }
191
192            fruit::Component<int> getRootComponent() {
193              return fruit::createComponent()
194                  .replace(getReplacedComponent, "Hi").with(getReplacementComponent, 2.0, "Hello", 12)
195                  .installComponentFunctions(fruit::componentFunction(getReplacedComponent, "Hi"));
196            }
197
198            int main() {
199              fruit::Injector<int> injector(getRootComponent);
200              int n = injector.get<int>();
201              Assert(n == 20);
202            }
203            '''
204        expect_success(
205            COMMON_DEFINITIONS,
206            source,
207            locals())
208
209    @multiple_parameters([
210        ('', 'getReplacedComponent', 'getReplacementComponent', 'getReplacementReplacementComponent'),
211        ('double', 'getReplacedComponent, 1.0', 'getReplacementComponent, 1.0', 'getReplacementReplacementComponent, 1.0'),
212    ])
213    def test_replace_component_chain_success(self,
214            ComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentInstallation, ReplacementReplacementComponentInstallation):
215        source = '''
216            fruit::Component<int> getReplacedComponent(ComponentParamTypes) {
217              static int n = 10;
218              return fruit::createComponent()
219                  .bindInstance(n);
220            }
221
222            fruit::Component<int> getReplacementComponent(ComponentParamTypes) {
223              static int n = 20;
224              return fruit::createComponent()
225                  .bindInstance(n);
226            }
227
228            fruit::Component<int> getReplacementReplacementComponent(ComponentParamTypes) {
229              static int n = 30;
230              return fruit::createComponent()
231                  .bindInstance(n);
232            }
233
234            fruit::Component<int> getRootComponent() {
235              return fruit::createComponent()
236                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
237                  .replace(ReplacementComponentInstallation).with(ReplacementReplacementComponentInstallation)
238                  .install(ReplacedComponentInstallation);
239            }
240
241            int main() {
242              fruit::Injector<int> injector(getRootComponent);
243              int n = injector.get<int>();
244              Assert(n == 30);
245            }
246            '''
247        expect_success(
248            COMMON_DEFINITIONS,
249            source,
250            locals())
251
252    @multiple_parameters([
253        ('', 'getReplacedComponent', 'getReplacementComponent', 'getReplacementReplacementComponent'),
254        ('double', 'getReplacedComponent, 1.0', 'getReplacementComponent, 1.0', 'getReplacementReplacementComponent, 1.0'),
255    ])
256    def test_replace_component_chain_other_order_success(self,
257            ComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentInstallation, ReplacementReplacementComponentInstallation):
258        source = '''
259            fruit::Component<int> getReplacedComponent(ComponentParamTypes) {
260              static int n = 10;
261              return fruit::createComponent()
262                  .bindInstance(n);
263            }
264
265            fruit::Component<int> getReplacementComponent(ComponentParamTypes) {
266              static int n = 20;
267              return fruit::createComponent()
268                  .bindInstance(n);
269            }
270
271            fruit::Component<int> getReplacementReplacementComponent(ComponentParamTypes) {
272              static int n = 30;
273              return fruit::createComponent()
274                  .bindInstance(n);
275            }
276
277            fruit::Component<int> getRootComponent() {
278              return fruit::createComponent()
279                  .replace(ReplacementComponentInstallation).with(ReplacementReplacementComponentInstallation)
280                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
281                  .install(ReplacedComponentInstallation);
282            }
283
284            int main() {
285              fruit::Injector<int> injector(getRootComponent);
286              int n = injector.get<int>();
287              Assert(n == 30);
288            }
289            '''
290        expect_success(
291            COMMON_DEFINITIONS,
292            source,
293            locals())
294
295    def test_replace_component_different_type_error(self):
296        source = '''
297            fruit::Component<int> getReplacedComponent();
298            fruit::Component<double> getReplacementComponent();
299
300            fruit::Component<> getRootComponent() {
301              return fruit::createComponent()
302                  .replace(getReplacedComponent).with(getReplacementComponent);
303            }
304            '''
305        expect_generic_compile_error(
306            # Clang
307            r'candidate template ignored: could not match .Component<int>. against .Component<double>.'
308            # GCC
309            r'|mismatched types .int. and .double.'
310            # MSVC
311            r'|could not deduce template argument for .fruit::Component<int> \(__cdecl \*\)\(FormalArgs...\). from .fruit::Component<double> \(void\).',
312            COMMON_DEFINITIONS,
313            source)
314
315    @multiple_parameters([
316        ('', 'getReplacedComponent'),
317        ('double', 'getReplacedComponent, 1.0'),
318    ], [
319        ('', 'getReplacementComponent'),
320        ('std::string', 'getReplacementComponent, std::string("Hello, world")'),
321    ])
322    def test_replace_component_already_replaced_consistent_ok(self,
323            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
324        source = '''
325            fruit::Component<int> getReplacedComponent(ReplacedComponentParamTypes) {
326              static int n = 10;
327              return fruit::createComponent()
328                  .bindInstance(n);
329            }
330
331            fruit::Component<int> getReplacementComponent(ReplacementComponentParamTypes) {
332              static int n = 20;
333              return fruit::createComponent()
334                  .bindInstance(n);
335            }
336
337            fruit::Component<int> getRootComponent() {
338              return fruit::createComponent()
339                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
340                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
341                  .install(ReplacedComponentInstallation);
342            }
343
344            int main() {
345              fruit::Injector<int> injector(getRootComponent);
346              int n = injector.get<int>();
347              Assert(n == 20);
348            }
349            '''
350        expect_success(
351            COMMON_DEFINITIONS,
352            source,
353            locals())
354
355    @multiple_parameters([
356        ('', 'getReplacedComponent'),
357        ('double', 'getReplacedComponent, 1.0'),
358    ], [
359        ('', 'getReplacementComponent'),
360        ('std::string', 'getReplacementComponent, std::string("Hello, world")'),
361    ])
362    def test_replace_component_already_replaced_across_normalized_component_consistent_ok(self,
363            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
364        source = '''
365            fruit::Component<int> getReplacedComponent(ReplacedComponentParamTypes) {
366              static int n = 10;
367              return fruit::createComponent()
368                  .bindInstance(n);
369            }
370
371            fruit::Component<int> getReplacementComponent(ReplacementComponentParamTypes) {
372              static int n = 20;
373              return fruit::createComponent()
374                  .bindInstance(n);
375            }
376
377            fruit::Component<> getRootComponent1() {
378              return fruit::createComponent()
379                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation);
380            }
381
382            fruit::Component<int> getRootComponent2() {
383              return fruit::createComponent()
384                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
385                  .install(ReplacedComponentInstallation);
386            }
387
388            int main() {
389              fruit::NormalizedComponent<> normalizedComponent(getRootComponent1);
390              fruit::Injector<int> injector(normalizedComponent, getRootComponent2);
391              int n = injector.get<int>();
392              Assert(n == 20);
393            }
394            '''
395        expect_success(
396            COMMON_DEFINITIONS,
397            source,
398            locals())
399
400    @multiple_parameters([
401        ('', 'getReplacedComponent'),
402        ('double', 'getReplacedComponent, 1.0'),
403    ], [
404        ('', 'getReplacementComponent', 'getOtherReplacementComponent'),
405        ('std::string', 'getReplacementComponent, std::string("Hello, world")', 'getOtherReplacementComponent, std::string("Hello, world")'),
406    ])
407    def test_replace_component_already_replaced_inconsistent_error(self,
408            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation, OtherReplacementComponentInstallation):
409        source = '''
410            fruit::Component<int> getReplacedComponent(ReplacedComponentParamTypes) {
411              static int n = 10;
412              return fruit::createComponent()
413                  .bindInstance(n);
414            }
415
416            fruit::Component<int> getReplacementComponent(ReplacementComponentParamTypes) {
417              static int n = 20;
418              return fruit::createComponent()
419                  .bindInstance(n);
420            }
421
422            fruit::Component<int> getOtherReplacementComponent(ReplacementComponentParamTypes) {
423              static int n = 30;
424              return fruit::createComponent()
425                  .bindInstance(n);
426            }
427
428            fruit::Component<> getRootComponent() {
429              return fruit::createComponent()
430                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
431                  .replace(ReplacedComponentInstallation).with(OtherReplacementComponentInstallation);
432            }
433
434            int main() {
435              fruit::Injector<> injector(getRootComponent);
436              (void) injector;
437            }
438            '''
439        expect_runtime_error(
440            r'Fatal injection error: the component function at (0x)?[0-9a-fA-F]* with signature '
441            r'(class )?fruit::Component<int> \((__cdecl)?\*\)\((void)?ReplacedComponentParamTypes\) was replaced '
442            r'\(using .replace\(...\).with\(...\)\) with both the component function at (0x)?[0-9a-fA-F]* with signature '
443            r'(class )?fruit::Component<int> \((__cdecl)?\*\)\(.*\) and the component function at '
444            r'(0x)?[0-9a-fA-F]* with signature (class )?fruit::Component<int> \((__cdecl)?\*\)\(.*\) .',
445            COMMON_DEFINITIONS,
446            source,
447            locals())
448
449    @multiple_parameters([
450        ('', 'getReplacedComponent'),
451        ('double', 'getReplacedComponent, 1.0'),
452    ], [
453        ('', 'getReplacementComponent', 'getOtherReplacementComponent'),
454        ('std::string', 'getReplacementComponent, std::string("Hello, world")', 'getOtherReplacementComponent, std::string("Hello, world")'),
455    ])
456    def test_replace_component_already_replaced_across_normalized_component_inconsistent_error(self,
457            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation, OtherReplacementComponentInstallation):
458        source = '''
459            fruit::Component<int> getReplacedComponent(ReplacedComponentParamTypes) {
460              static int n = 10;
461              return fruit::createComponent()
462                  .bindInstance(n);
463            }
464
465            fruit::Component<int> getReplacementComponent(ReplacementComponentParamTypes) {
466              static int n = 20;
467              return fruit::createComponent()
468                  .bindInstance(n);
469            }
470
471            fruit::Component<int> getOtherReplacementComponent(ReplacementComponentParamTypes) {
472              static int n = 30;
473              return fruit::createComponent()
474                  .bindInstance(n);
475            }
476
477            fruit::Component<> getRootComponent1() {
478              return fruit::createComponent()
479                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation);
480            }
481
482            fruit::Component<> getRootComponent2() {
483              return fruit::createComponent()
484                  .replace(ReplacedComponentInstallation).with(OtherReplacementComponentInstallation);
485            }
486
487            int main() {
488              fruit::NormalizedComponent<> normalizedComponent(getRootComponent1);
489              fruit::Injector<> injector(normalizedComponent, getRootComponent2);
490              (void) injector;
491            }
492            '''
493        expect_runtime_error(
494            r'Fatal injection error: the component function at (0x)?[0-9a-fA-F]* with signature '
495            r'(class )?fruit::Component<int> \((__cdecl)?\*\)\((void)?ReplacedComponentParamTypes\) was replaced '
496            r'\(using .replace\(...\).with\(...\)\) with both the component function at (0x)?[0-9a-fA-F]* with signature '
497            r'(class )?fruit::Component<int> \((__cdecl)?\*\)\(.*\) and the component function at '
498            r'(0x)?[0-9a-fA-F]* with signature (class )?fruit::Component<int> \((__cdecl)?\*\)\(.*\) .',
499            COMMON_DEFINITIONS,
500            source,
501            locals())
502
503    @multiple_parameters([
504        ('', 'getReplacedComponent'),
505        ('double', 'getReplacedComponent, 1.0'),
506    ], [
507        ('', 'getReplacementComponent'),
508        ('std::string', 'getReplacementComponent, std::string("Hello, world")'),
509    ])
510    def test_replace_component_after_install_error(self,
511            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
512        source = '''
513            fruit::Component<int> getReplacedComponent(ReplacedComponentParamTypes) {
514              static int n = 10;
515              return fruit::createComponent()
516                  .bindInstance(n);
517            }
518
519            fruit::Component<int> getReplacementComponent(ReplacementComponentParamTypes) {
520              static int n = 20;
521              return fruit::createComponent()
522                  .bindInstance(n);
523            }
524
525            fruit::Component<int> getRootComponent() {
526              return fruit::createComponent()
527                  .install(ReplacedComponentInstallation)
528                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation);
529            }
530
531            int main() {
532              fruit::Injector<int> injector(getRootComponent);
533              (void) injector;
534            }
535            '''
536        expect_runtime_error(
537            r'Fatal injection error: unable to replace \(using .replace\(...\).with\(...\)\) the component function at '
538            r'(0x)?[0-9a-fA-F]* with signature (class )?fruit::Component<int> \((__cdecl)?\*\)\((void)?ReplacedComponentParamTypes\) with the '
539            r'component function at (0x)?[0-9a-fA-F]* with signature '
540            r'(class )?fruit::Component<int> \((__cdecl)?\*\)\(.*\) because the former component function '
541            r'was installed before the .replace\(...\).with\(...\).',
542            COMMON_DEFINITIONS,
543            source,
544            locals())
545
546    @multiple_parameters([
547        ('', 'getReplacedComponent'),
548        ('double', 'getReplacedComponent, 1.0'),
549    ], [
550        ('', 'getReplacementComponent'),
551        ('std::string', 'getReplacementComponent, std::string("Hello, world")'),
552    ])
553    def test_replace_component_after_install_across_normalized_component_error(self,
554            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
555        source = '''
556            fruit::Component<int> getReplacedComponent(ReplacedComponentParamTypes) {
557              static int n = 10;
558              return fruit::createComponent()
559                  .bindInstance(n);
560            }
561
562            fruit::Component<int> getReplacementComponent(ReplacementComponentParamTypes) {
563              static int n = 20;
564              return fruit::createComponent()
565                  .bindInstance(n);
566            }
567
568            fruit::Component<int> getRootComponent1() {
569              return fruit::createComponent()
570                  .install(ReplacedComponentInstallation);
571            }
572
573            fruit::Component<> getRootComponent2() {
574              return fruit::createComponent()
575                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation);
576            }
577
578            int main() {
579              fruit::NormalizedComponent<int> normalizedComponent(getRootComponent1);
580              fruit::Injector<int> injector(normalizedComponent, getRootComponent2);
581              (void) injector;
582            }
583            '''
584        expect_runtime_error(
585            r'Fatal injection error: unable to replace \(using .replace\(...\).with\(...\)\) the component function at '
586            r'(0x)?[0-9a-fA-F]* with signature (class )?fruit::Component<int> \((__cdecl)?\*\)\((void)?ReplacedComponentParamTypes\) with the '
587            r'component function at (0x)?[0-9a-fA-F]* with signature '
588            r'(class )?fruit::Component<int> \((__cdecl)?\*\)\(.*\) because the former component function '
589            r'was installed before the .replace\(...\).with\(...\).',
590            COMMON_DEFINITIONS,
591            source,
592            locals())
593
594    @parameterized.parameters([
595        ('', 'getReplacedComponent', '', 'getReplacementComponent'),
596        ('double', 'getReplacedComponent, 1.0', 'std::string', 'getReplacementComponent, std::string("Hello, world")'),
597    ])
598    def test_replace_component_unused_ok(self,
599            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
600        source = '''
601            fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) {
602              static int n = 10;
603              return fruit::createComponent()
604                  .addInstanceMultibinding(n);
605            }
606
607            fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) {
608              static int n = 20;
609              return fruit::createComponent()
610                  .addInstanceMultibinding(n);
611            }
612
613            fruit::Component<> getRootComponent() {
614              return fruit::createComponent()
615                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation);
616            }
617
618            int main() {
619              fruit::Injector<> injector(getRootComponent);
620
621              std::vector<int*> multibindings = injector.getMultibindings<int>();
622              Assert(multibindings.size() == 0);
623            }
624            '''
625        expect_success(
626            COMMON_DEFINITIONS,
627            source,
628            locals())
629
630    @multiple_parameters([
631        ('', 'getReplacedComponent'),
632        ('double', 'getReplacedComponent, 1.0'),
633    ], [
634        ('', 'getReplacementComponent'),
635        ('std::string', 'getReplacementComponent, std::string("Hello, world")'),
636    ])
637    def test_replace_component_used_multiple_times_ok(self,
638            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
639        source = '''
640            fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) {
641              static int n = 10;
642              return fruit::createComponent()
643                  .addInstanceMultibinding(n);
644            }
645
646            fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) {
647              static int n = 20;
648              return fruit::createComponent()
649                  .addInstanceMultibinding(n);
650            }
651
652            fruit::Component<> getRootComponent() {
653              return fruit::createComponent()
654                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
655                  .install(ReplacedComponentInstallation)
656                  .install(ReplacedComponentInstallation);
657            }
658
659            int main() {
660              fruit::Injector<> injector(getRootComponent);
661
662              std::vector<int*> multibindings = injector.getMultibindings<int>();
663              Assert(multibindings.size() == 1);
664              Assert(*(multibindings[0]) == 20);
665            }
666            '''
667        expect_success(
668            COMMON_DEFINITIONS,
669            source,
670            locals())
671
672    @multiple_parameters([
673        ('', 'getReplacedComponent'),
674        ('double', 'getReplacedComponent, 1.0'),
675    ], [
676        ('', 'getReplacementComponent'),
677        ('std::string', 'getReplacementComponent, std::string("Hello, world")'),
678    ])
679    def test_replace_component_also_installed_directly_before_ok(self,
680            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
681        source = '''
682            fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) {
683              static int n = 10;
684              return fruit::createComponent()
685                  .addInstanceMultibinding(n);
686            }
687
688            fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) {
689              static int n = 20;
690              return fruit::createComponent()
691                  .addInstanceMultibinding(n);
692            }
693
694            fruit::Component<> getRootComponent() {
695              return fruit::createComponent()
696                  .install(ReplacementComponentInstallation)
697                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
698                  .install(ReplacedComponentInstallation);
699            }
700
701            int main() {
702              fruit::Injector<> injector(getRootComponent);
703
704              std::vector<int*> multibindings = injector.getMultibindings<int>();
705              Assert(multibindings.size() == 1);
706              Assert(*(multibindings[0]) == 20);
707            }
708            '''
709        expect_success(
710            COMMON_DEFINITIONS,
711            source,
712            locals())
713
714    @multiple_parameters([
715        ('', 'getReplacedComponent'),
716        ('double', 'getReplacedComponent, 1.0'),
717    ], [
718        ('', 'getReplacementComponent'),
719        ('std::string', 'getReplacementComponent, std::string("Hello, world")'),
720    ])
721    def test_replace_component_also_installed_directly_after_ok(self,
722            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
723        source = '''
724            fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) {
725              static int n = 10;
726              return fruit::createComponent()
727                  .addInstanceMultibinding(n);
728            }
729
730            fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) {
731              static int n = 20;
732              return fruit::createComponent()
733                  .addInstanceMultibinding(n);
734            }
735
736            fruit::Component<> getRootComponent() {
737              return fruit::createComponent()
738                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
739                  .install(ReplacedComponentInstallation)
740                  .install(ReplacementComponentInstallation);
741            }
742
743            int main() {
744              fruit::Injector<> injector(getRootComponent);
745
746              std::vector<int*> multibindings = injector.getMultibindings<int>();
747              Assert(multibindings.size() == 1);
748              Assert(*(multibindings[0]) == 20);
749            }
750            '''
751        expect_success(
752            COMMON_DEFINITIONS,
753            source,
754            locals())
755
756    @multiple_parameters([
757        ('', 'getReplacedComponent'),
758        ('double', 'getReplacedComponent, 1.0'),
759    ], [
760        ('', 'getReplacementComponent'),
761        ('std::string', 'getReplacementComponent, std::string("Hello, world")'),
762    ])
763    def test_replace_component_also_installed_directly_before_across_normalized_component_ok(self,
764            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
765        source = '''
766            fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) {
767              static int n = 10;
768              return fruit::createComponent()
769                  .addInstanceMultibinding(n);
770            }
771
772            fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) {
773              static int n = 20;
774              return fruit::createComponent()
775                  .addInstanceMultibinding(n);
776            }
777
778            fruit::Component<> getRootComponent1() {
779              return fruit::createComponent()
780                  .install(ReplacementComponentInstallation);
781            }
782
783            fruit::Component<> getRootComponent2() {
784              return fruit::createComponent()
785                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
786                  .install(ReplacedComponentInstallation);
787            }
788
789            int main() {
790              fruit::NormalizedComponent<> normalizedComponent(getRootComponent1);
791              fruit::Injector<> injector(normalizedComponent, getRootComponent2);
792
793              std::vector<int*> multibindings = injector.getMultibindings<int>();
794              Assert(multibindings.size() == 1);
795              Assert(*(multibindings[0]) == 20);
796            }
797            '''
798        expect_success(
799            COMMON_DEFINITIONS,
800            source,
801            locals())
802
803    @multiple_parameters([
804        ('', 'getReplacedComponent'),
805        ('double', 'getReplacedComponent, 1.0'),
806    ], [
807        ('', 'getReplacementComponent'),
808        ('std::string', 'getReplacementComponent, std::string("Hello, world")'),
809    ])
810    def test_replace_component_also_installed_directly_after_across_normalized_component_ok(self,
811            ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
812        source = '''
813            fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) {
814              static int n = 10;
815              return fruit::createComponent()
816                  .addInstanceMultibinding(n);
817            }
818
819            fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) {
820              static int n = 20;
821              return fruit::createComponent()
822                  .addInstanceMultibinding(n);
823            }
824
825            fruit::Component<> getRootComponent1() {
826              return fruit::createComponent()
827                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
828                  .install(ReplacedComponentInstallation);
829            }
830
831            fruit::Component<> getRootComponent2() {
832              return fruit::createComponent()
833                  .install(ReplacementComponentInstallation);
834            }
835
836            int main() {
837              fruit::NormalizedComponent<> normalizedComponent(getRootComponent1);
838              fruit::Injector<> injector(normalizedComponent, getRootComponent2);
839
840              std::vector<int*> multibindings = injector.getMultibindings<int>();
841              Assert(multibindings.size() == 1);
842              Assert(*(multibindings[0]) == 20);
843            }
844            '''
845        expect_success(
846            COMMON_DEFINITIONS,
847            source,
848            locals())
849
850    @multiple_parameters([
851        ('', 'getReplacedComponent', 'getOtherReplacementComponent'),
852        ('double', 'getReplacedComponent, 1.0', 'getOtherReplacementComponent, 1.0'),
853    ], [
854        ('', 'getReplacementComponent'),
855        ('std::string', 'getReplacementComponent, std::string("Hello, world")'),
856    ])
857    def test_replace_multiple_components_with_same(self,
858            ReplacedComponentParamTypes, ReplacedComponentInstallation, OtherReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation):
859        source = '''
860            fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) {
861              static int n = 10;
862              return fruit::createComponent()
863                  .addInstanceMultibinding(n);
864            }
865
866            fruit::Component<> getOtherReplacementComponent(ReplacedComponentParamTypes) {
867              static int n = 20;
868              return fruit::createComponent()
869                  .addInstanceMultibinding(n);
870            }
871
872            fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) {
873              static int n = 30;
874              return fruit::createComponent()
875                  .addInstanceMultibinding(n);
876            }
877
878            fruit::Component<> getRootComponent() {
879              return fruit::createComponent()
880                  .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation)
881                  .replace(OtherReplacedComponentInstallation).with(ReplacementComponentInstallation)
882                  .install(ReplacedComponentInstallation)
883                  .install(OtherReplacedComponentInstallation);
884            }
885
886            int main() {
887              fruit::Injector<> injector(getRootComponent);
888
889              std::vector<int*> multibindings = injector.getMultibindings<int>();
890              Assert(multibindings.size() == 1);
891              Assert(*(multibindings[0]) == 30);
892            }
893            '''
894        expect_success(
895            COMMON_DEFINITIONS,
896            source,
897            locals())
898
899    def test_replace_component_one_set_of_args_only(self):
900        source = '''
901            fruit::Component<> getReplacedComponent(double) {
902              static int n = 10;
903              return fruit::createComponent()
904                  .addInstanceMultibinding(n);
905            }
906
907            fruit::Component<> getReplacementComponent() {
908              static int n = 20;
909              return fruit::createComponent()
910                  .addInstanceMultibinding(n);
911            }
912
913            fruit::Component<> getRootComponent() {
914              return fruit::createComponent()
915                  .replace(getReplacedComponent, 1.0).with(getReplacementComponent)
916                  .install(getReplacedComponent, 1.0)
917                  .install(getReplacedComponent, 5.0);
918            }
919
920            int main() {
921              fruit::Injector<> injector(getRootComponent);
922
923              std::vector<int*> multibindings = injector.getMultibindings<int>();
924              Assert(multibindings.size() == 2);
925              Assert(*(multibindings[0]) == 20);
926              Assert(*(multibindings[1]) == 10);
927            }
928            '''
929        expect_success(
930            COMMON_DEFINITIONS,
931            source,
932            locals())
933
934    def test_replace_component_already_replaced_with_different_args(self):
935        source = '''
936            fruit::Component<> getReplacedComponent(double) {
937              static int n = 10;
938              return fruit::createComponent()
939                  .addInstanceMultibinding(n);
940            }
941
942            fruit::Component<> getReplacementComponent() {
943              static int n = 20;
944              return fruit::createComponent()
945                  .addInstanceMultibinding(n);
946            }
947
948            fruit::Component<> getOtherReplacementComponent() {
949              static int n = 30;
950              return fruit::createComponent()
951                  .addInstanceMultibinding(n);
952            }
953
954            fruit::Component<> getRootComponent() {
955              return fruit::createComponent()
956                  .replace(getReplacedComponent, 1.0).with(getReplacementComponent)
957                  .replace(getReplacedComponent, 5.0).with(getOtherReplacementComponent)
958                  .install(getReplacedComponent, 1.0)
959                  .install(getReplacedComponent, 5.0);
960            }
961
962            int main() {
963              fruit::Injector<> injector(getRootComponent);
964
965              std::vector<int*> multibindings = injector.getMultibindings<int>();
966              Assert(multibindings.size() == 2);
967              Assert(*(multibindings[0]) == 20);
968              Assert(*(multibindings[1]) == 30);
969            }
970            '''
971        expect_success(
972            COMMON_DEFINITIONS,
973            source,
974            locals())
975
976if __name__ == '__main__':
977    absltest.main()
978