xref: /aosp_15_r20/external/google-fruit/tests/test_register_constructor.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 XAnnot = fruit::Annotated<Annotation1, X>;
26
27    struct Annotation2 {};
28
29    struct Annotation3 {};
30
31    template <typename T>
32    using WithNoAnnotation = T;
33
34    template <typename T>
35    using WithAnnotation1 = fruit::Annotated<Annotation1, T>;
36    '''
37
38class TestRegisterConstructor(parameterized.TestCase):
39
40    def test_register_constructor_success_copyable_and_movable(self):
41        source = '''
42            struct X {
43              INJECT(X()) = default;
44              X(X&&) = default;
45              X(const X&) = default;
46            };
47
48            fruit::Component<X> getComponent() {
49              return fruit::createComponent();
50            }
51
52            int main() {
53              fruit::Injector<X> injector(getComponent);
54              injector.get<X*>();
55            }
56            '''
57        expect_success(
58            COMMON_DEFINITIONS,
59            source)
60
61    def test_register_constructor_success_movable_only(self):
62        source = '''
63            struct X {
64              INJECT(X()) = default;
65              X(X&&) = default;
66              X(const X&) = delete;
67            };
68
69            fruit::Component<X> getComponent() {
70              return fruit::createComponent();
71            }
72
73            int main() {
74              fruit::Injector<X> injector(getComponent);
75              injector.get<X*>();
76            }
77            '''
78        expect_success(
79            COMMON_DEFINITIONS,
80            source)
81
82    def test_register_constructor_success_not_movable(self):
83        source = '''
84            struct X {
85              INJECT(X()) = default;
86              X(X&&) = delete;
87              X(const X&) = delete;
88            };
89
90            fruit::Component<X> getComponent() {
91              return fruit::createComponent();
92            }
93
94            int main() {
95              fruit::Injector<X> injector(getComponent);
96              injector.get<X*>();
97            }
98            '''
99        expect_success(
100            COMMON_DEFINITIONS,
101            source)
102
103    # TODO: consider moving to test_normalized_component.py
104    @parameterized.parameters([
105        ('X', 'Y', 'Y', 'Z'),
106        ('X', 'Y', 'const Y', 'Z'),
107        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, Y>', 'fruit::Annotated<Annotation2, const Y>', 'fruit::Annotated<Annotation3, Z>'),
108    ])
109    def test_autoinject_with_annotation_success(self, XAnnot, YAnnot, MaybeConstYAnnot, ZAnnot):
110        source = '''
111            struct X {
112              using Inject = X();
113            };
114
115            struct Y : public ConstructionTracker<Y> {
116              using Inject = Y();
117            };
118
119            struct Z {
120              using Inject = Z();
121            };
122
123            fruit::Component<ZAnnot, MaybeConstYAnnot, XAnnot> getComponent() {
124              return fruit::createComponent();
125            }
126
127            fruit::Component<> getEmptyComponent() {
128              return fruit::createComponent();
129            }
130
131            int main() {
132              fruit::NormalizedComponent<> normalizedComponent(getEmptyComponent);
133              fruit::Injector<MaybeConstYAnnot> injector(normalizedComponent, getComponent);
134
135              Assert(Y::num_objects_constructed == 0);
136              injector.get<YAnnot>();
137              Assert(Y::num_objects_constructed == 1);
138            }
139            '''
140        expect_success(
141            COMMON_DEFINITIONS,
142            source,
143            locals())
144
145    def test_autoinject_annotation_in_signature_return_type(self):
146        source = '''
147            struct X {
148              using Inject = XAnnot();
149            };
150
151            fruit::Component<XAnnot> getComponent() {
152              return fruit::createComponent();
153            }
154            '''
155        expect_compile_error(
156            'InjectTypedefWithAnnotationError<X>',
157            'C::Inject is a signature that returns an annotated type',
158            COMMON_DEFINITIONS,
159            source)
160
161    def test_autoinject_wrong_class_in_typedef(self):
162        source = '''
163            struct X {
164              using Inject = X();
165            };
166
167            struct Y : public X {
168            };
169
170            fruit::Component<Y> getComponent() {
171              return fruit::createComponent();
172            }
173            '''
174        expect_compile_error(
175            'InjectTypedefForWrongClassError<Y,X>',
176            'C::Inject is a signature, but does not return a C. Maybe the class C has no Inject typedef and',
177            COMMON_DEFINITIONS,
178            source)
179
180    def test_register_constructor_error_abstract_class(self):
181        if re.search('MSVC', CXX_COMPILER_NAME) is not None:
182            # MSVC allows to construct the type X(int*) but SignatureType<Type<X(int*)>> doesn't find the
183            # specialization.
184            return
185        source = '''
186            struct X {
187              X(int*) {}
188
189              virtual void foo() = 0;
190            };
191
192            fruit::Component<X> getComponent() {
193              return fruit::createComponent()
194                .registerConstructor<fruit::Annotated<Annotation1, X>(int*)>();
195            }
196            '''
197        # Some compilers give a generic compile error, some don't and then Fruit reports the error.
198        try:
199            expect_generic_compile_error(
200                'invalid abstract return type'
201                '|.X.: cannot instantiate abstract class',
202                COMMON_DEFINITIONS,
203                source)
204        except:
205            expect_compile_error(
206                'CannotConstructAbstractClassError<X>',
207                'The specified class can.t be constructed because it.s an abstract class',
208                COMMON_DEFINITIONS,
209                source)
210
211    def test_register_constructor_error_malformed_signature(self):
212        source = '''
213            struct X {
214              X(int) {}
215            };
216
217            fruit::Component<X> getComponent() {
218              return fruit::createComponent()
219                .registerConstructor<X[]>();
220            }
221            '''
222        expect_compile_error(
223            r'NotASignatureError<X\[\]>',
224            r'CandidateSignature was specified as parameter, but it.s not a signature. Signatures are of the form',
225            COMMON_DEFINITIONS,
226            source)
227
228    def test_register_constructor_error_malformed_signature_autoinject(self):
229        source = '''
230            struct X {
231              using Inject = X[];
232              X(int) {}
233            };
234
235            fruit::Component<X> getComponent() {
236              return fruit::createComponent();
237            }
238            '''
239        expect_compile_error(
240            r'InjectTypedefNotASignatureError<X,X\[\]>',
241            r'C::Inject should be a typedef to a signature',
242            COMMON_DEFINITIONS,
243            source)
244
245    @parameterized.parameters([
246        'char*',
247        'fruit::Annotated<Annotation1, char*>',
248    ])
249    def test_register_constructor_does_not_exist_error(self, charPtrAnnot):
250        source = '''
251            struct X {
252              X(int*) {}
253            };
254
255            fruit::Component<X> getComponent() {
256              return fruit::createComponent()
257                .registerConstructor<X(charPtrAnnot)>();
258            }
259            '''
260        expect_compile_error(
261            r'NoConstructorMatchingInjectSignatureError<X,X\(char\*\)>',
262            r'contains an Inject typedef but it.s not constructible with the specified types',
263            COMMON_DEFINITIONS,
264            source,
265            locals())
266
267    @parameterized.parameters([
268        'char*',
269        'fruit::Annotated<Annotation1, char*>',
270    ])
271    def test_autoinject_constructor_does_not_exist_error(self, charPtrAnnot):
272        source = '''
273            struct X {
274              using Inject = X(charPtrAnnot);
275              X(int*) {}
276            };
277
278            fruit::Component<X> getComponent() {
279              return fruit::createComponent();
280            }
281            '''
282        expect_compile_error(
283            r'NoConstructorMatchingInjectSignatureError<X,X\(char\*\)>',
284            r'contains an Inject typedef but it.s not constructible with the specified types',
285            COMMON_DEFINITIONS,
286            source,
287            locals())
288
289    def test_autoinject_abstract_class_error(self):
290        source = '''
291            struct X {
292              using Inject = fruit::Annotated<Annotation1, X>();
293
294              virtual void scale() = 0;
295              // Note: here we "forgot" to implement scale() (on purpose, for this test) so X is an abstract class.
296            };
297
298            fruit::Component<fruit::Annotated<Annotation1, X>> getComponent() {
299              return fruit::createComponent();
300            }
301            '''
302        expect_compile_error(
303            'CannotConstructAbstractClassError<X>',
304            'The specified class can.t be constructed because it.s an abstract class.',
305            COMMON_DEFINITIONS,
306            source)
307
308    @multiple_parameters([
309        'WithNoAnnotation',
310        'WithAnnotation1',
311    ], [
312        'Y',
313        'const Y',
314        'Y*',
315        'const Y*',
316        'Y&',
317        'const Y&',
318        'std::shared_ptr<Y>',
319        'fruit::Provider<Y>',
320        'fruit::Provider<const Y>',
321    ])
322    def test_register_constructor_with_param_success(self, WithAnnotation, YVariant):
323        source = '''
324            struct Y {};
325            struct X {
326              X(YVariant) {
327              }
328            };
329
330            fruit::Component<WithAnnotation<Y>> getYComponent() {
331              return fruit::createComponent()
332                .registerConstructor<WithAnnotation<Y>()>();
333            }
334
335            fruit::Component<X> getComponent() {
336              return fruit::createComponent()
337                .install(getYComponent)
338                .registerConstructor<X(WithAnnotation<YVariant>)>();
339            }
340
341            int main() {
342              fruit::Injector<X> injector(getComponent);
343              injector.get<X>();
344            }
345            '''
346        expect_success(
347            COMMON_DEFINITIONS,
348            source,
349            locals())
350
351    @multiple_parameters([
352        'WithNoAnnotation',
353        'WithAnnotation1',
354    ], [
355        'Y',
356        'const Y',
357        'const Y*',
358        'const Y&',
359        'fruit::Provider<const Y>',
360    ])
361    def test_register_constructor_with_param_const_binding_success(self, WithAnnotation, YVariant):
362        source = '''
363            struct Y {};
364            struct X {
365              X(YVariant) {
366              }
367            };
368
369            const Y y{};
370
371            fruit::Component<WithAnnotation<const Y>> getYComponent() {
372              return fruit::createComponent()
373                .bindInstance<WithAnnotation<Y>, Y>(y);
374            }
375
376            fruit::Component<X> getComponent() {
377              return fruit::createComponent()
378                .install(getYComponent)
379                .registerConstructor<X(WithAnnotation<YVariant>)>();
380            }
381
382            int main() {
383              fruit::Injector<X> injector(getComponent);
384              injector.get<X>();
385            }
386            '''
387        expect_success(
388            COMMON_DEFINITIONS,
389            source,
390            locals())
391
392    @multiple_parameters([
393        ('WithNoAnnotation', 'Y'),
394        ('WithAnnotation1', 'fruit::Annotated<Annotation1,Y>'),
395    ], [
396        'Y*',
397        'Y&',
398        'std::shared_ptr<Y>',
399        'fruit::Provider<Y>',
400    ])
401    def test_register_constructor_with_param_error_nonconst_param_required(self, WithAnnotation, YAnnotRegex, YVariant):
402        source = '''
403            struct Y {};
404            struct X {
405              X(YVariant);
406            };
407
408            fruit::Component<WithAnnotation<const Y>> getYComponent();
409
410            fruit::Component<> getComponent() {
411              return fruit::createComponent()
412                .install(getYComponent)
413                .registerConstructor<X(WithAnnotation<YVariant>)>();
414            }
415            '''
416        expect_compile_error(
417            'NonConstBindingRequiredButConstBindingProvidedError<YAnnotRegex>',
418            'The type T was provided as constant, however one of the constructors/providers/factories in this component',
419            COMMON_DEFINITIONS,
420            source,
421            locals())
422
423    @multiple_parameters([
424        ('WithNoAnnotation', 'Y'),
425        ('WithAnnotation1', 'fruit::Annotated<Annotation1, Y>'),
426    ], [
427        'Y*',
428        'Y&',
429        'std::shared_ptr<Y>',
430        'fruit::Provider<Y>',
431    ])
432    def test_register_constructor_with_param_error_nonconst_param_required_install_after(self, WithAnnotation, YAnnotRegex, YVariant):
433        source = '''
434            struct Y {};
435            struct X {
436              X(YVariant);
437            };
438
439            fruit::Component<WithAnnotation<const Y>> getYComponent();
440
441            fruit::Component<> getComponent() {
442              return fruit::createComponent()
443                .registerConstructor<X(WithAnnotation<YVariant>)>()
444                .install(getYComponent);
445            }
446            '''
447        expect_compile_error(
448            'NonConstBindingRequiredButConstBindingProvidedError<YAnnotRegex>',
449            'The type T was provided as constant, however one of the constructors/providers/factories in this component',
450            COMMON_DEFINITIONS,
451            source,
452            locals())
453
454    def test_register_constructor_requiring_nonconst_then_requiring_const_ok(self):
455        source = '''
456            struct X {};
457
458            struct Y {
459              Y(X&) {}
460            };
461
462            struct Z {
463              Z(const X&) {}
464            };
465
466            fruit::Component<Y, Z> getRootComponent() {
467              return fruit::createComponent()
468                .registerConstructor<Y(X&)>()
469                .registerConstructor<Z(const X&)>()
470                .registerConstructor<X()>();
471            }
472
473            int main() {
474              fruit::Injector<Y, Z> injector(getRootComponent);
475              injector.get<Y>();
476              injector.get<Z>();
477            }
478            '''
479        expect_success(
480            COMMON_DEFINITIONS,
481            source,
482            locals())
483
484    def test_register_constructor_requiring_nonconst_then_requiring_const_declaring_const_requirement_error(self):
485        source = '''
486            struct X {};
487
488            struct Y {
489              Y(X&) {}
490            };
491
492            struct Z {
493              Z(const X&) {}
494            };
495
496            fruit::Component<fruit::Required<const X>, Y, Z> getRootComponent() {
497              return fruit::createComponent()
498                .registerConstructor<Y(X&)>()
499                .registerConstructor<Z(const X&)>();
500            }
501            '''
502        expect_compile_error(
503            'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<X>',
504            'The type T was declared as a const Required type in the returned Component, however',
505            COMMON_DEFINITIONS,
506            source,
507            locals())
508
509    def test_register_constructor_requiring_const_then_requiring_nonconst_ok(self):
510        source = '''
511            struct X {};
512
513            struct Y {
514              Y(const X&) {}
515            };
516
517            struct Z {
518              Z(X&) {}
519            };
520
521            fruit::Component<Y, Z> getRootComponent() {
522              return fruit::createComponent()
523                .registerConstructor<Y(const X&)>()
524                .registerConstructor<Z(X&)>()
525                .registerConstructor<X()>();
526            }
527
528            int main() {
529              fruit::Injector<Y, Z> injector(getRootComponent);
530              injector.get<Y>();
531              injector.get<Z>();
532            }
533            '''
534        expect_success(
535            COMMON_DEFINITIONS,
536            source,
537            locals())
538
539    def test_register_constructor_requiring_const_then_requiring_nonconst_declaring_const_requirement_error(self):
540        source = '''
541            struct X {};
542
543            struct Y {
544              Y(const X&) {}
545            };
546
547            struct Z {
548              Z(X&) {}
549            };
550
551            fruit::Component<fruit::Required<const X>, Y, Z> getRootComponent() {
552              return fruit::createComponent()
553                .registerConstructor<Y(const X&)>()
554                .registerConstructor<Z(X&)>();
555            }
556            '''
557        expect_compile_error(
558            'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<X>',
559            'The type T was declared as a const Required type in the returned Component, however',
560            COMMON_DEFINITIONS,
561            source,
562            locals())
563
564    @parameterized.parameters([
565        ('Y**', r'Y\*\*'),
566        ('std::shared_ptr<Y>*', r'std::shared_ptr<Y>\*'),
567        ('std::nullptr_t', r'(std::)?nullptr(_t)?'),
568        ('Y*&', r'Y\*&'),
569        ('Y(*)()', r'Y(\((__cdecl)?\*\))?\((void)?\)'),
570        ('fruit::Annotated<Annotation1, Y**>', r'Y\*\*'),
571    ])
572    def test_register_constructor_with_param_error_type_not_injectable(self, YVariant, YVariantRegex):
573        source = '''
574            struct Y {};
575            struct X {
576              X(YVariant);
577            };
578
579            fruit::Component<> getComponent() {
580              return fruit::createComponent()
581                .registerConstructor<X(YVariant)>();
582            }
583            '''
584        expect_compile_error(
585            'NonInjectableTypeError<YVariantRegex>',
586            'The type T is not injectable.',
587            COMMON_DEFINITIONS,
588            source,
589            locals())
590
591    def test_register_constructor_error_assisted_param(self):
592        source = '''
593            struct X {
594              INJECT(X(ASSISTED(double) factor)) {
595                (void) factor;
596              }
597            };
598
599            fruit::Component<X> getComponent() {
600              return fruit::createComponent()
601                .registerConstructor<X(fruit::Assisted<double>)>();
602            }
603            '''
604        expect_compile_error(
605            'AssistedParamInRegisterConstructorSignatureError<X\\(fruit::Assisted<double>\\)>',
606            'CandidateSignature was used as signature for a registerConstructor.* but it contains an assisted parameter.',
607            COMMON_DEFINITIONS,
608            source,
609            locals())
610
611    def test_implicit_register_constructor_error_assisted_param(self):
612        source = '''
613            struct X {
614              INJECT(X(ASSISTED(double) factor)) {
615                (void) factor;
616              }
617            };
618
619            fruit::Component<X> getComponent() {
620              return fruit::createComponent();
621            }
622            '''
623        expect_compile_error(
624            'AssistedParamInRegisterConstructorSignatureError<X\\(fruit::Assisted<double>\\)>',
625            'CandidateSignature was used as signature for a registerConstructor.* but it contains an assisted parameter.',
626            COMMON_DEFINITIONS,
627            source,
628            locals())
629
630
631
632if __name__ == '__main__':
633    absltest.main()
634