xref: /aosp_15_r20/external/google-fruit/tests/test_injector.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    struct Annotation2 {};
28    using XAnnot2 = fruit::Annotated<Annotation2, X>;
29    '''
30
31class TestInjector(parameterized.TestCase):
32    def test_empty_injector(self):
33        source = '''
34            fruit::Component<> getComponent() {
35              return fruit::createComponent();
36            }
37
38            int main() {
39              fruit::Injector<> injector(getComponent);
40            }
41            '''
42        expect_success(
43            COMMON_DEFINITIONS,
44            source)
45
46    @parameterized.parameters([
47        'X',
48        'fruit::Annotated<Annotation1, X>',
49    ])
50    def test_error_component_with_requirements(self, XAnnot):
51        source = '''
52            struct X {};
53
54            fruit::Component<fruit::Required<XAnnot>> getComponent();
55
56            void f(fruit::NormalizedComponent<XAnnot> normalizedComponent) {
57              fruit::Injector<XAnnot> injector(normalizedComponent, getComponent);
58            }
59            '''
60        expect_compile_error(
61            'ComponentWithRequirementsInInjectorError<XAnnot>',
62            'When using the two-argument constructor of Injector, the component used as second parameter must not have requirements',
63            COMMON_DEFINITIONS,
64            source,
65            locals())
66
67    @parameterized.parameters([
68        'X',
69        'fruit::Annotated<Annotation1, X>',
70    ])
71    def test_error_declared_types_not_provided(self, XAnnot):
72        source = '''
73            struct X {
74              using Inject = X();
75            };
76
77            fruit::Component<> getEmptyComponent() {
78              return fruit::createComponent();
79            }
80
81            int main() {
82              fruit::NormalizedComponent<> normalizedComponent(getEmptyComponent);
83              fruit::Injector<XAnnot> injector(normalizedComponent, getEmptyComponent);
84            }
85            '''
86        expect_compile_error(
87            'TypesInInjectorNotProvidedError<XAnnot>',
88            'The types in TypesNotProvided are declared as provided by the injector, but none of the two components passed to the Injector constructor provides them.',
89            COMMON_DEFINITIONS,
90            source,
91            locals())
92
93    @parameterized.parameters([
94        ('X', 'const X'),
95        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'),
96    ])
97    def test_error_declared_nonconst_types_provided_as_const(self, XAnnot, ConstXAnnot):
98        source = '''
99            struct X {
100              using Inject = X();
101            };
102
103            fruit::Component<ConstXAnnot> getComponent();
104
105            int main() {
106              fruit::Injector<XAnnot> injector(getComponent);
107            }
108            '''
109        expect_generic_compile_error(
110            r'no matching constructor for initialization of .fruit::Injector<XAnnot>.'
111            r'|no matching function for call to .fruit::Injector<XAnnot>::Injector\(fruit::Component<ConstXAnnot> \(&\)\(\)\).'
112            # MSVC
113            r'|.fruit::Injector<XAnnot>::Injector.: no overloaded function could convert all the argument types'
114            r'|.fruit::Injector<XAnnot>::Injector.: none of the 2 overloads could convert all the argument types',
115            COMMON_DEFINITIONS,
116            source,
117            locals())
118
119    @parameterized.parameters([
120        ('X', 'const X'),
121        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'),
122    ])
123    def test_error_declared_nonconst_types_provided_as_const_with_normalized_component(self, XAnnot, ConstXAnnot):
124        source = '''
125            struct X {};
126
127            fruit::Component<> getEmptyComponent();
128
129            void f(fruit::NormalizedComponent<ConstXAnnot> normalizedComponent) {
130              fruit::Injector<XAnnot> injector(normalizedComponent, getEmptyComponent);
131            }
132            '''
133        expect_compile_error(
134            'TypesInInjectorProvidedAsConstOnlyError<XAnnot>',
135            'The types in TypesProvidedAsConstOnly are declared as non-const provided types by the injector',
136            COMMON_DEFINITIONS,
137            source,
138            locals())
139
140    @parameterized.parameters([
141        ('X', 'Y'),
142        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, Y>'),
143    ])
144    def test_injector_get_error_type_not_provided(self, XAnnot, YAnnot):
145        source = '''
146            struct X {
147              using Inject = X();
148            };
149
150            struct Y {};
151
152            fruit::Component<XAnnot> getComponent() {
153              return fruit::createComponent();
154            }
155
156            int main() {
157              fruit::Injector<XAnnot> injector(getComponent);
158              injector.get<YAnnot>();
159            }
160            '''
161        expect_compile_error(
162            'TypeNotProvidedError<YAnnot>',
163            'Trying to get an instance of T, but it is not provided by this Provider/Injector.',
164            COMMON_DEFINITIONS,
165            source,
166            locals())
167
168    @parameterized.parameters([
169        ('const X', 'X&', r'X&'),
170        ('const X', 'X*', r'X\*'),
171        ('const X', 'std::shared_ptr<X>', r'std::shared_ptr<X>'),
172        ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X&>', r'fruit::Annotated<Annotation1, X&>'),
173        ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X*>', r'fruit::Annotated<Annotation1, X\*>'),
174        ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, std::shared_ptr<X>>', r'fruit::Annotated<Annotation1, std::shared_ptr<X>>'),
175    ])
176    def test_injector_const_provided_type_does_not_allow_injecting_nonconst_variants(self, ConstXAnnot, XInjectorGetParam, XInjectorGetParamRegex):
177        source = '''
178            void f(fruit::Injector<ConstXAnnot> injector) {
179              injector.get<XInjectorGetParam>();
180            }
181            '''
182        expect_compile_error(
183            'TypeProvidedAsConstOnlyError<XInjectorGetParamRegex>',
184            'Trying to get an instance of T, but it is only provided as a constant by this Provider/Injector',
185            COMMON_DEFINITIONS,
186            source,
187            locals())
188
189    @parameterized.parameters([
190        ('X', 'X'),
191        ('X', 'const X&'),
192        ('X', 'const X*'),
193        ('X', 'X&'),
194        ('X', 'X*'),
195        ('X', 'std::shared_ptr<X>'),
196        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'),
197        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X&>'),
198        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X*>'),
199        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X&>'),
200        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X*>'),
201        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, std::shared_ptr<X>>'),
202    ])
203    def test_injector_get_ok(self, XBindingInInjector, XInjectorGetParam):
204        source = '''
205            struct X {
206              using Inject = X();
207            };
208
209            fruit::Component<XBindingInInjector> getComponent() {
210              return fruit::createComponent();
211            }
212
213            int main() {
214              fruit::Injector<XBindingInInjector> injector(getComponent);
215
216              auto x = injector.get<XInjectorGetParam>();
217              (void)x;
218            }
219            '''
220        expect_success(
221            COMMON_DEFINITIONS,
222            source,
223            locals())
224
225    @parameterized.parameters([
226        ('const X', 'X'),
227        ('const X', 'const X&'),
228        ('const X', 'const X*'),
229        ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X>'),
230        ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X&>'),
231        ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X*>'),
232    ])
233    def test_injector_get_const_binding_ok(self, XBindingInInjector, XInjectorGetParam):
234        XBindingInInjectorWithoutConst = XBindingInInjector.replace('const ', '')
235        source = '''
236            struct X {};
237
238            const X x{};
239
240            fruit::Component<XBindingInInjector> getComponent() {
241              return fruit::createComponent()
242                  .bindInstance<XBindingInInjectorWithoutConst, X>(x);
243            }
244
245            int main() {
246              fruit::Injector<XBindingInInjector> injector(getComponent);
247
248              auto x = injector.get<XInjectorGetParam>();
249              (void)x;
250            }
251            '''
252        expect_success(
253            COMMON_DEFINITIONS,
254            source,
255            locals())
256
257    @parameterized.parameters([
258        ('X**', r'X\*\*'),
259        ('std::shared_ptr<X>*', r'std::shared_ptr<X>\*'),
260        ('const std::shared_ptr<X>', r'const std::shared_ptr<X>'),
261        ('X* const', r'X\* const'),
262        ('const X* const', r'const X\* const'),
263        ('std::nullptr_t', r'(std::)?nullptr(_t)?'),
264        ('X*&', r'X\*&'),
265        ('X(*)()', r'X(\((__cdecl)?\*\))?\((void)?\)'),
266        ('void', r'void'),
267        ('fruit::Annotated<Annotation1, X**>', r'X\*\*'),
268    ])
269    def test_injector_get_error_type_not_injectable(self, XVariant, XVariantRegex):
270        source = '''
271            struct X {};
272
273            void f(fruit::Injector<X> injector) {
274              injector.get<XVariant>();
275            }
276            '''
277        expect_compile_error(
278            'NonInjectableTypeError<XVariantRegex>',
279            'The type T is not injectable.',
280            COMMON_DEFINITIONS,
281            source,
282            locals())
283
284    @parameterized.parameters([
285        ('X[]', r'X\[\]'),
286    ])
287    def test_injector_get_error_array_type(self, XVariant, XVariantRegex):
288        source = '''
289            struct X {};
290
291            void f(fruit::Injector<X> injector) {
292              injector.get<XVariant>();
293            }
294            '''
295        expect_generic_compile_error(
296            'function cannot return array type'
297            '|function returning an array'
298            # MSVC
299            '|.fruit::Injector<X>::get.: no matching overloaded function found',
300            COMMON_DEFINITIONS,
301            source,
302            locals())
303
304if __name__ == '__main__':
305    absltest.main()
306