• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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\(Arg &&\).: cannot convert argument 1 from .std::_Tuple_val<Arg>. to .const Arg &.',
407            COMMON_DEFINITIONS,
408            source)
409
410    def test_install_with_args_error_not_move_constructible_with_conversion(self):
411        source = '''
412            struct Arg {
413              Arg(int) {}
414              Arg() = default;
415              Arg(const Arg&) = default;
416              Arg(Arg&&) = delete;
417              Arg& operator=(const Arg&) = default;
418              Arg& operator=(Arg&&) = default;
419            };
420
421            bool operator==(const Arg&, const Arg&);
422
423            namespace std {
424              template <>
425              struct hash<Arg> {
426                size_t operator()(const Arg&);
427              };
428            }
429
430            fruit::Component<X> getParentComponent(int, std::string, Arg);
431
432            fruit::Component<X> getComponent() {
433              return fruit::createComponent()
434                .install(getParentComponent, 5, std::string("Hello"), 15);
435            }
436            '''
437        expect_generic_compile_error(
438            r'error: use of deleted function .Arg::Arg\(Arg&&\).'
439            r'|error: call to deleted constructor of .Arg.'
440            r'|.Arg::Arg\(Arg &&\).: cannot convert argument 1 from .std::_Tuple_val<Arg>. to .int.',
441            COMMON_DEFINITIONS,
442            source)
443
444    def test_install_with_args_error_not_copy_constructible(self):
445        source = '''
446            struct X {
447              int n;
448              X(int n) : n(n) {}
449            };
450
451            struct Arg {
452              Arg() = default;
453              Arg(const Arg&) = delete;
454              Arg(Arg&&) = default;
455              Arg& operator=(const Arg&) = default;
456              Arg& operator=(Arg&&) = default;
457            };
458
459            bool operator==(const Arg&, const Arg&);
460
461            namespace std {
462              template <>
463              struct hash<Arg> {
464                size_t operator()(const Arg&);
465              };
466            }
467
468            fruit::Component<X> getParentComponent(int, std::string, Arg);
469
470            fruit::Component<X> getComponent() {
471              return fruit::createComponent()
472                .install(getParentComponent, 5, std::string("Hello"), Arg{});
473            }
474            '''
475        expect_generic_compile_error(
476            r'error: use of deleted function .Arg::Arg\(const Arg&\).'
477            r'|error: call to deleted constructor of .Arg.'
478            r'|error C2280: .Arg::Arg\(const Arg &\).: attempting to reference a deleted function',
479            COMMON_DEFINITIONS,
480            source)
481
482    def test_install_with_args_error_not_copy_constructible_with_conversion(self):
483        source = '''
484            struct X {
485              int n;
486              X(int n) : n(n) {}
487            };
488
489            struct Arg {
490              Arg(int) {}
491              Arg() = default;
492              Arg(const Arg&) = delete;
493              Arg(Arg&&) = default;
494              Arg& operator=(const Arg&) = default;
495              Arg& operator=(Arg&&) = default;
496            };
497
498            bool operator==(const Arg&, const Arg&);
499
500            namespace std {
501              template <>
502              struct hash<Arg> {
503                size_t operator()(const Arg&);
504              };
505            }
506
507            fruit::Component<X> getParentComponent(int, std::string, Arg);
508
509            fruit::Component<X> getComponent() {
510              return fruit::createComponent()
511                .install(getParentComponent, 5, std::string("Hello"), 15);
512            }
513            '''
514        expect_generic_compile_error(
515            r'error: use of deleted function .Arg::Arg\(const Arg&\).'
516            r'|error: call to deleted constructor of .Arg.'
517            r'|error C2280: .Arg::Arg\(const Arg &\).: attempting to reference a deleted function',
518            COMMON_DEFINITIONS,
519            source)
520
521    def test_install_with_args_error_not_move_assignable(self):
522        source = '''
523            struct Arg {
524              Arg() = default;
525              Arg(const Arg&) = default;
526              Arg(Arg&&) = default;
527              Arg& operator=(const Arg&) = default;
528              Arg& operator=(Arg&&) = delete;
529            };
530
531            bool operator==(const Arg&, const Arg&);
532
533            namespace std {
534              template <>
535              struct hash<Arg> {
536                size_t operator()(const Arg&);
537              };
538            }
539
540            fruit::Component<X> getParentComponent(int, std::string, Arg);
541
542            fruit::Component<X> getComponent() {
543              return fruit::createComponent()
544                .install(getParentComponent, 5, std::string("Hello"), Arg{});
545            }
546            '''
547        expect_generic_compile_error(
548            r'error: use of deleted function .Arg& Arg::operator=\(Arg&&\).'
549            r'|error: overload resolution selected deleted operator .=.'
550            r'|error C2280: .Arg &Arg::operator =\(Arg &&\).: attempting to reference a deleted function',
551            COMMON_DEFINITIONS,
552            source)
553
554    def test_install_with_args_error_not_move_assignable_with_conversion(self):
555        source = '''
556            struct Arg {
557              Arg(int) {}
558              Arg() = default;
559              Arg(const Arg&) = default;
560              Arg(Arg&&) = default;
561              Arg& operator=(const Arg&) = default;
562              Arg& operator=(Arg&&) = delete;
563            };
564
565            bool operator==(const Arg&, const Arg&);
566
567            namespace std {
568              template <>
569              struct hash<Arg> {
570                size_t operator()(const Arg&);
571              };
572            }
573
574            fruit::Component<X> getParentComponent(int, std::string, Arg);
575
576            fruit::Component<X> getComponent() {
577              return fruit::createComponent()
578                .install(getParentComponent, 5, std::string("Hello"), 15);
579            }
580            '''
581        expect_generic_compile_error(
582            r'error: use of deleted function .Arg& Arg::operator=\(Arg&&\).'
583            r'|error: overload resolution selected deleted operator .=.'
584            r'|error C2280: .Arg &Arg::operator =\(Arg &&\).: attempting to reference a deleted function',
585            COMMON_DEFINITIONS,
586            source)
587
588    def test_install_with_args_error_not_copy_assignable(self):
589        source = '''
590            struct X {
591              int n;
592              X(int n) : n(n) {}
593            };
594
595            struct Arg {
596              Arg() = default;
597              Arg(const Arg&) = default;
598              Arg(Arg&&) = default;
599              Arg& operator=(const Arg&) = delete;
600              Arg& operator=(Arg&&) = default;
601            };
602
603            bool operator==(const Arg&, const Arg&);
604
605            namespace std {
606              template <>
607              struct hash<Arg> {
608                size_t operator()(const Arg&);
609              };
610            }
611
612            fruit::Component<X> getParentComponent(int, std::string, Arg);
613
614            fruit::Component<X> getComponent() {
615              return fruit::createComponent()
616                .install(getParentComponent, 5, std::string("Hello"), Arg{});
617            }
618            '''
619        expect_generic_compile_error(
620            r'error: use of deleted function .Arg& Arg::operator=\(const Arg&\).'
621            r'|error: overload resolution selected deleted operator .=.'
622            r'|error C2280: .Arg &Arg::operator =\(const Arg &\).: attempting to reference a deleted function',
623            COMMON_DEFINITIONS,
624            source)
625
626    def test_install_with_args_error_not_copy_assignable_with_conversion(self):
627        source = '''
628            struct X {
629              int n;
630              X(int n) : n(n) {}
631            };
632
633            struct Arg {
634              Arg(int) {}
635              Arg() = default;
636              Arg(const Arg&) = default;
637              Arg(Arg&&) = default;
638              Arg& operator=(const Arg&) = delete;
639              Arg& operator=(Arg&&) = default;
640            };
641
642            bool operator==(const Arg&, const Arg&);
643
644            namespace std {
645              template <>
646              struct hash<Arg> {
647                size_t operator()(const Arg&);
648              };
649            }
650
651            fruit::Component<X> getParentComponent(int, std::string, Arg);
652
653            fruit::Component<X> getComponent() {
654              return fruit::createComponent()
655                .install(getParentComponent, 5, std::string("Hello"), 15);
656            }
657            '''
658        expect_generic_compile_error(
659            r'error: use of deleted function .Arg& Arg::operator=\(const Arg&\).'
660            r'|error: overload resolution selected deleted operator .=.'
661            r'|error C2280: .Arg &Arg::operator =\(const Arg &\).: attempting to reference a deleted function',
662            COMMON_DEFINITIONS,
663            source)
664
665    def test_install_with_args_error_not_equality_comparable(self):
666        source = '''
667            struct X {
668              int n;
669              X(int n) : n(n) {}
670            };
671
672            struct Arg {
673              Arg() = default;
674              Arg(const Arg&) = default;
675              Arg(Arg&&) = default;
676              Arg& operator=(const Arg&) = default;
677              Arg& operator=(Arg&&) = default;
678            };
679
680            namespace std {
681              template <>
682              struct hash<Arg> {
683                size_t operator()(const Arg&);
684              };
685            }
686
687            fruit::Component<X> getParentComponent(int, std::string, Arg);
688
689            fruit::Component<X> getComponent() {
690              return fruit::createComponent()
691                .install(getParentComponent, 5, std::string("Hello"), Arg{});
692            }
693            '''
694        expect_generic_compile_error(
695            r'error: no match for .operator==. \(operand types are .const Arg. and .const Arg.\)'
696            r'|error: invalid operands to binary expression \(.const Arg. and .const Arg.\)'
697            r'|error C2676: binary .==.: .const Arg. does not define this operator',
698            COMMON_DEFINITIONS,
699            source)
700
701    def test_install_with_args_error_not_equality_comparable_with_conversion(self):
702        source = '''
703            struct X {
704              int n;
705              X(int n) : n(n) {}
706            };
707
708            struct Arg {
709              Arg(int) {}
710              Arg() = default;
711              Arg(const Arg&) = default;
712              Arg(Arg&&) = default;
713              Arg& operator=(const Arg&) = default;
714              Arg& operator=(Arg&&) = default;
715            };
716
717            namespace std {
718              template <>
719              struct hash<Arg> {
720                size_t operator()(const Arg&);
721              };
722            }
723
724            fruit::Component<X> getParentComponent(int, std::string, Arg);
725
726            fruit::Component<X> getComponent() {
727              return fruit::createComponent()
728                .install(getParentComponent, 5, std::string("Hello"), 15);
729            }
730            '''
731        expect_generic_compile_error(
732            r'error: no match for .operator==. \(operand types are .const Arg. and .const Arg.\)'
733            r'|error: invalid operands to binary expression \(.const Arg. and .const Arg.\)'
734            r'|error C2676: binary .==.: .const Arg. does not define this operator',
735            COMMON_DEFINITIONS,
736            source)
737
738    def test_install_with_args_error_not_hashable(self):
739        source = '''
740            struct Arg {
741              Arg() = default;
742              Arg(const Arg&) = default;
743              Arg(Arg&&) = default;
744              Arg& operator=(const Arg&) = default;
745              Arg& operator=(Arg&&) = default;
746            };
747
748            bool operator==(const Arg&, const Arg&);
749
750            fruit::Component<X> getParentComponent(int, std::string, Arg);
751
752            fruit::Component<X> getComponent() {
753              return fruit::createComponent()
754                .install(getParentComponent, 5, std::string("Hello"), Arg{});
755            }
756            '''
757        expect_generic_compile_error(
758            r'error: use of deleted function .std::hash<Arg>::hash\(\).'
759            r'|error: call to implicitly-deleted default constructor of .std::hash<Arg>.'
760            r'|error: invalid use of incomplete type .struct std::hash<Arg>.'
761            r'|error: implicit instantiation of undefined template .std::(__1::)?hash<Arg>.'
762            r'|error C2338: The C\+\+ Standard doesn.t provide a hash for this type.'
763            r'|error C2064: term does not evaluate to a function taking 1 arguments',
764            COMMON_DEFINITIONS,
765            source)
766
767    def test_install_with_args_error_not_hashable_with_conversion(self):
768        source = '''
769            struct Arg {
770              Arg(int) {}
771              Arg() = default;
772              Arg(const Arg&) = default;
773              Arg(Arg&&) = default;
774              Arg& operator=(const Arg&) = default;
775              Arg& operator=(Arg&&) = default;
776            };
777
778            bool operator==(const Arg&, const Arg&);
779
780            fruit::Component<X> getParentComponent(int, std::string, Arg);
781
782            fruit::Component<X> getComponent() {
783              return fruit::createComponent()
784                .install(getParentComponent, 5, std::string("Hello"), 15);
785            }
786            '''
787        expect_generic_compile_error(
788            r'error: use of deleted function .std::hash<Arg>::hash\(\).'
789            r'|error: call to implicitly-deleted default constructor of .std::hash<Arg>.'
790            r'|error: invalid use of incomplete type .struct std::hash<Arg>.'
791            r'|error: implicit instantiation of undefined template .std::(__1::)?hash<Arg>.'
792            r'|error C2338: The C\+\+ Standard doesn.t provide a hash for this type.'
793            r'|error C2064: term does not evaluate to a function taking 1 arguments',
794            COMMON_DEFINITIONS,
795            source)
796
797    @parameterized.parameters([
798        'X',
799        'fruit::Annotated<Annotation1, X>',
800    ])
801    def test_install_component_functions_deduped(self, XAnnot):
802        source = '''
803            struct X {};
804
805            X x;
806
807            fruit::Component<> getComponent() {
808              return fruit::createComponent()
809                .addInstanceMultibinding<XAnnot, X>(x);
810            }
811
812            fruit::Component<> getComponent2() {
813              return fruit::createComponent()
814                .install(getComponent);
815            }
816
817            fruit::Component<> getComponent3() {
818              return fruit::createComponent()
819                .install(getComponent);
820            }
821
822            fruit::Component<> getComponent4() {
823              return fruit::createComponent()
824                .install(getComponent2)
825                .install(getComponent3);
826            }
827
828            int main() {
829              fruit::Injector<> injector(getComponent4);
830
831              // We test multibindings because the effect on other bindings is not user-visible (that only affects
832              // performance).
833              std::vector<X*> multibindings = injector.getMultibindings<XAnnot>();
834              Assert(multibindings.size() == 1);
835              Assert(multibindings[0] == &x);
836            }
837            '''
838        expect_success(
839            COMMON_DEFINITIONS,
840            source,
841            locals())
842
843    @parameterized.parameters([
844        'X',
845        'fruit::Annotated<Annotation1, X>',
846    ])
847    def test_install_component_functions_deduped_across_normalized_component(self, XAnnot):
848        source = '''
849            struct X {};
850
851            X x;
852
853            fruit::Component<> getComponent() {
854              return fruit::createComponent()
855                .addInstanceMultibinding<XAnnot, X>(x);
856            }
857
858            fruit::Component<> getComponent2() {
859              return fruit::createComponent()
860                .install(getComponent);
861            }
862
863            fruit::Component<> getComponent3() {
864              return fruit::createComponent()
865                .install(getComponent);
866            }
867
868            int main() {
869              fruit::NormalizedComponent<> normalizedComponent(getComponent2);
870              fruit::Injector<> injector(normalizedComponent, getComponent3);
871
872              // We test multibindings because the effect on other bindings is not user-visible (that only affects
873              // performance).
874              std::vector<X*> multibindings = injector.getMultibindings<XAnnot>();
875              Assert(multibindings.size() == 1);
876              Assert(multibindings[0] == &x);
877            }
878            '''
879        expect_success(
880            COMMON_DEFINITIONS,
881            source,
882            locals())
883
884    @parameterized.parameters([
885        'X',
886        'fruit::Annotated<Annotation1, X>',
887    ])
888    def test_install_component_functions_with_args_deduped(self, XAnnot):
889        source = '''
890            struct X {};
891
892            X x;
893
894            fruit::Component<> getComponent(int) {
895              return fruit::createComponent()
896                .addInstanceMultibinding<XAnnot, X>(x);
897            }
898
899            fruit::Component<> getComponent2() {
900              return fruit::createComponent()
901                .install(getComponent, 1);
902            }
903
904            fruit::Component<> getComponent3() {
905              return fruit::createComponent()
906                .install(getComponent, 1);
907            }
908
909            fruit::Component<> getComponent4() {
910              return fruit::createComponent()
911                .install(getComponent2)
912                .install(getComponent3);
913            }
914
915            int main() {
916              fruit::Injector<> injector(getComponent4);
917
918              // We test multibindings because the effect on other bindings is not user-visible (that only affects
919              // performance).
920              std::vector<X*> multibindings = injector.getMultibindings<XAnnot>();
921              Assert(multibindings.size() == 1);
922              Assert(multibindings[0] == &x);
923            }
924            '''
925        expect_success(
926            COMMON_DEFINITIONS,
927            source,
928            locals())
929
930    @parameterized.parameters([
931        'X',
932        'fruit::Annotated<Annotation1, X>',
933    ])
934    def test_install_component_functions_different_args_not_deduped(self, XAnnot):
935        source = '''
936            struct X {};
937
938            X x;
939
940            fruit::Component<> getComponent(int) {
941              return fruit::createComponent()
942                .addInstanceMultibinding<XAnnot, X>(x);
943            }
944
945            fruit::Component<> getComponent2() {
946              return fruit::createComponent()
947                .install(getComponent, 1);
948            }
949
950            fruit::Component<> getComponent3() {
951              return fruit::createComponent()
952                .install(getComponent, 2);
953            }
954
955            fruit::Component<> getComponent4() {
956              return fruit::createComponent()
957                .install(getComponent2)
958                .install(getComponent3);
959            }
960
961            int main() {
962              fruit::Injector<> injector(getComponent4);
963
964              // We test multibindings because the effect on other bindings is not user-visible (it only affects
965              // performance).
966              std::vector<X*> multibindings = injector.getMultibindings<XAnnot>();
967              Assert(multibindings.size() == 2);
968              Assert(multibindings[0] == &x);
969              Assert(multibindings[1] == &x);
970            }
971            '''
972        expect_success(
973            COMMON_DEFINITIONS,
974            source,
975            locals())
976
977    def test_install_component_functions_loop(self):
978        source = '''
979            struct X {};
980            struct Y {};
981            struct Z {};
982
983            // X -> Y -> Z -> Y
984
985            fruit::Component<X> getXComponent();
986            fruit::Component<Y> getYComponent();
987            fruit::Component<Z> getZComponent();
988
989            fruit::Component<X> getXComponent() {
990              return fruit::createComponent()
991                  .registerConstructor<X()>()
992                  .install(getYComponent);
993            }
994
995            fruit::Component<Y> getYComponent() {
996              return fruit::createComponent()
997                  .registerConstructor<Y()>()
998                  .install(getZComponent);
999            }
1000
1001            fruit::Component<Z> getZComponent() {
1002              return fruit::createComponent()
1003                  .registerConstructor<Z()>()
1004                  .install(getYComponent);
1005            }
1006
1007            int main() {
1008              fruit::Injector<X> injector(getXComponent);
1009              (void)injector;
1010            }
1011            '''
1012        expect_runtime_error(
1013            r'Component installation trace \(from top-level to the most deeply-nested\):\n'
1014            r'(class )?fruit::Component<(struct )?X> ?\((__cdecl)?\*\)\((void)?\)\n'
1015            r'<-- The loop starts here\n'
1016            r'(class )?fruit::Component<(struct )?Y> ?\((__cdecl)?\*\)\((void)?\)\n'
1017            r'(class )?fruit::Component<(struct )?Z> ?\((__cdecl)?\*\)\((void)?\)\n'
1018            r'(class )?fruit::Component<(struct )?Y> ?\((__cdecl)?\*\)\((void)?\)\n',
1019            COMMON_DEFINITIONS,
1020            source,
1021            locals())
1022
1023    def test_install_component_functions_different_arguments_loop_not_reported(self):
1024        source = '''
1025            struct X {};
1026            struct Y {};
1027            struct Z {};
1028
1029            // X -> Y(1) -> Z -> Y(2)
1030
1031            fruit::Component<X> getXComponent();
1032            fruit::Component<Y> getYComponent(int);
1033            fruit::Component<Z> getZComponent();
1034
1035            fruit::Component<X> getXComponent() {
1036              return fruit::createComponent()
1037                  .registerConstructor<X()>()
1038                  .install(getYComponent, 1);
1039            }
1040
1041            fruit::Component<Y> getYComponent(int n) {
1042                if (n == 1) {
1043                    return fruit::createComponent()
1044                        .registerConstructor<Y()>()
1045                        .install(getZComponent);
1046                } else {
1047                    return fruit::createComponent()
1048                        .registerConstructor<Y()>();
1049                }
1050            }
1051
1052            fruit::Component<Z> getZComponent() {
1053              return fruit::createComponent()
1054                  .registerConstructor<Z()>()
1055                  .install(getYComponent, 2);
1056            }
1057
1058            int main() {
1059              fruit::Injector<X> injector(getXComponent);
1060              injector.get<X>();
1061            }
1062            '''
1063        expect_success(
1064            COMMON_DEFINITIONS,
1065            source,
1066            locals())
1067
1068if __name__ == '__main__':
1069    absltest.main()
1070