xref: /aosp_15_r20/external/google-fruit/tests/test_injected_provider.py (revision a65addddcf69f38db5b288d787b6b7571a57bb8f)
1*a65addddSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*a65addddSAndroid Build Coastguard Worker#  Copyright 2016 Google Inc. All Rights Reserved.
3*a65addddSAndroid Build Coastguard Worker#
4*a65addddSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*a65addddSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*a65addddSAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*a65addddSAndroid Build Coastguard Worker#
8*a65addddSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
9*a65addddSAndroid Build Coastguard Worker#
10*a65addddSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*a65addddSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS-IS" BASIS,
12*a65addddSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*a65addddSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*a65addddSAndroid Build Coastguard Worker# limitations under the License.
15*a65addddSAndroid Build Coastguard Worker
16*a65addddSAndroid Build Coastguard Workerfrom absl.testing import parameterized
17*a65addddSAndroid Build Coastguard Workerfrom fruit_test_common import *
18*a65addddSAndroid Build Coastguard Worker
19*a65addddSAndroid Build Coastguard WorkerCOMMON_DEFINITIONS = '''
20*a65addddSAndroid Build Coastguard Worker    #include "test_common.h"
21*a65addddSAndroid Build Coastguard Worker
22*a65addddSAndroid Build Coastguard Worker    struct X;
23*a65addddSAndroid Build Coastguard Worker
24*a65addddSAndroid Build Coastguard Worker    struct Annotation1 {};
25*a65addddSAndroid Build Coastguard Worker    using XAnnot = fruit::Annotated<Annotation1, X>;
26*a65addddSAndroid Build Coastguard Worker
27*a65addddSAndroid Build Coastguard Worker    struct Annotation2 {};
28*a65addddSAndroid Build Coastguard Worker    '''
29*a65addddSAndroid Build Coastguard Worker
30*a65addddSAndroid Build Coastguard Workerclass TestInjectedProvider(parameterized.TestCase):
31*a65addddSAndroid Build Coastguard Worker    @parameterized.parameters([
32*a65addddSAndroid Build Coastguard Worker        ('X*', r'X\*'),
33*a65addddSAndroid Build Coastguard Worker        ('const X*', r'const X\*'),
34*a65addddSAndroid Build Coastguard Worker        ('X&', r'X&'),
35*a65addddSAndroid Build Coastguard Worker        ('const X&', r'const X&'),
36*a65addddSAndroid Build Coastguard Worker        ('std::shared_ptr<X>', r'std::shared_ptr<X>'),
37*a65addddSAndroid Build Coastguard Worker    ])
38*a65addddSAndroid Build Coastguard Worker    def test_error_non_class_type_parameter(self, XVariant, XVariantRegexp):
39*a65addddSAndroid Build Coastguard Worker        source = '''
40*a65addddSAndroid Build Coastguard Worker            struct X {};
41*a65addddSAndroid Build Coastguard Worker
42*a65addddSAndroid Build Coastguard Worker            fruit::Provider<XVariant> provider;
43*a65addddSAndroid Build Coastguard Worker            '''
44*a65addddSAndroid Build Coastguard Worker        expect_compile_error(
45*a65addddSAndroid Build Coastguard Worker            'NonClassTypeError<XVariantRegexp,X>',
46*a65addddSAndroid Build Coastguard Worker            'A non-class type T was specified. Use C instead',
47*a65addddSAndroid Build Coastguard Worker            COMMON_DEFINITIONS,
48*a65addddSAndroid Build Coastguard Worker            source,
49*a65addddSAndroid Build Coastguard Worker            locals())
50*a65addddSAndroid Build Coastguard Worker
51*a65addddSAndroid Build Coastguard Worker    def test_error_annotated_type_parameter(self):
52*a65addddSAndroid Build Coastguard Worker        source = '''
53*a65addddSAndroid Build Coastguard Worker            struct X {};
54*a65addddSAndroid Build Coastguard Worker
55*a65addddSAndroid Build Coastguard Worker            fruit::Provider<XAnnot> provider;
56*a65addddSAndroid Build Coastguard Worker            '''
57*a65addddSAndroid Build Coastguard Worker        expect_compile_error(
58*a65addddSAndroid Build Coastguard Worker            'AnnotatedTypeError<fruit::Annotated<Annotation1,X>,X>',
59*a65addddSAndroid Build Coastguard Worker            'An annotated type was specified where a non-annotated type was expected.',
60*a65addddSAndroid Build Coastguard Worker            COMMON_DEFINITIONS,
61*a65addddSAndroid Build Coastguard Worker            source)
62*a65addddSAndroid Build Coastguard Worker
63*a65addddSAndroid Build Coastguard Worker    @parameterized.parameters([
64*a65addddSAndroid Build Coastguard Worker        ('X', 'fruit::Provider<X>', 'X', 'X'),
65*a65addddSAndroid Build Coastguard Worker        ('X', 'fruit::Provider<X>', 'X', 'const X&'),
66*a65addddSAndroid Build Coastguard Worker        ('X', 'fruit::Provider<X>', 'X', 'const X*'),
67*a65addddSAndroid Build Coastguard Worker        ('X', 'fruit::Provider<X>', 'X', 'X&'),
68*a65addddSAndroid Build Coastguard Worker        ('X', 'fruit::Provider<X>', 'X', 'X*'),
69*a65addddSAndroid Build Coastguard Worker        ('X', 'fruit::Provider<X>', 'X', 'std::shared_ptr<X>'),
70*a65addddSAndroid Build Coastguard Worker        ('X', 'fruit::Provider<X>', 'X', 'fruit::Provider<X>'),
71*a65addddSAndroid Build Coastguard Worker        ('X', 'fruit::Provider<X>', 'X', 'fruit::Provider<const X>'),
72*a65addddSAndroid Build Coastguard Worker        ('X', 'fruit::Provider<const X>', 'const X', 'const X&'),
73*a65addddSAndroid Build Coastguard Worker        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, fruit::Provider<X>>', 'X', 'const X&'),
74*a65addddSAndroid Build Coastguard Worker        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, fruit::Provider<const X>>', 'const X', 'const X&'),
75*a65addddSAndroid Build Coastguard Worker    ])
76*a65addddSAndroid Build Coastguard Worker    def test_provider_get_ok(self, XBindingInInjector, XProviderAnnot, XParamInProvider, XProviderGetParam):
77*a65addddSAndroid Build Coastguard Worker        source = '''
78*a65addddSAndroid Build Coastguard Worker            struct X {
79*a65addddSAndroid Build Coastguard Worker              using Inject = X();
80*a65addddSAndroid Build Coastguard Worker            };
81*a65addddSAndroid Build Coastguard Worker
82*a65addddSAndroid Build Coastguard Worker            fruit::Component<XBindingInInjector> getComponent() {
83*a65addddSAndroid Build Coastguard Worker              return fruit::createComponent();
84*a65addddSAndroid Build Coastguard Worker            }
85*a65addddSAndroid Build Coastguard Worker
86*a65addddSAndroid Build Coastguard Worker            int main() {
87*a65addddSAndroid Build Coastguard Worker              fruit::Injector<XBindingInInjector> injector(getComponent);
88*a65addddSAndroid Build Coastguard Worker              fruit::Provider<XParamInProvider> provider = injector.get<XProviderAnnot>();
89*a65addddSAndroid Build Coastguard Worker
90*a65addddSAndroid Build Coastguard Worker              XProviderGetParam x = provider.get<XProviderGetParam>();
91*a65addddSAndroid Build Coastguard Worker              (void)x;
92*a65addddSAndroid Build Coastguard Worker            }
93*a65addddSAndroid Build Coastguard Worker            '''
94*a65addddSAndroid Build Coastguard Worker        expect_success(
95*a65addddSAndroid Build Coastguard Worker            COMMON_DEFINITIONS,
96*a65addddSAndroid Build Coastguard Worker            source,
97*a65addddSAndroid Build Coastguard Worker            locals())
98*a65addddSAndroid Build Coastguard Worker
99*a65addddSAndroid Build Coastguard Worker    @parameterized.parameters([
100*a65addddSAndroid Build Coastguard Worker        ('const X', 'fruit::Provider<const X>', 'const X', 'X'),
101*a65addddSAndroid Build Coastguard Worker        ('const X', 'fruit::Provider<const X>', 'const X', 'const X&'),
102*a65addddSAndroid Build Coastguard Worker        ('const X', 'fruit::Provider<const X>', 'const X', 'const X*'),
103*a65addddSAndroid Build Coastguard Worker        ('const X', 'fruit::Provider<const X>', 'const X', 'fruit::Provider<const X>'),
104*a65addddSAndroid Build Coastguard Worker        ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, fruit::Provider<const X>>', 'const X', 'const X&'),
105*a65addddSAndroid Build Coastguard Worker    ])
106*a65addddSAndroid Build Coastguard Worker    def test_provider_get_const_binding_ok(self, XBindingInInjector, XProviderAnnot, XParamInProvider, XProviderGetParam):
107*a65addddSAndroid Build Coastguard Worker        XBindingInInjectorWithoutConst = XBindingInInjector.replace('const ', '')
108*a65addddSAndroid Build Coastguard Worker        source = '''
109*a65addddSAndroid Build Coastguard Worker            struct X {};
110*a65addddSAndroid Build Coastguard Worker
111*a65addddSAndroid Build Coastguard Worker            const X x{};
112*a65addddSAndroid Build Coastguard Worker
113*a65addddSAndroid Build Coastguard Worker            fruit::Component<XBindingInInjector> getComponent() {
114*a65addddSAndroid Build Coastguard Worker              return fruit::createComponent()
115*a65addddSAndroid Build Coastguard Worker                  .bindInstance<XBindingInInjectorWithoutConst, X>(x);
116*a65addddSAndroid Build Coastguard Worker            }
117*a65addddSAndroid Build Coastguard Worker
118*a65addddSAndroid Build Coastguard Worker            int main() {
119*a65addddSAndroid Build Coastguard Worker              fruit::Injector<XBindingInInjector> injector(getComponent);
120*a65addddSAndroid Build Coastguard Worker              fruit::Provider<XParamInProvider> provider = injector.get<XProviderAnnot>();
121*a65addddSAndroid Build Coastguard Worker
122*a65addddSAndroid Build Coastguard Worker              XProviderGetParam x = provider.get<XProviderGetParam>();
123*a65addddSAndroid Build Coastguard Worker              (void)x;
124*a65addddSAndroid Build Coastguard Worker            }
125*a65addddSAndroid Build Coastguard Worker            '''
126*a65addddSAndroid Build Coastguard Worker        expect_success(
127*a65addddSAndroid Build Coastguard Worker            COMMON_DEFINITIONS,
128*a65addddSAndroid Build Coastguard Worker            source,
129*a65addddSAndroid Build Coastguard Worker            locals())
130*a65addddSAndroid Build Coastguard Worker
131*a65addddSAndroid Build Coastguard Worker    def test_provider_get_during_injection_ok(self):
132*a65addddSAndroid Build Coastguard Worker        source = '''
133*a65addddSAndroid Build Coastguard Worker            struct X {
134*a65addddSAndroid Build Coastguard Worker              INJECT(X()) = default;
135*a65addddSAndroid Build Coastguard Worker              void foo() {
136*a65addddSAndroid Build Coastguard Worker              }
137*a65addddSAndroid Build Coastguard Worker            };
138*a65addddSAndroid Build Coastguard Worker
139*a65addddSAndroid Build Coastguard Worker            struct Y {
140*a65addddSAndroid Build Coastguard Worker              X x;
141*a65addddSAndroid Build Coastguard Worker              INJECT(Y(fruit::Provider<X> xProvider))
142*a65addddSAndroid Build Coastguard Worker                : x(xProvider.get<X>()) {
143*a65addddSAndroid Build Coastguard Worker              }
144*a65addddSAndroid Build Coastguard Worker
145*a65addddSAndroid Build Coastguard Worker              void foo() {
146*a65addddSAndroid Build Coastguard Worker                x.foo();
147*a65addddSAndroid Build Coastguard Worker              }
148*a65addddSAndroid Build Coastguard Worker            };
149*a65addddSAndroid Build Coastguard Worker
150*a65addddSAndroid Build Coastguard Worker            struct Z {
151*a65addddSAndroid Build Coastguard Worker              Y y;
152*a65addddSAndroid Build Coastguard Worker              INJECT(Z(fruit::Provider<Y> yProvider))
153*a65addddSAndroid Build Coastguard Worker                  : y(yProvider.get<Y>()) {
154*a65addddSAndroid Build Coastguard Worker              }
155*a65addddSAndroid Build Coastguard Worker
156*a65addddSAndroid Build Coastguard Worker              void foo() {
157*a65addddSAndroid Build Coastguard Worker                y.foo();
158*a65addddSAndroid Build Coastguard Worker              }
159*a65addddSAndroid Build Coastguard Worker            };
160*a65addddSAndroid Build Coastguard Worker
161*a65addddSAndroid Build Coastguard Worker            fruit::Component<Z> getZComponent() {
162*a65addddSAndroid Build Coastguard Worker              return fruit::createComponent();
163*a65addddSAndroid Build Coastguard Worker            }
164*a65addddSAndroid Build Coastguard Worker
165*a65addddSAndroid Build Coastguard Worker            int main() {
166*a65addddSAndroid Build Coastguard Worker              fruit::Injector<Z> injector(getZComponent);
167*a65addddSAndroid Build Coastguard Worker              fruit::Provider<Z> provider(injector);
168*a65addddSAndroid Build Coastguard Worker              // During provider.get<Z>(), yProvider.get() is called, and during that xProvider.get()
169*a65addddSAndroid Build Coastguard Worker              // is called.
170*a65addddSAndroid Build Coastguard Worker              Z z = provider.get<Z>();
171*a65addddSAndroid Build Coastguard Worker              z.foo();
172*a65addddSAndroid Build Coastguard Worker            }
173*a65addddSAndroid Build Coastguard Worker            '''
174*a65addddSAndroid Build Coastguard Worker        expect_success(
175*a65addddSAndroid Build Coastguard Worker            COMMON_DEFINITIONS,
176*a65addddSAndroid Build Coastguard Worker            source)
177*a65addddSAndroid Build Coastguard Worker
178*a65addddSAndroid Build Coastguard Worker    def test_provider_get_error_type_not_provided(self):
179*a65addddSAndroid Build Coastguard Worker        source = '''
180*a65addddSAndroid Build Coastguard Worker            struct X {};
181*a65addddSAndroid Build Coastguard Worker            struct Y {};
182*a65addddSAndroid Build Coastguard Worker
183*a65addddSAndroid Build Coastguard Worker            void f(fruit::Provider<X> provider) {
184*a65addddSAndroid Build Coastguard Worker              provider.get<Y>();
185*a65addddSAndroid Build Coastguard Worker            }
186*a65addddSAndroid Build Coastguard Worker            '''
187*a65addddSAndroid Build Coastguard Worker        expect_compile_error(
188*a65addddSAndroid Build Coastguard Worker            'TypeNotProvidedError<Y>',
189*a65addddSAndroid Build Coastguard Worker            'Trying to get an instance of T, but it is not provided by this Provider/Injector.',
190*a65addddSAndroid Build Coastguard Worker            COMMON_DEFINITIONS,
191*a65addddSAndroid Build Coastguard Worker            source)
192*a65addddSAndroid Build Coastguard Worker
193*a65addddSAndroid Build Coastguard Worker    @parameterized.parameters([
194*a65addddSAndroid Build Coastguard Worker        ('X**', r'X\*\*'),
195*a65addddSAndroid Build Coastguard Worker        ('std::shared_ptr<X>*', r'std::shared_ptr<X>\*'),
196*a65addddSAndroid Build Coastguard Worker        ('const std::shared_ptr<X>', r'const std::shared_ptr<X>'),
197*a65addddSAndroid Build Coastguard Worker        ('X* const', r'X\* const'),
198*a65addddSAndroid Build Coastguard Worker        ('const X* const', r'const X\* const'),
199*a65addddSAndroid Build Coastguard Worker        ('std::nullptr_t', r'(std::)?nullptr(_t)?'),
200*a65addddSAndroid Build Coastguard Worker        ('X*&', r'X\*&'),
201*a65addddSAndroid Build Coastguard Worker        ('X(*)()', r'X(\((__cdecl)?\*\))?\((void)?\)'),
202*a65addddSAndroid Build Coastguard Worker        ('void', r'void'),
203*a65addddSAndroid Build Coastguard Worker        ('fruit::Annotated<Annotation1, fruit::Annotated<Annotation1, X>>', r'fruit::Annotated<Annotation1, X>'),
204*a65addddSAndroid Build Coastguard Worker    ])
205*a65addddSAndroid Build Coastguard Worker    def test_provider_get_error_type_not_injectable(self, XVariant, XVariantRegex):
206*a65addddSAndroid Build Coastguard Worker        source = '''
207*a65addddSAndroid Build Coastguard Worker            struct X {};
208*a65addddSAndroid Build Coastguard Worker
209*a65addddSAndroid Build Coastguard Worker            void f(fruit::Provider<X> provider) {
210*a65addddSAndroid Build Coastguard Worker              provider.get<XVariant>();
211*a65addddSAndroid Build Coastguard Worker            }
212*a65addddSAndroid Build Coastguard Worker            '''
213*a65addddSAndroid Build Coastguard Worker        expect_compile_error(
214*a65addddSAndroid Build Coastguard Worker            'NonInjectableTypeError<XVariantRegex>',
215*a65addddSAndroid Build Coastguard Worker            'The type T is not injectable',
216*a65addddSAndroid Build Coastguard Worker            COMMON_DEFINITIONS,
217*a65addddSAndroid Build Coastguard Worker            source,
218*a65addddSAndroid Build Coastguard Worker            locals())
219*a65addddSAndroid Build Coastguard Worker
220*a65addddSAndroid Build Coastguard Worker    @parameterized.parameters([
221*a65addddSAndroid Build Coastguard Worker        ('X&', r'X&'),
222*a65addddSAndroid Build Coastguard Worker        ('X*', r'X\*'),
223*a65addddSAndroid Build Coastguard Worker        ('std::shared_ptr<X>', r'std::shared_ptr<X>'),
224*a65addddSAndroid Build Coastguard Worker        ('fruit::Provider<X>', r'fruit::Provider<X>'),
225*a65addddSAndroid Build Coastguard Worker    ])
226*a65addddSAndroid Build Coastguard Worker    def test_const_provider_get_does_not_allow_injecting_nonconst_variants(self, XProviderGetParam, XProviderGetParamRegex):
227*a65addddSAndroid Build Coastguard Worker        source = '''
228*a65addddSAndroid Build Coastguard Worker            void f(fruit::Provider<const X> provider) {
229*a65addddSAndroid Build Coastguard Worker              provider.get<XProviderGetParam>();
230*a65addddSAndroid Build Coastguard Worker            }
231*a65addddSAndroid Build Coastguard Worker            '''
232*a65addddSAndroid Build Coastguard Worker        expect_compile_error(
233*a65addddSAndroid Build Coastguard Worker            'TypeProvidedAsConstOnlyError<XProviderGetParamRegex>',
234*a65addddSAndroid Build Coastguard Worker            'Trying to get an instance of T, but it is only provided as a constant by this Provider/Injector',
235*a65addddSAndroid Build Coastguard Worker            COMMON_DEFINITIONS,
236*a65addddSAndroid Build Coastguard Worker            source,
237*a65addddSAndroid Build Coastguard Worker            locals())
238*a65addddSAndroid Build Coastguard Worker
239*a65addddSAndroid Build Coastguard Worker    @parameterized.parameters([
240*a65addddSAndroid Build Coastguard Worker        ('fruit::Provider<Y>'),
241*a65addddSAndroid Build Coastguard Worker        ('ANNOTATED(Annotation1, fruit::Provider<Y>)'),
242*a65addddSAndroid Build Coastguard Worker    ])
243*a65addddSAndroid Build Coastguard Worker    def test_lazy_injection_with_annotations(self, Y_PROVIDER_ANNOT):
244*a65addddSAndroid Build Coastguard Worker        source = '''
245*a65addddSAndroid Build Coastguard Worker            struct Y : public ConstructionTracker<Y> {
246*a65addddSAndroid Build Coastguard Worker              using Inject = Y();
247*a65addddSAndroid Build Coastguard Worker            };
248*a65addddSAndroid Build Coastguard Worker
249*a65addddSAndroid Build Coastguard Worker            struct X : public ConstructionTracker<X> {
250*a65addddSAndroid Build Coastguard Worker              INJECT(X(Y_PROVIDER_ANNOT provider)) : provider(provider) {
251*a65addddSAndroid Build Coastguard Worker              }
252*a65addddSAndroid Build Coastguard Worker
253*a65addddSAndroid Build Coastguard Worker              void run() {
254*a65addddSAndroid Build Coastguard Worker                Y* y(provider);
255*a65addddSAndroid Build Coastguard Worker                (void) y;
256*a65addddSAndroid Build Coastguard Worker              }
257*a65addddSAndroid Build Coastguard Worker
258*a65addddSAndroid Build Coastguard Worker              fruit::Provider<Y> provider;
259*a65addddSAndroid Build Coastguard Worker            };
260*a65addddSAndroid Build Coastguard Worker
261*a65addddSAndroid Build Coastguard Worker            fruit::Component<X> getComponent() {
262*a65addddSAndroid Build Coastguard Worker              return fruit::createComponent();
263*a65addddSAndroid Build Coastguard Worker            }
264*a65addddSAndroid Build Coastguard Worker
265*a65addddSAndroid Build Coastguard Worker            fruit::Component<> getEmptyComponent() {
266*a65addddSAndroid Build Coastguard Worker              return fruit::createComponent();
267*a65addddSAndroid Build Coastguard Worker            }
268*a65addddSAndroid Build Coastguard Worker
269*a65addddSAndroid Build Coastguard Worker            int main() {
270*a65addddSAndroid Build Coastguard Worker              fruit::NormalizedComponent<> normalizedComponent(getEmptyComponent);
271*a65addddSAndroid Build Coastguard Worker              fruit::Injector<X> injector(normalizedComponent, getComponent);
272*a65addddSAndroid Build Coastguard Worker
273*a65addddSAndroid Build Coastguard Worker              Assert(X::num_objects_constructed == 0);
274*a65addddSAndroid Build Coastguard Worker              Assert(Y::num_objects_constructed == 0);
275*a65addddSAndroid Build Coastguard Worker
276*a65addddSAndroid Build Coastguard Worker              X* x(injector);
277*a65addddSAndroid Build Coastguard Worker
278*a65addddSAndroid Build Coastguard Worker              Assert(X::num_objects_constructed == 1);
279*a65addddSAndroid Build Coastguard Worker              Assert(Y::num_objects_constructed == 0);
280*a65addddSAndroid Build Coastguard Worker
281*a65addddSAndroid Build Coastguard Worker              x->run();
282*a65addddSAndroid Build Coastguard Worker
283*a65addddSAndroid Build Coastguard Worker              Assert(X::num_objects_constructed == 1);
284*a65addddSAndroid Build Coastguard Worker              Assert(Y::num_objects_constructed == 1);
285*a65addddSAndroid Build Coastguard Worker            }
286*a65addddSAndroid Build Coastguard Worker            '''
287*a65addddSAndroid Build Coastguard Worker        expect_success(
288*a65addddSAndroid Build Coastguard Worker            COMMON_DEFINITIONS,
289*a65addddSAndroid Build Coastguard Worker            source,
290*a65addddSAndroid Build Coastguard Worker            locals())
291*a65addddSAndroid Build Coastguard Worker
292*a65addddSAndroid Build Coastguard Workerif __name__ == '__main__':
293*a65addddSAndroid Build Coastguard Worker    absltest.main()
294