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