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