• 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    struct Y {};
24
25    struct Annotation1 {};
26    using IntAnnot1 = fruit::Annotated<Annotation1, int>;
27    using XAnnot1 = fruit::Annotated<Annotation1, X>;
28
29    struct Annotation2 {};
30    using IntAnnot2 = fruit::Annotated<Annotation2, int>;
31    using XAnnot2 = fruit::Annotated<Annotation2, X>;
32    '''
33
34class TestComponentAndInjectorParams(parameterized.TestCase):
35    @multiple_parameters([
36        ('X', 'X'),
37        ('X', 'const X'),
38        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'),
39        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'),
40    ], [
41        'Component',
42        'NormalizedComponent',
43        'Injector',
44    ])
45    def test_duplicate_type(self, XAnnot, MaybeConstXAnnot, Class):
46        source = '''
47            InstantiateType(fruit::Class<MaybeConstXAnnot, MaybeConstXAnnot>)
48            '''
49        expect_compile_error(
50            'RepeatedTypesError<XAnnot,XAnnot>',
51            'A type was specified more than once.',
52            COMMON_DEFINITIONS,
53            source,
54            locals())
55
56    @multiple_parameters([
57        ('X', 'const X'),
58        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'),
59    ], [
60        'Component',
61        'NormalizedComponent',
62        'Injector',
63    ])
64    def test_duplicate_type_different_constness(self, XAnnot, ConstXAnnot, Class):
65        source = '''
66            InstantiateType(fruit::Class<XAnnot, ConstXAnnot>)
67            '''
68        expect_compile_error(
69            'RepeatedTypesError<XAnnot,XAnnot>',
70            'A type was specified more than once.',
71            COMMON_DEFINITIONS,
72            source,
73            locals())
74
75    def test_duplicate_type_with_different_annotation_ok(self):
76        source = '''
77            fruit::Component<XAnnot1, XAnnot2> getComponent() {
78              return fruit::createComponent()
79                .registerConstructor<XAnnot1()>()
80                .registerConstructor<XAnnot2()>();
81            }
82
83            int main() {
84              fruit::Injector<XAnnot1, XAnnot2> injector1(getComponent);
85              injector1.get<XAnnot1>();
86              injector1.get<XAnnot2>();
87
88              fruit::NormalizedComponent<XAnnot1, XAnnot2> normalizedComponent(getComponent);
89              fruit::Injector<XAnnot1, XAnnot2> injector2(getComponent);
90              injector2.get<XAnnot1>();
91              injector2.get<XAnnot2>();
92            }
93            '''
94        expect_success(
95            COMMON_DEFINITIONS,
96            source)
97
98    @multiple_parameters([
99        ('X', 'X'),
100        ('X', 'const X'),
101        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'),
102        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'),
103    ], [
104        'Component',
105        'NormalizedComponent',
106    ])
107    def test_duplicate_type_in_required(self, XAnnot, MaybeConstXAnnot, Class):
108        source = '''
109            InstantiateType(fruit::Class<fruit::Required<MaybeConstXAnnot, MaybeConstXAnnot>>)
110            '''
111        expect_compile_error(
112            'RepeatedTypesError<XAnnot,XAnnot>',
113            'A type was specified more than once.',
114            COMMON_DEFINITIONS,
115            source,
116            locals())
117
118    @multiple_parameters([
119        'Component',
120        'NormalizedComponent',
121    ], [
122        ('X', 'const X'),
123        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'),
124    ])
125    def test_component_duplicate_type_in_required_different_constness(self, Class, XAnnot, ConstXAnnot):
126        source = '''
127            InstantiateType(fruit::Class<fruit::Required<XAnnot, ConstXAnnot>>)
128            '''
129        expect_compile_error(
130            'RepeatedTypesError<XAnnot,XAnnot>',
131            'A type was specified more than once.',
132            COMMON_DEFINITIONS,
133            source,
134            locals())
135
136    @multiple_parameters([
137        ('X', 'X'),
138        ('X', 'const X'),
139        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'),
140        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'),
141    ], [
142        'Component',
143        'NormalizedComponent',
144    ])
145    def test_same_type_in_required_and_provided(self, XAnnot, MaybeConstXAnnot, Class):
146        source = '''
147            InstantiateType(fruit::Class<fruit::Required<MaybeConstXAnnot>, MaybeConstXAnnot>)
148            '''
149        expect_compile_error(
150            'RepeatedTypesError<XAnnot,XAnnot>',
151            'A type was specified more than once.',
152            COMMON_DEFINITIONS,
153            source,
154            locals())
155
156    @multiple_parameters([
157        ('X', 'X', 'const X'),
158        ('X', 'const X', 'X'),
159        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'),
160        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X>'),
161    ], [
162        'Component',
163        'NormalizedComponent',
164    ])
165    def test_same_type_in_required_and_provided_different_constness(self, XAnnot, XAnnotInRequirements, XAnnotInProvides, Class):
166        source = '''
167            InstantiateType(fruit::Class<fruit::Required<XAnnotInRequirements>, XAnnotInProvides>)
168            '''
169        expect_compile_error(
170            'RepeatedTypesError<XAnnot,XAnnot>',
171            'A type was specified more than once.',
172            COMMON_DEFINITIONS,
173            source,
174            locals())
175
176    def test_same_type_in_required_and_provided_different_annotation_ok(self):
177        source = '''
178            fruit::Component<fruit::Required<XAnnot1>, XAnnot2> getComponent() {
179              return fruit::createComponent()
180                .registerConstructor<XAnnot2()>();
181            }
182
183            fruit::Component<XAnnot1, XAnnot2> getRootComponent() {
184              return fruit::createComponent()
185                  .install(getComponent)
186                  .registerConstructor<XAnnot1()>();
187            }
188
189            fruit::Component<> getEmptyComponent() {
190              return fruit::createComponent();
191            }
192
193            int main() {
194              fruit::Injector<XAnnot1, XAnnot2> injector1(getRootComponent);
195              injector1.get<XAnnot1>();
196              injector1.get<XAnnot2>();
197
198              fruit::NormalizedComponent<XAnnot1, XAnnot2> normalizedComponent(getRootComponent);
199              fruit::Injector<XAnnot1, XAnnot2> injector2(normalizedComponent, getEmptyComponent);
200              injector2.get<XAnnot1>();
201              injector2.get<XAnnot2>();
202            }
203            '''
204        expect_success(
205            COMMON_DEFINITIONS,
206            source)
207
208    @multiple_parameters([
209        ('X*', r'X\*'),
210        ('const X*', r'const X\*'),
211        ('X&', r'X&'),
212        ('const X&', r'const X&'),
213        ('std::shared_ptr<X>', r'std::shared_ptr<X>'),
214        ('fruit::Annotated<Annotation1, X*>', r'X\*'),
215        ('fruit::Annotated<Annotation1, const X*>', r'const X\*'),
216        ('fruit::Annotated<Annotation1, X&>', r'X&'),
217        ('fruit::Annotated<Annotation1, const X&>', r'const X&'),
218        ('fruit::Annotated<Annotation1, std::shared_ptr<X>>', r'std::shared_ptr<X>'),
219    ], [
220        'Component',
221        'NormalizedComponent',
222        'Injector',
223    ])
224    def test_error_non_class_type(self, XVariantAnnot, XVariantRegexp, Class):
225        source = '''
226            InstantiateType(fruit::Class<XVariantAnnot>)
227            '''
228        expect_compile_error(
229            'NonClassTypeError<XVariantRegexp,X>',
230            'A non-class type T was specified. Use C instead.',
231            COMMON_DEFINITIONS,
232            source,
233            locals())
234
235    @multiple_parameters([
236        ('const X', 'const X'),
237        ('fruit::Annotated<Annotation1, const X>', 'const X'),
238    ], [
239        'Component',
240        'NormalizedComponent',
241        'Injector',
242    ])
243    def test_const_provided_type_ok(self, XVariantAnnot, XVariantRegexp, Class):
244        source = '''
245            InstantiateType(fruit::Class<XVariantAnnot>)
246            '''
247        expect_success(
248            COMMON_DEFINITIONS,
249            source,
250            locals())
251
252    @multiple_parameters([
253        ('X*', r'X\*'),
254        ('const X*', r'const X\*'),
255        ('X&', r'X&'),
256        ('const X&', r'const X&'),
257        ('std::shared_ptr<X>', r'std::shared_ptr<X>'),
258        ('fruit::Annotated<Annotation1, X*>', r'X\*'),
259        ('fruit::Annotated<Annotation1, const X*>', r'const X\*'),
260        ('fruit::Annotated<Annotation1, X&>', r'X&'),
261        ('fruit::Annotated<Annotation1, const X&>', r'const X&'),
262        ('fruit::Annotated<Annotation1, std::shared_ptr<X>>', r'std::shared_ptr<X>'),
263    ], [
264        'Component',
265        'NormalizedComponent',
266    ])
267    def test_error_non_class_type_in_requirements(self, XVariantAnnot, XVariantRegexp, Class):
268        source = '''
269            InstantiateType(fruit::Class<fruit::Required<XVariantAnnot>>)
270            '''
271        expect_compile_error(
272            'NonClassTypeError<XVariantRegexp,X>',
273            'A non-class type T was specified. Use C instead.',
274            COMMON_DEFINITIONS,
275            source,
276            locals())
277
278    @parameterized.parameters([
279        ('const Z', 'Z'),
280        ('fruit::Annotated<Annotation1, const Z>', 'fruit::Annotated<Annotation1, Z>'),
281    ])
282    def test_const_class_type_ok(self, ConstZAnnot, ZAnnot):
283        source = '''
284            struct Z {};
285
286            const Z z{};
287
288            fruit::Component<ConstZAnnot> getComponent() {
289              return fruit::createComponent()
290                  .bindInstance<ZAnnot, Z>(z);
291            }
292
293            fruit::Component<> getEmptyComponent() {
294              return fruit::createComponent();
295            }
296
297            int main() {
298              fruit::NormalizedComponent<ConstZAnnot> normalizedComponent(getComponent);
299              fruit::Injector<ConstZAnnot> injector(normalizedComponent, getEmptyComponent);
300              injector.get<ZAnnot>();
301            }
302            '''
303        expect_success(
304            COMMON_DEFINITIONS,
305            source,
306            locals())
307
308    @parameterized.parameters([
309        ('const Z', 'Z'),
310        ('fruit::Annotated<Annotation1, const Z>', 'fruit::Annotated<Annotation1, Z>'),
311    ])
312    def test_const_class_type_in_requirements_ok(self, ConstZAnnot, ZAnnot):
313        source = '''
314            struct Z {};
315
316            fruit::Component<fruit::Required<ConstZAnnot>> getComponent() {
317              return fruit::createComponent();
318            }
319
320            const Z z{};
321
322            fruit::Component<ConstZAnnot> getEmptyComponent() {
323              return fruit::createComponent()
324                  .bindInstance<ZAnnot, Z>(z);
325            }
326
327            int main() {
328              fruit::NormalizedComponent<fruit::Required<ConstZAnnot>> normalizedComponent(getComponent);
329              fruit::Injector<ConstZAnnot> injector(normalizedComponent, getEmptyComponent);
330              injector.get<ZAnnot>();
331            }
332            '''
333        expect_success(
334            COMMON_DEFINITIONS,
335            source,
336            locals())
337
338    @parameterized.parameters([
339        'Component',
340        'NormalizedComponent',
341    ])
342    def test_two_required_lists_error(self, Class):
343        source = '''
344            InstantiateType(fruit::Class<fruit::Required<X>, fruit::Required<Y>>)
345        '''
346        expect_compile_error(
347            'RequiredTypesInComponentArgumentsError<fruit::Required<Y>>',
348            'A Required<...> type was passed as a non-first template parameter to fruit::Component or fruit::NormalizedComponent',
349            COMMON_DEFINITIONS,
350            source,
351            locals())
352
353    @parameterized.parameters([
354        'Component',
355        'NormalizedComponent',
356    ])
357    def test_required_list_not_first_argument_error(self, Class):
358        source = '''
359            InstantiateType(fruit::Class<X, fruit::Required<Y>>)
360        '''
361        expect_compile_error(
362            'RequiredTypesInComponentArgumentsError<fruit::Required<Y>>',
363            'A Required<...> type was passed as a non-first template parameter to fruit::Component or fruit::NormalizedComponent',
364            COMMON_DEFINITIONS,
365            source,
366            locals())
367
368    def test_multiple_required_types_ok(self):
369        source = '''
370            fruit::Component<fruit::Required<X, Y>> getEmptyComponent() {
371              return fruit::createComponent();
372            }
373
374            fruit::Component<X, Y> getComponent() {
375              return fruit::createComponent()
376                  .install(getEmptyComponent)
377                  .registerConstructor<X()>()
378                  .registerConstructor<Y()>();
379            }
380
381            int main() {
382              fruit::NormalizedComponent<fruit::Required<X, Y>> normalizedComponent(getEmptyComponent);
383              fruit::Injector<X> injector(normalizedComponent, getComponent);
384              injector.get<X>();
385            }
386        '''
387        expect_success(
388            COMMON_DEFINITIONS,
389            source)
390
391    @parameterized.parameters([
392        ('X', 'Y'),
393        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, Y>'),
394    ])
395    def test_error_requirements_in_injector(self, XAnnot, YAnnot):
396        source = '''
397            InstantiateType(fruit::Injector<fruit::Required<YAnnot>, XAnnot>)
398            '''
399        expect_compile_error(
400            'InjectorWithRequirementsError<YAnnot>',
401            'Injectors can.t have requirements.',
402            COMMON_DEFINITIONS,
403            source,
404            locals())
405
406    @parameterized.parameters([
407        ('X', 'Y'),
408        ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, Y>'),
409    ])
410    def test_error_requirements_in_injector_second_argument(self, XAnnot, YAnnot):
411        source = '''
412            InstantiateType(fruit::Injector<XAnnot, fruit::Required<YAnnot>>)
413            '''
414        expect_compile_error(
415            'InjectorWithRequirementsError<YAnnot>',
416            'Injectors can.t have requirements.',
417            COMMON_DEFINITIONS,
418            source,
419            locals())
420
421if __name__ == '__main__':
422    absltest.main()
423