1#!/usr/bin/env python3
2#  Copyright 2016 Google Inc. All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS-IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16from fruit_test_common import *
17
18COMMON_DEFINITIONS = '''
19    #include "test_common.h"
20
21    struct X;
22
23    struct Annotation1 {};
24    using XAnnot1 = fruit::Annotated<Annotation1, X>;
25    '''
26
27@pytest.mark.parametrize('XParamInChildComponent,XParamInRootComponent', [
28    ('X', 'X'),
29    ('X', 'const X'),
30    ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'),
31    ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'),
32])
33def test_success(XParamInChildComponent, XParamInRootComponent):
34    source = '''
35        struct X {
36          int n;
37          X(int n) : n(n) {}
38        };
39
40        fruit::Component<XParamInChildComponent> getChildComponent() {
41          return fruit::createComponent()
42            .registerProvider<XParamInChildComponent()>([]() { return X(5); });
43        }
44
45        fruit::Component<XParamInRootComponent> getRootComponent() {
46          return fruit::createComponent()
47            .install(getChildComponent);
48        }
49
50        int main() {
51          fruit::Injector<XParamInRootComponent> injector(getRootComponent);
52          X x = injector.get<XParamInRootComponent>();
53          Assert(x.n == 5);
54        }
55        '''
56    expect_success(
57        COMMON_DEFINITIONS,
58        source,
59        locals())
60
61@pytest.mark.parametrize('XParamInChildComponent,XParamInRootComponent', [
62    ('const X', 'X'),
63    ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X>'),
64])
65def test_install_error_child_component_provides_const(XParamInChildComponent, XParamInRootComponent):
66    source = '''
67        struct X {};
68
69        fruit::Component<XParamInChildComponent> getChildComponent();
70
71        fruit::Component<XParamInRootComponent> getRootComponent() {
72          return fruit::createComponent()
73            .install(getChildComponent);
74        }
75        '''
76    expect_compile_error(
77        'NonConstBindingRequiredButConstBindingProvidedError<XParamInRootComponent>',
78        'The type T was provided as constant, however one of the constructors/providers/factories in this component',
79        COMMON_DEFINITIONS,
80        source,
81        locals())
82
83@pytest.mark.parametrize('ProvidedXParam,RequiredXParam', [
84    ('X', 'X'),
85    ('X', 'const X'),
86    ('const X', 'const X'),
87    ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'),
88    ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'),
89    ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X>'),
90])
91def test_with_requirements_success(ProvidedXParam, RequiredXParam):
92    ProvidedXParamWithoutConst = ProvidedXParam.replace('const ', '')
93    source = '''
94        struct X {
95          int n;
96          X(int n) : n(n) {}
97        };
98
99        struct Y {
100          X x;
101          Y(X x): x(x) {}
102        };
103
104        fruit::Component<fruit::Required<RequiredXParam>, Y> getChildComponent1() {
105          return fruit::createComponent()
106            .registerProvider<Y(RequiredXParam)>([](X x) { return Y(x); });
107        }
108
109        fruit::Component<ProvidedXParam> getChildComponent2() {
110          return fruit::createComponent()
111            .registerProvider<ProvidedXParamWithoutConst()>([]() { return X(5); });
112        }
113
114        fruit::Component<Y> getRootComponent() {
115          return fruit::createComponent()
116            .install(getChildComponent1)
117            .install(getChildComponent2);
118        }
119
120        int main() {
121          fruit::Injector<Y> injector(getRootComponent);
122          Y y = injector.get<Y>();
123          Assert(y.x.n == 5);
124        }
125        '''
126    expect_success(
127        COMMON_DEFINITIONS,
128        source,
129        locals())
130
131@pytest.mark.parametrize('ProvidedXParam,RequiredXParam', [
132    ('const X', 'X'),
133    ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X>'),
134])
135def test_with_requirements_error_only_nonconst_provided(ProvidedXParam, RequiredXParam):
136    source = '''
137        struct X {};
138        struct Y {};
139
140        fruit::Component<fruit::Required<RequiredXParam>, Y> getChildComponent1();
141
142        fruit::Component<ProvidedXParam> getChildComponent2();
143
144        fruit::Component<Y> getRootComponent() {
145          return fruit::createComponent()
146            .install(getChildComponent1)
147            .install(getChildComponent2);
148        }
149        '''
150    expect_compile_error(
151        'NonConstBindingRequiredButConstBindingProvidedError<RequiredXParam>',
152        'The type T was provided as constant, however one of the constructors/providers/factories in this component',
153        COMMON_DEFINITIONS,
154        source,
155        locals())
156
157@pytest.mark.parametrize('ProvidedXParam,RequiredXParam', [
158    ('const X', 'X'),
159    ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X>'),
160])
161def test_with_requirements_error_only_nonconst_provided_reversed_install_order(ProvidedXParam, RequiredXParam):
162    source = '''
163        struct X {};
164        struct Y {};
165
166        fruit::Component<fruit::Required<RequiredXParam>, Y> getChildComponent1();
167
168        fruit::Component<ProvidedXParam> getChildComponent2();
169
170        fruit::Component<Y> getRootComponent() {
171          return fruit::createComponent()
172            .install(getChildComponent2)
173            .install(getChildComponent1);
174        }
175        '''
176    expect_compile_error(
177        'NonConstBindingRequiredButConstBindingProvidedError<RequiredXParam>',
178        'The type T was provided as constant, however one of the constructors/providers/factories in this component',
179        COMMON_DEFINITIONS,
180        source,
181        locals())
182
183def test_with_requirements_not_specified_in_child_component_error():
184    source = '''
185        struct X {
186          int n;
187          X(int n) : n(n) {}
188        };
189
190        struct Y {
191          X x;
192          Y(X x): x(x) {}
193        };
194
195        fruit::Component<fruit::Required<X>, Y> getParentYComponent() {
196          return fruit::createComponent()
197            .registerProvider([](X x) { return Y(x); });
198        }
199
200        // We intentionally don't have fruit::Required<X> here, we want to test that this results in an error.
201        fruit::Component<Y> getYComponent() {
202          return fruit::createComponent()
203            .install(getParentYComponent);
204        }
205        '''
206    expect_compile_error(
207        'NoBindingFoundError<X>',
208        'No explicit binding nor C::Inject definition was found for T',
209        COMMON_DEFINITIONS,
210        source)
211
212@pytest.mark.parametrize('XAnnot,ConstXAnnot', [
213    ('X', 'const X'),
214    ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'),
215])
216def test_install_requiring_nonconst_then_install_requiring_const_ok(XAnnot, ConstXAnnot):
217    source = '''
218        struct X {};
219        struct Y {};
220        struct Z {};
221
222        fruit::Component<fruit::Required<XAnnot>, Y> getChildComponent1() {
223          return fruit::createComponent()
224              .registerConstructor<Y()>();
225        }
226
227        fruit::Component<fruit::Required<ConstXAnnot>, Z> getChildComponent2() {
228          return fruit::createComponent()
229              .registerConstructor<Z()>();
230        }
231
232        fruit::Component<Y, Z> getRootComponent() {
233          return fruit::createComponent()
234            .install(getChildComponent1)
235            .install(getChildComponent2)
236            .registerConstructor<XAnnot()>();
237        }
238
239        int main() {
240          fruit::Injector<Y, Z> injector(getRootComponent);
241          injector.get<Y>();
242          injector.get<Z>();
243        }
244        '''
245    expect_success(
246        COMMON_DEFINITIONS,
247        source,
248        locals())
249
250def test_install_requiring_nonconst_then_install_requiring_const_declaring_const_requirement_error():
251    source = '''
252        struct X {};
253        struct Y {};
254        struct Z {};
255
256        fruit::Component<fruit::Required<X>, Y> getChildComponent1();
257        fruit::Component<fruit::Required<const X>, Z> getChildComponent2();
258
259        fruit::Component<fruit::Required<const X>, Y, Z> getRootComponent() {
260          return fruit::createComponent()
261            .install(getChildComponent1)
262            .install(getChildComponent2);
263        }
264        '''
265    expect_compile_error(
266        'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<X>',
267        'The type T was declared as a const Required type in the returned Component, however',
268        COMMON_DEFINITIONS,
269        source,
270        locals())
271
272def test_install_requiring_const_then_install_requiring_nonconst_ok():
273    source = '''
274        struct X {};
275        struct Y {};
276        struct Z {};
277
278        fruit::Component<fruit::Required<const X>, Y> getChildComponent1() {
279          return fruit::createComponent()
280              .registerConstructor<Y()>();
281        }
282
283        fruit::Component<fruit::Required<X>, Z> getChildComponent2() {
284          return fruit::createComponent()
285              .registerConstructor<Z()>();
286        }
287
288        fruit::Component<Y, Z> getRootComponent() {
289          return fruit::createComponent()
290            .install(getChildComponent1)
291            .install(getChildComponent2)
292            .registerConstructor<X()>();
293        }
294
295        int main() {
296          fruit::Injector<Y, Z> injector(getRootComponent);
297          injector.get<Y>();
298          injector.get<Z>();
299        }
300        '''
301    expect_success(
302        COMMON_DEFINITIONS,
303        source,
304        locals())
305
306def test_install_requiring_const_then_install_requiring_nonconst_declaring_const_requirement_error():
307    source = '''
308        struct X {};
309        struct Y {};
310        struct Z {};
311
312        fruit::Component<fruit::Required<const X>, Y> getChildComponent1();
313        fruit::Component<fruit::Required<X>, Z> getChildComponent2();
314
315        fruit::Component<fruit::Required<const X>, Y, Z> getRootComponent() {
316          return fruit::createComponent()
317            .install(getChildComponent1)
318            .install(getChildComponent2);
319        }
320        '''
321    expect_compile_error(
322        'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<X>',
323        'The type T was declared as a const Required type in the returned Component, however',
324        COMMON_DEFINITIONS,
325        source,
326        locals())
327
328def test_install_with_args_success():
329    source = '''
330        struct X {
331          int n;
332          X(int n) : n(n) {}
333        };
334
335        struct Arg {
336          Arg(int) {}
337          Arg() = default;
338          Arg(const Arg&) = default;
339          Arg(Arg&&) = default;
340          Arg& operator=(const Arg&) = default;
341          Arg& operator=(Arg&&) = default;
342        };
343
344        bool operator==(const Arg&, const Arg&) {
345          return true;
346        }
347
348        namespace std {
349          template <>
350          struct hash<Arg> {
351            size_t operator()(const Arg&) {
352              return 0;
353            }
354          };
355        }
356
357        fruit::Component<X> getParentComponent(int, std::string, Arg, Arg) {
358          return fruit::createComponent()
359            .registerProvider([]() { return X(5); });
360        }
361
362        fruit::Component<X> getComponent() {
363          return fruit::createComponent()
364            .install(getParentComponent, 5, std::string("Hello"), Arg{}, 15);
365        }
366
367        int main() {
368          fruit::Injector<X> injector(getComponent);
369          X x = injector.get<X>();
370          Assert(x.n == 5);
371        }
372        '''
373    expect_success(COMMON_DEFINITIONS, source)
374
375def test_install_with_args_error_not_move_constructible():
376    source = '''
377        struct Arg {
378          Arg() = default;
379          Arg(const Arg&) = default;
380          Arg(Arg&&) = delete;
381          Arg& operator=(const Arg&) = default;
382          Arg& operator=(Arg&&) = default;
383        };
384
385        bool operator==(const Arg&, const Arg&);
386
387        namespace std {
388          template <>
389          struct hash<Arg> {
390            size_t operator()(const Arg&);
391          };
392        }
393
394        fruit::Component<X> getParentComponent(int, std::string, Arg);
395
396        fruit::Component<X> getComponent() {
397          return fruit::createComponent()
398            .install(getParentComponent, 5, std::string("Hello"), Arg{});
399        }
400        '''
401    expect_generic_compile_error(
402        'error: use of deleted function .Arg::Arg\(Arg&&\).'
403            + '|error: call to deleted constructor of .Arg.'
404            + '|.Arg::Arg\(Arg &&\).: cannot convert argument 1 from .std::_Tuple_val<Arg>. to .const Arg &.',
405        COMMON_DEFINITIONS,
406        source)
407
408def test_install_with_args_error_not_move_constructible_with_conversion():
409    source = '''
410        struct Arg {
411          Arg(int) {}
412          Arg() = default;
413          Arg(const Arg&) = default;
414          Arg(Arg&&) = delete;
415          Arg& operator=(const Arg&) = default;
416          Arg& operator=(Arg&&) = default;
417        };
418
419        bool operator==(const Arg&, const Arg&);
420
421        namespace std {
422          template <>
423          struct hash<Arg> {
424            size_t operator()(const Arg&);
425          };
426        }
427
428        fruit::Component<X> getParentComponent(int, std::string, Arg);
429
430        fruit::Component<X> getComponent() {
431          return fruit::createComponent()
432            .install(getParentComponent, 5, std::string("Hello"), 15);
433        }
434        '''
435    expect_generic_compile_error(
436        'error: use of deleted function .Arg::Arg\(Arg&&\).'
437            + '|error: call to deleted constructor of .Arg.'
438            + '|.Arg::Arg\(Arg &&\).: cannot convert argument 1 from .std::_Tuple_val<Arg>. to .int.',
439        COMMON_DEFINITIONS,
440        source)
441
442def test_install_with_args_error_not_copy_constructible():
443    source = '''
444        struct X {
445          int n;
446          X(int n) : n(n) {}
447        };
448
449        struct Arg {
450          Arg() = default;
451          Arg(const Arg&) = delete;
452          Arg(Arg&&) = default;
453          Arg& operator=(const Arg&) = default;
454          Arg& operator=(Arg&&) = default;
455        };
456
457        bool operator==(const Arg&, const Arg&);
458
459        namespace std {
460          template <>
461          struct hash<Arg> {
462            size_t operator()(const Arg&);
463          };
464        }
465
466        fruit::Component<X> getParentComponent(int, std::string, Arg);
467
468        fruit::Component<X> getComponent() {
469          return fruit::createComponent()
470            .install(getParentComponent, 5, std::string("Hello"), Arg{});
471        }
472        '''
473    expect_generic_compile_error(
474        'error: use of deleted function .Arg::Arg\(const Arg&\).'
475            + '|error: call to deleted constructor of .Arg.'
476            + '|error C2280: .Arg::Arg\(const Arg &\).: attempting to reference a deleted function',
477        COMMON_DEFINITIONS,
478        source)
479
480def test_install_with_args_error_not_copy_constructible_with_conversion():
481    source = '''
482        struct X {
483          int n;
484          X(int n) : n(n) {}
485        };
486
487        struct Arg {
488          Arg(int) {}
489          Arg() = default;
490          Arg(const Arg&) = delete;
491          Arg(Arg&&) = default;
492          Arg& operator=(const Arg&) = default;
493          Arg& operator=(Arg&&) = default;
494        };
495
496        bool operator==(const Arg&, const Arg&);
497
498        namespace std {
499          template <>
500          struct hash<Arg> {
501            size_t operator()(const Arg&);
502          };
503        }
504
505        fruit::Component<X> getParentComponent(int, std::string, Arg);
506
507        fruit::Component<X> getComponent() {
508          return fruit::createComponent()
509            .install(getParentComponent, 5, std::string("Hello"), 15);
510        }
511        '''
512    expect_generic_compile_error(
513        'error: use of deleted function .Arg::Arg\(const Arg&\).'
514            + '|error: call to deleted constructor of .Arg.'
515            + '|error C2280: .Arg::Arg\(const Arg &\).: attempting to reference a deleted function',
516        COMMON_DEFINITIONS,
517        source)
518
519def test_install_with_args_error_not_move_assignable():
520    source = '''
521        struct Arg {
522          Arg() = default;
523          Arg(const Arg&) = default;
524          Arg(Arg&&) = default;
525          Arg& operator=(const Arg&) = default;
526          Arg& operator=(Arg&&) = delete;
527        };
528
529        bool operator==(const Arg&, const Arg&);
530
531        namespace std {
532          template <>
533          struct hash<Arg> {
534            size_t operator()(const Arg&);
535          };
536        }
537
538        fruit::Component<X> getParentComponent(int, std::string, Arg);
539
540        fruit::Component<X> getComponent() {
541          return fruit::createComponent()
542            .install(getParentComponent, 5, std::string("Hello"), Arg{});
543        }
544        '''
545    expect_generic_compile_error(
546        'error: use of deleted function .Arg& Arg::operator=\(Arg&&\).'
547            + '|error: overload resolution selected deleted operator .=.'
548            + '|error C2280: .Arg &Arg::operator =\(Arg &&\).: attempting to reference a deleted function',
549        COMMON_DEFINITIONS,
550        source)
551
552def test_install_with_args_error_not_move_assignable_with_conversion():
553    source = '''
554        struct Arg {
555          Arg(int) {}
556          Arg() = default;
557          Arg(const Arg&) = default;
558          Arg(Arg&&) = default;
559          Arg& operator=(const Arg&) = default;
560          Arg& operator=(Arg&&) = delete;
561        };
562
563        bool operator==(const Arg&, const Arg&);
564
565        namespace std {
566          template <>
567          struct hash<Arg> {
568            size_t operator()(const Arg&);
569          };
570        }
571
572        fruit::Component<X> getParentComponent(int, std::string, Arg);
573
574        fruit::Component<X> getComponent() {
575          return fruit::createComponent()
576            .install(getParentComponent, 5, std::string("Hello"), 15);
577        }
578        '''
579    expect_generic_compile_error(
580        'error: use of deleted function .Arg& Arg::operator=\(Arg&&\).'
581            + '|error: overload resolution selected deleted operator .=.'
582            + '|error C2280: .Arg &Arg::operator =\(Arg &&\).: attempting to reference a deleted function',
583        COMMON_DEFINITIONS,
584        source)
585
586def test_install_with_args_error_not_copy_assignable():
587    source = '''
588        struct X {
589          int n;
590          X(int n) : n(n) {}
591        };
592
593        struct Arg {
594          Arg() = default;
595          Arg(const Arg&) = default;
596          Arg(Arg&&) = default;
597          Arg& operator=(const Arg&) = delete;
598          Arg& operator=(Arg&&) = default;
599        };
600
601        bool operator==(const Arg&, const Arg&);
602
603        namespace std {
604          template <>
605          struct hash<Arg> {
606            size_t operator()(const Arg&);
607          };
608        }
609
610        fruit::Component<X> getParentComponent(int, std::string, Arg);
611
612        fruit::Component<X> getComponent() {
613          return fruit::createComponent()
614            .install(getParentComponent, 5, std::string("Hello"), Arg{});
615        }
616        '''
617    expect_generic_compile_error(
618        'error: use of deleted function .Arg& Arg::operator=\(const Arg&\).'
619            + '|error: overload resolution selected deleted operator .=.'
620            + '|error C2280: .Arg &Arg::operator =\(const Arg &\).: attempting to reference a deleted function',
621        COMMON_DEFINITIONS,
622        source)
623
624def test_install_with_args_error_not_copy_assignable_with_conversion():
625    source = '''
626        struct X {
627          int n;
628          X(int n) : n(n) {}
629        };
630
631        struct Arg {
632          Arg(int) {}
633          Arg() = default;
634          Arg(const Arg&) = default;
635          Arg(Arg&&) = default;
636          Arg& operator=(const Arg&) = delete;
637          Arg& operator=(Arg&&) = default;
638        };
639
640        bool operator==(const Arg&, const Arg&);
641
642        namespace std {
643          template <>
644          struct hash<Arg> {
645            size_t operator()(const Arg&);
646          };
647        }
648
649        fruit::Component<X> getParentComponent(int, std::string, Arg);
650
651        fruit::Component<X> getComponent() {
652          return fruit::createComponent()
653            .install(getParentComponent, 5, std::string("Hello"), 15);
654        }
655        '''
656    expect_generic_compile_error(
657        'error: use of deleted function .Arg& Arg::operator=\(const Arg&\).'
658            + '|error: overload resolution selected deleted operator .=.'
659            + '|error C2280: .Arg &Arg::operator =\(const Arg &\).: attempting to reference a deleted function',
660        COMMON_DEFINITIONS,
661        source)
662
663def test_install_with_args_error_not_equality_comparable():
664    source = '''
665        struct X {
666          int n;
667          X(int n) : n(n) {}
668        };
669
670        struct Arg {
671          Arg() = default;
672          Arg(const Arg&) = default;
673          Arg(Arg&&) = default;
674          Arg& operator=(const Arg&) = default;
675          Arg& operator=(Arg&&) = default;
676        };
677
678        namespace std {
679          template <>
680          struct hash<Arg> {
681            size_t operator()(const Arg&);
682          };
683        }
684
685        fruit::Component<X> getParentComponent(int, std::string, Arg);
686
687        fruit::Component<X> getComponent() {
688          return fruit::createComponent()
689            .install(getParentComponent, 5, std::string("Hello"), Arg{});
690        }
691        '''
692    expect_generic_compile_error(
693        'error: no match for .operator==. \(operand types are .const Arg. and .const Arg.\)'
694            + '|error: invalid operands to binary expression \(.const Arg. and .const Arg.\)'
695            + '|error C2676: binary .==.: .const Arg. does not define this operator',
696        COMMON_DEFINITIONS,
697        source)
698
699def test_install_with_args_error_not_equality_comparable_with_conversion():
700    source = '''
701        struct X {
702          int n;
703          X(int n) : n(n) {}
704        };
705
706        struct Arg {
707          Arg(int) {}
708          Arg() = default;
709          Arg(const Arg&) = default;
710          Arg(Arg&&) = default;
711          Arg& operator=(const Arg&) = default;
712          Arg& operator=(Arg&&) = default;
713        };
714
715        namespace std {
716          template <>
717          struct hash<Arg> {
718            size_t operator()(const Arg&);
719          };
720        }
721
722        fruit::Component<X> getParentComponent(int, std::string, Arg);
723
724        fruit::Component<X> getComponent() {
725          return fruit::createComponent()
726            .install(getParentComponent, 5, std::string("Hello"), 15);
727        }
728        '''
729    expect_generic_compile_error(
730        'error: no match for .operator==. \(operand types are .const Arg. and .const Arg.\)'
731            + '|error: invalid operands to binary expression \(.const Arg. and .const Arg.\)'
732            + '|error C2676: binary .==.: .const Arg. does not define this operator',
733        COMMON_DEFINITIONS,
734        source)
735
736def test_install_with_args_error_not_hashable():
737    source = '''
738        struct Arg {
739          Arg() = default;
740          Arg(const Arg&) = default;
741          Arg(Arg&&) = default;
742          Arg& operator=(const Arg&) = default;
743          Arg& operator=(Arg&&) = default;
744        };
745
746        bool operator==(const Arg&, const Arg&);
747
748        fruit::Component<X> getParentComponent(int, std::string, Arg);
749
750        fruit::Component<X> getComponent() {
751          return fruit::createComponent()
752            .install(getParentComponent, 5, std::string("Hello"), Arg{});
753        }
754        '''
755    expect_generic_compile_error(
756        'error: use of deleted function .std::hash<Arg>::hash\(\).'
757            + '|error: call to implicitly-deleted default constructor of .std::hash<Arg>.'
758            + '|error: invalid use of incomplete type .struct std::hash<Arg>.'
759            + '|error: implicit instantiation of undefined template .std::(__1::)?hash<Arg>.'
760            + '|error C2338: The C\+\+ Standard doesn.t provide a hash for this type.'
761            + '|error C2064: term does not evaluate to a function taking 1 arguments',
762        COMMON_DEFINITIONS,
763        source)
764
765def test_install_with_args_error_not_hashable_with_conversion():
766    source = '''
767        struct Arg {
768          Arg(int) {}
769          Arg() = default;
770          Arg(const Arg&) = default;
771          Arg(Arg&&) = default;
772          Arg& operator=(const Arg&) = default;
773          Arg& operator=(Arg&&) = default;
774        };
775
776        bool operator==(const Arg&, const Arg&);
777
778        fruit::Component<X> getParentComponent(int, std::string, Arg);
779
780        fruit::Component<X> getComponent() {
781          return fruit::createComponent()
782            .install(getParentComponent, 5, std::string("Hello"), 15);
783        }
784        '''
785    expect_generic_compile_error(
786        'error: use of deleted function .std::hash<Arg>::hash\(\).'
787            + '|error: call to implicitly-deleted default constructor of .std::hash<Arg>.'
788            + '|error: invalid use of incomplete type .struct std::hash<Arg>.'
789            + '|error: implicit instantiation of undefined template .std::(__1::)?hash<Arg>.'
790            + '|error C2338: The C\+\+ Standard doesn.t provide a hash for this type.'
791            + '|error C2064: term does not evaluate to a function taking 1 arguments',
792        COMMON_DEFINITIONS,
793        source)
794
795@pytest.mark.parametrize('XAnnot', [
796    'X',
797    'fruit::Annotated<Annotation1, X>',
798])
799def test_install_component_functions_deduped(XAnnot):
800    source = '''
801        struct X {};
802
803        X x;
804
805        fruit::Component<> getComponent() {
806          return fruit::createComponent()
807            .addInstanceMultibinding<XAnnot, X>(x);
808        }
809
810        fruit::Component<> getComponent2() {
811          return fruit::createComponent()
812            .install(getComponent);
813        }
814
815        fruit::Component<> getComponent3() {
816          return fruit::createComponent()
817            .install(getComponent);
818        }
819
820        fruit::Component<> getComponent4() {
821          return fruit::createComponent()
822            .install(getComponent2)
823            .install(getComponent3);
824        }
825
826        int main() {
827          fruit::Injector<> injector(getComponent4);
828
829          // We test multibindings because the effect on other bindings is not user-visible (that only affects
830          // performance).
831          std::vector<X*> multibindings = injector.getMultibindings<XAnnot>();
832          Assert(multibindings.size() == 1);
833          Assert(multibindings[0] == &x);
834        }
835        '''
836    expect_success(
837        COMMON_DEFINITIONS,
838        source,
839        locals())
840
841@pytest.mark.parametrize('XAnnot', [
842    'X',
843    'fruit::Annotated<Annotation1, X>',
844])
845def test_install_component_functions_deduped_across_normalized_component(XAnnot):
846    source = '''
847        struct X {};
848
849        X x;
850
851        fruit::Component<> getComponent() {
852          return fruit::createComponent()
853            .addInstanceMultibinding<XAnnot, X>(x);
854        }
855
856        fruit::Component<> getComponent2() {
857          return fruit::createComponent()
858            .install(getComponent);
859        }
860
861        fruit::Component<> getComponent3() {
862          return fruit::createComponent()
863            .install(getComponent);
864        }
865
866        int main() {
867          fruit::NormalizedComponent<> normalizedComponent(getComponent2);
868          fruit::Injector<> injector(normalizedComponent, getComponent3);
869
870          // We test multibindings because the effect on other bindings is not user-visible (that only affects
871          // performance).
872          std::vector<X*> multibindings = injector.getMultibindings<XAnnot>();
873          Assert(multibindings.size() == 1);
874          Assert(multibindings[0] == &x);
875        }
876        '''
877    expect_success(
878        COMMON_DEFINITIONS,
879        source,
880        locals())
881
882@pytest.mark.parametrize('XAnnot', [
883    'X',
884    'fruit::Annotated<Annotation1, X>',
885])
886def test_install_component_functions_with_args_deduped(XAnnot):
887    source = '''
888        struct X {};
889
890        X x;
891
892        fruit::Component<> getComponent(int) {
893          return fruit::createComponent()
894            .addInstanceMultibinding<XAnnot, X>(x);
895        }
896
897        fruit::Component<> getComponent2() {
898          return fruit::createComponent()
899            .install(getComponent, 1);
900        }
901
902        fruit::Component<> getComponent3() {
903          return fruit::createComponent()
904            .install(getComponent, 1);
905        }
906
907        fruit::Component<> getComponent4() {
908          return fruit::createComponent()
909            .install(getComponent2)
910            .install(getComponent3);
911        }
912
913        int main() {
914          fruit::Injector<> injector(getComponent4);
915
916          // We test multibindings because the effect on other bindings is not user-visible (that only affects
917          // performance).
918          std::vector<X*> multibindings = injector.getMultibindings<XAnnot>();
919          Assert(multibindings.size() == 1);
920          Assert(multibindings[0] == &x);
921        }
922        '''
923    expect_success(
924        COMMON_DEFINITIONS,
925        source,
926        locals())
927
928@pytest.mark.parametrize('XAnnot', [
929    'X',
930    'fruit::Annotated<Annotation1, X>',
931])
932def test_install_component_functions_different_args_not_deduped(XAnnot):
933    source = '''
934        struct X {};
935
936        X x;
937
938        fruit::Component<> getComponent(int) {
939          return fruit::createComponent()
940            .addInstanceMultibinding<XAnnot, X>(x);
941        }
942
943        fruit::Component<> getComponent2() {
944          return fruit::createComponent()
945            .install(getComponent, 1);
946        }
947
948        fruit::Component<> getComponent3() {
949          return fruit::createComponent()
950            .install(getComponent, 2);
951        }
952
953        fruit::Component<> getComponent4() {
954          return fruit::createComponent()
955            .install(getComponent2)
956            .install(getComponent3);
957        }
958
959        int main() {
960          fruit::Injector<> injector(getComponent4);
961
962          // We test multibindings because the effect on other bindings is not user-visible (it only affects
963          // performance).
964          std::vector<X*> multibindings = injector.getMultibindings<XAnnot>();
965          Assert(multibindings.size() == 2);
966          Assert(multibindings[0] == &x);
967          Assert(multibindings[1] == &x);
968        }
969        '''
970    expect_success(
971        COMMON_DEFINITIONS,
972        source,
973        locals())
974
975def test_install_component_functions_loop():
976    source = '''
977        struct X {};
978        struct Y {};
979        struct Z {};
980
981        // X -> Y -> Z -> Y
982
983        fruit::Component<X> getXComponent();
984        fruit::Component<Y> getYComponent();
985        fruit::Component<Z> getZComponent();
986
987        fruit::Component<X> getXComponent() {
988          return fruit::createComponent()
989              .registerConstructor<X()>()
990              .install(getYComponent);
991        }
992
993        fruit::Component<Y> getYComponent() {
994          return fruit::createComponent()
995              .registerConstructor<Y()>()
996              .install(getZComponent);
997        }
998
999        fruit::Component<Z> getZComponent() {
1000          return fruit::createComponent()
1001              .registerConstructor<Z()>()
1002              .install(getYComponent);
1003        }
1004
1005        int main() {
1006          fruit::Injector<X> injector(getXComponent);
1007          (void)injector;
1008        }
1009        '''
1010    expect_runtime_error(
1011        'Component installation trace \(from top-level to the most deeply-nested\):\n'
1012            + '(class )?fruit::Component<(struct )?X> ?\((__cdecl)?\*\)\((void)?\)\n'
1013            + '<-- The loop starts here\n'
1014            + '(class )?fruit::Component<(struct )?Y> ?\((__cdecl)?\*\)\((void)?\)\n'
1015            + '(class )?fruit::Component<(struct )?Z> ?\((__cdecl)?\*\)\((void)?\)\n'
1016            + '(class )?fruit::Component<(struct )?Y> ?\((__cdecl)?\*\)\((void)?\)\n',
1017        COMMON_DEFINITIONS,
1018        source,
1019        locals())
1020
1021def test_install_component_functions_different_arguments_loop_not_reported():
1022    source = '''
1023        struct X {};
1024        struct Y {};
1025        struct Z {};
1026
1027        // X -> Y(1) -> Z -> Y(2)
1028
1029        fruit::Component<X> getXComponent();
1030        fruit::Component<Y> getYComponent(int);
1031        fruit::Component<Z> getZComponent();
1032
1033        fruit::Component<X> getXComponent() {
1034          return fruit::createComponent()
1035              .registerConstructor<X()>()
1036              .install(getYComponent, 1);
1037        }
1038
1039        fruit::Component<Y> getYComponent(int n) {
1040            if (n == 1) {
1041                return fruit::createComponent()
1042                    .registerConstructor<Y()>()
1043                    .install(getZComponent);
1044            } else {
1045                return fruit::createComponent()
1046                    .registerConstructor<Y()>();
1047            }
1048        }
1049
1050        fruit::Component<Z> getZComponent() {
1051          return fruit::createComponent()
1052              .registerConstructor<Z()>()
1053              .install(getYComponent, 2);
1054        }
1055
1056        int main() {
1057          fruit::Injector<X> injector(getXComponent);
1058          injector.get<X>();
1059        }
1060        '''
1061    expect_success(
1062        COMMON_DEFINITIONS,
1063        source,
1064        locals())
1065
1066if __name__== '__main__':
1067    main(__file__)
1068