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