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