• 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 Annotation1 {};
23
24    template <typename T>
25    using WithNoAnnot = T;
26
27    template <typename T>
28    using WithAnnot1 = fruit::Annotated<Annotation1, T>;
29    '''
30
31class TestRegisterProvider(parameterized.TestCase):
32    @multiple_parameters([
33        'WithNoAnnot',
34        'WithAnnot1',
35    ], [
36       ('X()', 'X'),
37       ('new X()', 'X*'),
38    ])
39    def test_register_provider_success(self, WithAnnot, ConstructX, XPtr):
40        source = '''
41            struct X : public ConstructionTracker<X> {
42              int value = 5;
43            };
44
45            fruit::Component<WithAnnot<X>> getComponent() {
46              return fruit::createComponent()
47                .registerProvider<WithAnnot<XPtr>()>([](){return ConstructX;});
48            }
49
50            int main() {
51              fruit::Injector<WithAnnot<X>> injector(getComponent);
52
53              Assert((injector.get<WithAnnot<X                 >>(). value == 5));
54              Assert((injector.get<WithAnnot<X*                >>()->value == 5));
55              Assert((injector.get<WithAnnot<X&                >>(). value == 5));
56              Assert((injector.get<WithAnnot<const X           >>(). value == 5));
57              Assert((injector.get<WithAnnot<const X*          >>()->value == 5));
58              Assert((injector.get<WithAnnot<const X&          >>(). value == 5));
59              Assert((injector.get<WithAnnot<std::shared_ptr<X>>>()->value == 5));
60
61              Assert(X::num_objects_constructed == 1);
62            }
63            '''
64        expect_success(
65            COMMON_DEFINITIONS,
66            source,
67            locals())
68
69    @parameterized.parameters([
70        'WithNoAnnot',
71        'WithAnnot1',
72    ])
73    def test_register_provider_abstract_class_ok(self, WithAnnot):
74        source = '''
75            struct I {
76              virtual int foo() = 0;
77              virtual ~I() = default;
78            };
79
80            struct X : public I {
81              int foo() override {
82                return 5;
83              }
84            };
85
86            fruit::Component<WithAnnot<I>> getComponent() {
87              return fruit::createComponent()
88                .registerProvider<WithAnnot<I*>()>([](){return static_cast<I*>(new X());});
89            }
90
91            int main() {
92              fruit::Injector<WithAnnot<I>> injector(getComponent);
93
94              Assert(injector.get<WithAnnot<I*>>()->foo() == 5);
95            }
96            '''
97        expect_success(
98            COMMON_DEFINITIONS,
99            source,
100            locals())
101
102    @parameterized.parameters([
103        'WithNoAnnot',
104        'WithAnnot1',
105    ])
106    def test_register_provider_abstract_class_with_no_virtual_destructor_error(self, WithAnnot):
107        source = '''
108            struct I {
109              virtual int foo() = 0;
110            };
111
112            struct X : public I {
113              int foo() override {
114                return 5;
115              }
116            };
117
118            fruit::Component<WithAnnot<I>> getComponent() {
119              return fruit::createComponent()
120                .registerProvider<WithAnnot<I*>()>([](){return static_cast<I*>(new X());});
121            }
122            '''
123        expect_compile_error(
124            r'ProviderReturningPointerToAbstractClassWithNoVirtualDestructorError<I>',
125            r'registerProvider\(\) was called with a lambda that returns a pointer to T, but T is an abstract class',
126            COMMON_DEFINITIONS,
127            source,
128            locals())
129
130    @parameterized.parameters([
131        'X()',
132        'new X()',
133    ])
134    def test_register_provider_not_copyable_success(self, ConstructX):
135        source = '''
136            struct X {
137              X() = default;
138              X(X&&) = default;
139              X(const X&) = delete;
140            };
141
142            fruit::Component<X> getComponent() {
143              return fruit::createComponent()
144                .registerProvider([](){return ConstructX;});
145            }
146
147            int main() {
148              fruit::Injector<X> injector(getComponent);
149              injector.get<X*>();
150            }
151            '''
152        expect_success(
153            COMMON_DEFINITIONS,
154            source,
155            locals())
156
157    def test_register_provider_not_movable_returning_pointer_success(self):
158        source = '''
159            struct X {
160              X() = default;
161              X(X&&) = delete;
162              X(const X&) = delete;
163            };
164
165            fruit::Component<X> getComponent() {
166              return fruit::createComponent()
167                .registerProvider([](){return new X();});
168            }
169
170            int main() {
171              fruit::Injector<X> injector(getComponent);
172              injector.get<X*>();
173            }
174            '''
175        expect_success(
176            COMMON_DEFINITIONS,
177            source)
178
179    @parameterized.parameters([
180        'X',
181        'fruit::Annotated<Annotation1, X>',
182    ])
183    def test_register_provider_error_not_function(self, XAnnot):
184        source = '''
185            struct X {
186              X(int) {}
187            };
188
189            fruit::Component<XAnnot> getComponent() {
190              int n = 3;
191              return fruit::createComponent()
192                .registerProvider<XAnnot()>([=]{return X(n);});
193            }
194            '''
195        expect_compile_error(
196            'FunctorUsedAsProviderError<.*>',
197            'A stateful lambda or a non-lambda functor was used as provider',
198            COMMON_DEFINITIONS,
199            source,
200            locals())
201
202    @parameterized.parameters([
203        'int',
204        'fruit::Annotated<Annotation1, int>',
205    ])
206    def test_register_provider_error_malformed_signature(self, intAnnot):
207        source = '''
208            fruit::Component<intAnnot> getComponent() {
209              return fruit::createComponent()
210                .registerProvider<intAnnot>([](){return 42;});
211            }
212            '''
213        expect_compile_error(
214            'NotASignatureError<intAnnot>',
215            'CandidateSignature was specified as parameter, but it.s not a signature. Signatures are of the form',
216            COMMON_DEFINITIONS,
217            source,
218            locals())
219
220    @parameterized.parameters([
221        ('X', 'X*', '(struct )?X'),
222        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X*>', '(struct )?fruit::Annotated<(struct )?Annotation1, ?(struct )?X>'),
223    ])
224    def test_register_provider_error_returned_nullptr(self, XAnnot, XPtrAnnot, XAnnotRegex):
225        source = '''
226            struct X {};
227
228            fruit::Component<XAnnot> getComponent() {
229              return fruit::createComponent()
230                  .registerProvider<XPtrAnnot()>([](){return (X*)nullptr;});
231            }
232
233            int main() {
234              fruit::Injector<XAnnot> injector(getComponent);
235              injector.get<XAnnot>();
236            }
237            '''
238        expect_runtime_error(
239            'Fatal injection error: attempting to get an instance for the type XAnnotRegex but the provider returned nullptr',
240            COMMON_DEFINITIONS,
241            source,
242            locals())
243
244    @multiple_parameters([
245        ('X()', 'X'),
246        ('new X()', 'X*'),
247    ], [
248        'WithNoAnnot',
249        'WithAnnot1',
250    ], [
251        'Y',
252        'const Y',
253        'Y*',
254        'const Y*',
255        'Y&',
256        'const Y&',
257        'std::shared_ptr<Y>',
258        'fruit::Provider<Y>',
259        'fruit::Provider<const Y>',
260    ])
261    def test_register_provider_with_param_success(self, ConstructX, XPtr, WithAnnot, YVariant):
262        source = '''
263            struct Y {};
264            struct X {};
265
266            fruit::Component<WithAnnot<Y>> getYComponent() {
267              return fruit::createComponent()
268                .registerConstructor<WithAnnot<Y>()>();
269            }
270
271            fruit::Component<X> getComponent() {
272              return fruit::createComponent()
273                .install(getYComponent)
274                .registerProvider<XPtr(WithAnnot<YVariant>)>([](YVariant){ return ConstructX; });
275            }
276
277            int main() {
278              fruit::Injector<X> injector(getComponent);
279              injector.get<X>();
280            }
281            '''
282        expect_success(
283            COMMON_DEFINITIONS,
284            source,
285            locals())
286
287    @multiple_parameters([
288        ('X()', 'X'),
289        ('new X()', 'X*'),
290    ], [
291        'WithNoAnnot',
292        'WithAnnot1',
293    ], [
294        'Y',
295        'const Y',
296        'const Y*',
297        'const Y&',
298        'fruit::Provider<const Y>',
299    ])
300    def test_register_provider_with_param_const_binding_success(self, ConstructX, XPtr, WithAnnot, YVariant):
301        source = '''
302            struct Y {};
303            struct X {};
304
305            const Y y{};
306
307            fruit::Component<WithAnnot<const Y>> getYComponent() {
308              return fruit::createComponent()
309                .bindInstance<WithAnnot<Y>, Y>(y);
310            }
311
312            fruit::Component<X> getComponent() {
313              return fruit::createComponent()
314                .install(getYComponent)
315                .registerProvider<XPtr(WithAnnot<YVariant>)>([](YVariant){ return ConstructX; });
316            }
317
318            int main() {
319              fruit::Injector<X> injector(getComponent);
320              injector.get<X>();
321            }
322            '''
323        expect_success(
324            COMMON_DEFINITIONS,
325            source,
326            locals())
327
328    @multiple_parameters([
329        ('X()', 'X'),
330        ('new X()', 'X*'),
331    ], [
332        ('WithNoAnnot', 'Y'),
333        ('WithAnnot1', 'fruit::Annotated<Annotation1, Y>'),
334    ], [
335        'Y*',
336        'Y&',
337        'std::shared_ptr<Y>',
338        'fruit::Provider<Y>',
339    ])
340    def test_register_provider_with_param_error_nonconst_param_required(self, ConstructX, XPtr, WithAnnot, YAnnotRegex, YVariant):
341        source = '''
342            struct Y {};
343            struct X {};
344
345            fruit::Component<WithAnnot<const Y>> getYComponent();
346
347            fruit::Component<> getComponent() {
348              return fruit::createComponent()
349                .install(getYComponent)
350                .registerProvider<XPtr(WithAnnot<YVariant>)>([](YVariant){ return ConstructX; });
351            }
352            '''
353        expect_compile_error(
354            'NonConstBindingRequiredButConstBindingProvidedError<YAnnotRegex>',
355            'The type T was provided as constant, however one of the constructors/providers/factories in this component',
356            COMMON_DEFINITIONS,
357            source,
358            locals())
359
360    @multiple_parameters([
361        ('X()', 'X'),
362        ('new X()', 'X*'),
363    ], [
364        ('WithNoAnnot', 'Y'),
365        ('WithAnnot1', 'fruit::Annotated<Annotation1, Y>'),
366    ], [
367        'Y*',
368        'Y&',
369        'std::shared_ptr<Y>',
370        'fruit::Provider<Y>',
371    ])
372    def test_register_provider_with_param_error_nonconst_param_required_install_after(self, ConstructX, XPtr, WithAnnot, YAnnotRegex, YVariant):
373        source = '''
374            struct Y {};
375            struct X {};
376
377            fruit::Component<WithAnnot<const Y>> getYComponent();
378
379            fruit::Component<> getComponent() {
380              return fruit::createComponent()
381                .registerProvider<XPtr(WithAnnot<YVariant>)>([](YVariant){ return ConstructX; })
382                .install(getYComponent);
383            }
384            '''
385        expect_compile_error(
386            'NonConstBindingRequiredButConstBindingProvidedError<YAnnotRegex>',
387            'The type T was provided as constant, however one of the constructors/providers/factories in this component',
388            COMMON_DEFINITIONS,
389            source,
390            locals())
391
392    def test_register_provider_requiring_nonconst_then_requiring_const_ok(self):
393        source = '''
394            struct X {};
395            struct Y {};
396            struct Z {};
397
398            fruit::Component<Y, Z> getRootComponent() {
399              return fruit::createComponent()
400                .registerProvider([](X&) { return Y();})
401                .registerProvider([](const X&) { return Z();})
402                .registerConstructor<X()>();
403            }
404
405            int main() {
406              fruit::Injector<Y, Z> injector(getRootComponent);
407              injector.get<Y>();
408              injector.get<Z>();
409            }
410            '''
411        expect_success(
412            COMMON_DEFINITIONS,
413            source,
414            locals())
415
416    def test_register_provider_requiring_nonconst_then_requiring_const_declaring_const_requirement_error(self):
417        source = '''
418            struct X {};
419            struct Y {};
420            struct Z {};
421
422            fruit::Component<fruit::Required<const X>, Y, Z> getRootComponent() {
423              return fruit::createComponent()
424                .registerProvider([](X&) { return Y();})
425                .registerProvider([](const X&) { return Z();});
426            }
427            '''
428        expect_compile_error(
429            'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<X>',
430            'The type T was declared as a const Required type in the returned Component, however',
431            COMMON_DEFINITIONS,
432            source,
433            locals())
434
435    def test_register_provider_requiring_const_then_requiring_nonconst_ok(self):
436        source = '''
437            struct X {};
438            struct Y {};
439            struct Z {};
440
441            fruit::Component<Y, Z> getRootComponent() {
442              return fruit::createComponent()
443                .registerProvider([](const X&) { return Y();})
444                .registerProvider([](X&) { return Z();})
445                .registerConstructor<X()>();
446            }
447
448            int main() {
449              fruit::Injector<Y, Z> injector(getRootComponent);
450              injector.get<Y>();
451              injector.get<Z>();
452            }
453            '''
454        expect_success(
455            COMMON_DEFINITIONS,
456            source,
457            locals())
458
459    def test_register_provider_requiring_const_then_requiring_nonconst_declaring_const_requirement_error(self):
460        source = '''
461            struct X {};
462            struct Y {};
463            struct Z {};
464
465            fruit::Component<fruit::Required<const X>, Y, Z> getRootComponent() {
466              return fruit::createComponent()
467                .registerProvider([](const X&) { return Y();})
468                .registerProvider([](X&) { return Z();});
469            }
470            '''
471        expect_compile_error(
472            'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<X>',
473            'The type T was declared as a const Required type in the returned Component, however',
474            COMMON_DEFINITIONS,
475            source,
476            locals())
477
478    @multiple_parameters([
479        ('X()', 'X'),
480        ('new X()', 'X*'),
481    ], [
482        ('Y**', r'Y\*\*'),
483        ('std::shared_ptr<Y>*', r'std::shared_ptr<Y>\*'),
484        ('std::nullptr_t', r'(std::)?nullptr(_t)?'),
485        ('Y*&', r'Y\*&'),
486        ('Y(*)()', r'Y(\((__cdecl)?\*\))?\((void)?\)'),
487    ])
488    def test_register_provider_with_param_error_type_not_injectable(self, ConstructX, XPtr, YVariant, YVariantRegex):
489        source = '''
490            struct Y {};
491            struct X {};
492
493            fruit::Component<> getComponent() {
494              return fruit::createComponent()
495                .registerProvider<XPtr(YVariant)>([](YVariant){ return ConstructX; });
496            }
497            '''
498        expect_compile_error(
499            'NonInjectableTypeError<YVariantRegex>',
500            'The type T is not injectable.',
501            COMMON_DEFINITIONS,
502            source,
503            locals())
504
505if __name__ == '__main__':
506    absltest.main()
507