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