• 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 XAnnot = fruit::Annotated<Annotation1, X>;
26
27    struct Annotation2 {};
28    '''
29
30class TestInjectedProvider(parameterized.TestCase):
31    @parameterized.parameters([
32        ('X*', r'X\*'),
33        ('const X*', r'const X\*'),
34        ('X&', r'X&'),
35        ('const X&', r'const X&'),
36        ('std::shared_ptr<X>', r'std::shared_ptr<X>'),
37    ])
38    def test_error_non_class_type_parameter(self, XVariant, XVariantRegexp):
39        source = '''
40            struct X {};
41
42            fruit::Provider<XVariant> provider;
43            '''
44        expect_compile_error(
45            'NonClassTypeError<XVariantRegexp,X>',
46            'A non-class type T was specified. Use C instead',
47            COMMON_DEFINITIONS,
48            source,
49            locals())
50
51    def test_error_annotated_type_parameter(self):
52        source = '''
53            struct X {};
54
55            fruit::Provider<XAnnot> provider;
56            '''
57        expect_compile_error(
58            'AnnotatedTypeError<fruit::Annotated<Annotation1,X>,X>',
59            'An annotated type was specified where a non-annotated type was expected.',
60            COMMON_DEFINITIONS,
61            source)
62
63    @parameterized.parameters([
64        ('X', 'fruit::Provider<X>', 'X', 'X'),
65        ('X', 'fruit::Provider<X>', 'X', 'const X&'),
66        ('X', 'fruit::Provider<X>', 'X', 'const X*'),
67        ('X', 'fruit::Provider<X>', 'X', 'X&'),
68        ('X', 'fruit::Provider<X>', 'X', 'X*'),
69        ('X', 'fruit::Provider<X>', 'X', 'std::shared_ptr<X>'),
70        ('X', 'fruit::Provider<X>', 'X', 'fruit::Provider<X>'),
71        ('X', 'fruit::Provider<X>', 'X', 'fruit::Provider<const X>'),
72        ('X', 'fruit::Provider<const X>', 'const X', 'const X&'),
73        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, fruit::Provider<X>>', 'X', 'const X&'),
74        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, fruit::Provider<const X>>', 'const X', 'const X&'),
75    ])
76    def test_provider_get_ok(self, XBindingInInjector, XProviderAnnot, XParamInProvider, XProviderGetParam):
77        source = '''
78            struct X {
79              using Inject = X();
80            };
81
82            fruit::Component<XBindingInInjector> getComponent() {
83              return fruit::createComponent();
84            }
85
86            int main() {
87              fruit::Injector<XBindingInInjector> injector(getComponent);
88              fruit::Provider<XParamInProvider> provider = injector.get<XProviderAnnot>();
89
90              XProviderGetParam x = provider.get<XProviderGetParam>();
91              (void)x;
92            }
93            '''
94        expect_success(
95            COMMON_DEFINITIONS,
96            source,
97            locals())
98
99    @parameterized.parameters([
100        ('const X', 'fruit::Provider<const X>', 'const X', 'X'),
101        ('const X', 'fruit::Provider<const X>', 'const X', 'const X&'),
102        ('const X', 'fruit::Provider<const X>', 'const X', 'const X*'),
103        ('const X', 'fruit::Provider<const X>', 'const X', 'fruit::Provider<const X>'),
104        ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, fruit::Provider<const X>>', 'const X', 'const X&'),
105    ])
106    def test_provider_get_const_binding_ok(self, XBindingInInjector, XProviderAnnot, XParamInProvider, XProviderGetParam):
107        XBindingInInjectorWithoutConst = XBindingInInjector.replace('const ', '')
108        source = '''
109            struct X {};
110
111            const X x{};
112
113            fruit::Component<XBindingInInjector> getComponent() {
114              return fruit::createComponent()
115                  .bindInstance<XBindingInInjectorWithoutConst, X>(x);
116            }
117
118            int main() {
119              fruit::Injector<XBindingInInjector> injector(getComponent);
120              fruit::Provider<XParamInProvider> provider = injector.get<XProviderAnnot>();
121
122              XProviderGetParam x = provider.get<XProviderGetParam>();
123              (void)x;
124            }
125            '''
126        expect_success(
127            COMMON_DEFINITIONS,
128            source,
129            locals())
130
131    def test_provider_get_during_injection_ok(self):
132        source = '''
133            struct X {
134              INJECT(X()) = default;
135              void foo() {
136              }
137            };
138
139            struct Y {
140              X x;
141              INJECT(Y(fruit::Provider<X> xProvider))
142                : x(xProvider.get<X>()) {
143              }
144
145              void foo() {
146                x.foo();
147              }
148            };
149
150            struct Z {
151              Y y;
152              INJECT(Z(fruit::Provider<Y> yProvider))
153                  : y(yProvider.get<Y>()) {
154              }
155
156              void foo() {
157                y.foo();
158              }
159            };
160
161            fruit::Component<Z> getZComponent() {
162              return fruit::createComponent();
163            }
164
165            int main() {
166              fruit::Injector<Z> injector(getZComponent);
167              fruit::Provider<Z> provider(injector);
168              // During provider.get<Z>(), yProvider.get() is called, and during that xProvider.get()
169              // is called.
170              Z z = provider.get<Z>();
171              z.foo();
172            }
173            '''
174        expect_success(
175            COMMON_DEFINITIONS,
176            source)
177
178    def test_provider_get_error_type_not_provided(self):
179        source = '''
180            struct X {};
181            struct Y {};
182
183            void f(fruit::Provider<X> provider) {
184              provider.get<Y>();
185            }
186            '''
187        expect_compile_error(
188            'TypeNotProvidedError<Y>',
189            'Trying to get an instance of T, but it is not provided by this Provider/Injector.',
190            COMMON_DEFINITIONS,
191            source)
192
193    @parameterized.parameters([
194        ('X**', r'X\*\*'),
195        ('std::shared_ptr<X>*', r'std::shared_ptr<X>\*'),
196        ('const std::shared_ptr<X>', r'const std::shared_ptr<X>'),
197        ('X* const', r'X\* const'),
198        ('const X* const', r'const X\* const'),
199        ('std::nullptr_t', r'(std::)?nullptr(_t)?'),
200        ('X*&', r'X\*&'),
201        ('X(*)()', r'X(\((__cdecl)?\*\))?\((void)?\)'),
202        ('void', r'void'),
203        ('fruit::Annotated<Annotation1, fruit::Annotated<Annotation1, X>>', r'fruit::Annotated<Annotation1, X>'),
204    ])
205    def test_provider_get_error_type_not_injectable(self, XVariant, XVariantRegex):
206        source = '''
207            struct X {};
208
209            void f(fruit::Provider<X> provider) {
210              provider.get<XVariant>();
211            }
212            '''
213        expect_compile_error(
214            'NonInjectableTypeError<XVariantRegex>',
215            'The type T is not injectable',
216            COMMON_DEFINITIONS,
217            source,
218            locals())
219
220    @parameterized.parameters([
221        ('X&', r'X&'),
222        ('X*', r'X\*'),
223        ('std::shared_ptr<X>', r'std::shared_ptr<X>'),
224        ('fruit::Provider<X>', r'fruit::Provider<X>'),
225    ])
226    def test_const_provider_get_does_not_allow_injecting_nonconst_variants(self, XProviderGetParam, XProviderGetParamRegex):
227        source = '''
228            void f(fruit::Provider<const X> provider) {
229              provider.get<XProviderGetParam>();
230            }
231            '''
232        expect_compile_error(
233            'TypeProvidedAsConstOnlyError<XProviderGetParamRegex>',
234            'Trying to get an instance of T, but it is only provided as a constant by this Provider/Injector',
235            COMMON_DEFINITIONS,
236            source,
237            locals())
238
239    @parameterized.parameters([
240        ('fruit::Provider<Y>'),
241        ('ANNOTATED(Annotation1, fruit::Provider<Y>)'),
242    ])
243    def test_lazy_injection_with_annotations(self, Y_PROVIDER_ANNOT):
244        source = '''
245            struct Y : public ConstructionTracker<Y> {
246              using Inject = Y();
247            };
248
249            struct X : public ConstructionTracker<X> {
250              INJECT(X(Y_PROVIDER_ANNOT provider)) : provider(provider) {
251              }
252
253              void run() {
254                Y* y(provider);
255                (void) y;
256              }
257
258              fruit::Provider<Y> provider;
259            };
260
261            fruit::Component<X> getComponent() {
262              return fruit::createComponent();
263            }
264
265            fruit::Component<> getEmptyComponent() {
266              return fruit::createComponent();
267            }
268
269            int main() {
270              fruit::NormalizedComponent<> normalizedComponent(getEmptyComponent);
271              fruit::Injector<X> injector(normalizedComponent, getComponent);
272
273              Assert(X::num_objects_constructed == 0);
274              Assert(Y::num_objects_constructed == 0);
275
276              X* x(injector);
277
278              Assert(X::num_objects_constructed == 1);
279              Assert(Y::num_objects_constructed == 0);
280
281              x->run();
282
283              Assert(X::num_objects_constructed == 1);
284              Assert(Y::num_objects_constructed == 1);
285            }
286            '''
287        expect_success(
288            COMMON_DEFINITIONS,
289            source,
290            locals())
291
292if __name__ == '__main__':
293    absltest.main()
294