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. 15import pytest 16 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 35@pytest.mark.parametrize('IAnnot,XAnnot,WithAnnot', [ 36 ('I', 'X', 'WithNoAnnot'), 37 ('fruit::Annotated<Annotation1, I>', 'fruit::Annotated<Annotation2, X>', 'WithAnnot1'), 38]) 39def 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]) 77def 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 110def 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 160if __name__== '__main__': 161 main(__file__) 162