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 Annotation1 {};
     23     struct Annotation2 {};
     24 
     25     template <typename T>
     26     using WithNoAnnot = T;
     27 
     28     template <typename T>
     29     using WithAnnot1 = fruit::Annotated<Annotation1, T>;
     30 
     31     template <typename T>
     32     using WithAnnot2 = fruit::Annotated<Annotation2, T>;
     33     '''
     34 
     35 @pytest.mark.parametrize('IAnnot,XAnnot,WithAnnot', [
     36     ('I', 'X', 'WithNoAnnot'),
     37     ('fruit::Annotated<Annotation1, I>', 'fruit::Annotated<Annotation2, X>', 'WithAnnot1'),
     38 ])
     39 def test_provider_returning_value_success_with_annotation(IAnnot, XAnnot, WithAnnot):
     40     source = '''
     41         struct I {
     42           int value = 5;
     43         };
     44 
     45         struct X : public I, ConstructionTracker<X> {
     46         };
     47 
     48         fruit::Component<IAnnot> getComponent() {
     49           return fruit::createComponent()
     50             .registerProvider<XAnnot()>([](){return X();})
     51             .bind<IAnnot, XAnnot>();
     52         }
     53 
     54         int main() {
     55           fruit::Injector<IAnnot> injector(getComponent);
     56           Assert((injector.get<WithAnnot<I                 >>() .value == 5));
     57           Assert((injector.get<WithAnnot<I*                >>()->value == 5));
     58           Assert((injector.get<WithAnnot<I&                >>() .value == 5));
     59           Assert((injector.get<WithAnnot<const I           >>() .value == 5));
     60           Assert((injector.get<WithAnnot<const I*          >>()->value == 5));
     61           Assert((injector.get<WithAnnot<const I&          >>() .value == 5));
     62           Assert((injector.get<WithAnnot<std::shared_ptr<I>>>()->value == 5));
     63           Assert(fruit::impl::InjectorAccessorForTests::unsafeGet<WithAnnot<X>>(injector) == nullptr);
     64 
     65           Assert(X::num_objects_constructed == 1);
     66         }
     67         '''
     68     expect_success(
     69         COMMON_DEFINITIONS,
     70         source,
     71         locals())
     72 
     73 @pytest.mark.parametrize('IAnnot,XAnnot,XPtrAnnot,WithAnnot', [
     74     ('I', 'X', 'X*', 'WithNoAnnot'),
     75     ('fruit::Annotated<Annotation1, I>', 'fruit::Annotated<Annotation2, X>', 'fruit::Annotated<Annotation2, X*>', 'WithAnnot1'),
     76 ])
     77 def test_provider_returning_pointer_success_with_annotation(IAnnot, XAnnot, XPtrAnnot, WithAnnot):
     78     source = '''
     79         struct I {
     80           int value = 5;
     81         };
     82 
     83         struct X : public I, ConstructionTracker<X> {
     84         };
     85 
     86         fruit::Component<IAnnot> getComponent() {
     87           return fruit::createComponent()
     88             .registerProvider<XPtrAnnot()>([](){return new X();})
     89             .bind<IAnnot, XAnnot>();
     90         }
     91 
     92         int main() {
     93           fruit::Injector<IAnnot> injector(getComponent);
     94           Assert((injector.get<WithAnnot<I                 >>() .value == 5));
     95           Assert((injector.get<WithAnnot<I*                >>()->value == 5));
     96           Assert((injector.get<WithAnnot<I&                >>() .value == 5));
     97           Assert((injector.get<WithAnnot<const I           >>() .value == 5));
     98           Assert((injector.get<WithAnnot<const I*          >>()->value == 5));
     99           Assert((injector.get<WithAnnot<const I&          >>() .value == 5));
    100           Assert((injector.get<WithAnnot<std::shared_ptr<I>>>()->value == 5));
    101           Assert(fruit::impl::InjectorAccessorForTests::unsafeGet<WithAnnot<X>>(injector) == nullptr);
    102           Assert(X::num_objects_constructed == 1);
    103         }
    104         '''
    105     expect_success(
    106         COMMON_DEFINITIONS,
    107         source,
    108         locals())
    109 
    110 def test_compression_undone():
    111     source = '''
    112         struct I1 {};
    113         struct C1 : public I1, ConstructionTracker<C1> {
    114           INJECT(C1()) = default;
    115         };
    116 
    117         struct I2 {};
    118         struct C2 : public I2 {
    119           INJECT(C2(I1*)) {}
    120         };
    121 
    122         fruit::Component<I1> getI1Component() {
    123           return fruit::createComponent()
    124               .bind<I1, C1>();
    125         }
    126 
    127         fruit::Component<I2> getI2Component() {
    128           return fruit::createComponent()
    129               .install(getI1Component)
    130               .bind<I2, C2>();
    131         }
    132 
    133         struct X {
    134           // Intentionally C1 and not I1. This prevents binding compression for the I1->C1 edge.
    135           INJECT(X(C1*)) {}
    136         };
    137 
    138         fruit::Component<X> getXComponent() {
    139           return fruit::createComponent();
    140         }
    141 
    142         int main() {
    143           // Here the binding C2->I1->C1 is compressed into C2->C1.
    144           fruit::NormalizedComponent<I2> normalizedComponent(getI2Component);
    145 
    146           // However the binding X->C1 prevents binding compression on I1->C1, the binding compression must be undone.
    147           fruit::Injector<I2, X> injector(normalizedComponent, getXComponent);
    148 
    149           Assert(C1::num_objects_constructed == 0);
    150           injector.get<I2*>();
    151           injector.get<X*>();
    152           Assert(fruit::impl::InjectorAccessorForTests::unsafeGet<C1>(injector) != nullptr);
    153           Assert(C1::num_objects_constructed == 1);
    154         }
    155         '''
    156     expect_success(
    157         COMMON_DEFINITIONS,
    158         source)
    159 
    160 if __name__== '__main__':
    161     main(__file__)
    162