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 X; 23 24 struct Annotation1 {}; 25 using XAnnot = fruit::Annotated<Annotation1, X>; 26 27 struct Annotation2 {}; 28 ''' 29 30class TestInjectedProvider(parameterized.TestCase): 31 @parameterized.parameters([ 32 ('X*', r'X\*'), 33 ('const X*', r'const X\*'), 34 ('X&', r'X&'), 35 ('const X&', r'const X&'), 36 ('std::shared_ptr<X>', r'std::shared_ptr<X>'), 37 ]) 38 def test_error_non_class_type_parameter(self, XVariant, XVariantRegexp): 39 source = ''' 40 struct X {}; 41 42 fruit::Provider<XVariant> provider; 43 ''' 44 expect_compile_error( 45 'NonClassTypeError<XVariantRegexp,X>', 46 'A non-class type T was specified. Use C instead', 47 COMMON_DEFINITIONS, 48 source, 49 locals()) 50 51 def test_error_annotated_type_parameter(self): 52 source = ''' 53 struct X {}; 54 55 fruit::Provider<XAnnot> provider; 56 ''' 57 expect_compile_error( 58 'AnnotatedTypeError<fruit::Annotated<Annotation1,X>,X>', 59 'An annotated type was specified where a non-annotated type was expected.', 60 COMMON_DEFINITIONS, 61 source) 62 63 @parameterized.parameters([ 64 ('X', 'fruit::Provider<X>', 'X', 'X'), 65 ('X', 'fruit::Provider<X>', 'X', 'const X&'), 66 ('X', 'fruit::Provider<X>', 'X', 'const X*'), 67 ('X', 'fruit::Provider<X>', 'X', 'X&'), 68 ('X', 'fruit::Provider<X>', 'X', 'X*'), 69 ('X', 'fruit::Provider<X>', 'X', 'std::shared_ptr<X>'), 70 ('X', 'fruit::Provider<X>', 'X', 'fruit::Provider<X>'), 71 ('X', 'fruit::Provider<X>', 'X', 'fruit::Provider<const X>'), 72 ('X', 'fruit::Provider<const X>', 'const X', 'const X&'), 73 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, fruit::Provider<X>>', 'X', 'const X&'), 74 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, fruit::Provider<const X>>', 'const X', 'const X&'), 75 ]) 76 def test_provider_get_ok(self, XBindingInInjector, XProviderAnnot, XParamInProvider, XProviderGetParam): 77 source = ''' 78 struct X { 79 using Inject = X(); 80 }; 81 82 fruit::Component<XBindingInInjector> getComponent() { 83 return fruit::createComponent(); 84 } 85 86 int main() { 87 fruit::Injector<XBindingInInjector> injector(getComponent); 88 fruit::Provider<XParamInProvider> provider = injector.get<XProviderAnnot>(); 89 90 XProviderGetParam x = provider.get<XProviderGetParam>(); 91 (void)x; 92 } 93 ''' 94 expect_success( 95 COMMON_DEFINITIONS, 96 source, 97 locals()) 98 99 @parameterized.parameters([ 100 ('const X', 'fruit::Provider<const X>', 'const X', 'X'), 101 ('const X', 'fruit::Provider<const X>', 'const X', 'const X&'), 102 ('const X', 'fruit::Provider<const X>', 'const X', 'const X*'), 103 ('const X', 'fruit::Provider<const X>', 'const X', 'fruit::Provider<const X>'), 104 ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, fruit::Provider<const X>>', 'const X', 'const X&'), 105 ]) 106 def test_provider_get_const_binding_ok(self, XBindingInInjector, XProviderAnnot, XParamInProvider, XProviderGetParam): 107 XBindingInInjectorWithoutConst = XBindingInInjector.replace('const ', '') 108 source = ''' 109 struct X {}; 110 111 const X x{}; 112 113 fruit::Component<XBindingInInjector> getComponent() { 114 return fruit::createComponent() 115 .bindInstance<XBindingInInjectorWithoutConst, X>(x); 116 } 117 118 int main() { 119 fruit::Injector<XBindingInInjector> injector(getComponent); 120 fruit::Provider<XParamInProvider> provider = injector.get<XProviderAnnot>(); 121 122 XProviderGetParam x = provider.get<XProviderGetParam>(); 123 (void)x; 124 } 125 ''' 126 expect_success( 127 COMMON_DEFINITIONS, 128 source, 129 locals()) 130 131 def test_provider_get_during_injection_ok(self): 132 source = ''' 133 struct X { 134 INJECT(X()) = default; 135 void foo() { 136 } 137 }; 138 139 struct Y { 140 X x; 141 INJECT(Y(fruit::Provider<X> xProvider)) 142 : x(xProvider.get<X>()) { 143 } 144 145 void foo() { 146 x.foo(); 147 } 148 }; 149 150 struct Z { 151 Y y; 152 INJECT(Z(fruit::Provider<Y> yProvider)) 153 : y(yProvider.get<Y>()) { 154 } 155 156 void foo() { 157 y.foo(); 158 } 159 }; 160 161 fruit::Component<Z> getZComponent() { 162 return fruit::createComponent(); 163 } 164 165 int main() { 166 fruit::Injector<Z> injector(getZComponent); 167 fruit::Provider<Z> provider(injector); 168 // During provider.get<Z>(), yProvider.get() is called, and during that xProvider.get() 169 // is called. 170 Z z = provider.get<Z>(); 171 z.foo(); 172 } 173 ''' 174 expect_success( 175 COMMON_DEFINITIONS, 176 source) 177 178 def test_provider_get_error_type_not_provided(self): 179 source = ''' 180 struct X {}; 181 struct Y {}; 182 183 void f(fruit::Provider<X> provider) { 184 provider.get<Y>(); 185 } 186 ''' 187 expect_compile_error( 188 'TypeNotProvidedError<Y>', 189 'Trying to get an instance of T, but it is not provided by this Provider/Injector.', 190 COMMON_DEFINITIONS, 191 source) 192 193 @parameterized.parameters([ 194 ('X**', r'X\*\*'), 195 ('std::shared_ptr<X>*', r'std::shared_ptr<X>\*'), 196 ('const std::shared_ptr<X>', r'const std::shared_ptr<X>'), 197 ('X* const', r'X\* const'), 198 ('const X* const', r'const X\* const'), 199 ('std::nullptr_t', r'(std::)?nullptr(_t)?'), 200 ('X*&', r'X\*&'), 201 ('X(*)()', r'X(\((__cdecl)?\*\))?\((void)?\)'), 202 ('void', r'void'), 203 ('fruit::Annotated<Annotation1, fruit::Annotated<Annotation1, X>>', r'fruit::Annotated<Annotation1, X>'), 204 ]) 205 def test_provider_get_error_type_not_injectable(self, XVariant, XVariantRegex): 206 source = ''' 207 struct X {}; 208 209 void f(fruit::Provider<X> provider) { 210 provider.get<XVariant>(); 211 } 212 ''' 213 expect_compile_error( 214 'NonInjectableTypeError<XVariantRegex>', 215 'The type T is not injectable', 216 COMMON_DEFINITIONS, 217 source, 218 locals()) 219 220 @parameterized.parameters([ 221 ('X&', r'X&'), 222 ('X*', r'X\*'), 223 ('std::shared_ptr<X>', r'std::shared_ptr<X>'), 224 ('fruit::Provider<X>', r'fruit::Provider<X>'), 225 ]) 226 def test_const_provider_get_does_not_allow_injecting_nonconst_variants(self, XProviderGetParam, XProviderGetParamRegex): 227 source = ''' 228 void f(fruit::Provider<const X> provider) { 229 provider.get<XProviderGetParam>(); 230 } 231 ''' 232 expect_compile_error( 233 'TypeProvidedAsConstOnlyError<XProviderGetParamRegex>', 234 'Trying to get an instance of T, but it is only provided as a constant by this Provider/Injector', 235 COMMON_DEFINITIONS, 236 source, 237 locals()) 238 239 @parameterized.parameters([ 240 ('fruit::Provider<Y>'), 241 ('ANNOTATED(Annotation1, fruit::Provider<Y>)'), 242 ]) 243 def test_lazy_injection_with_annotations(self, Y_PROVIDER_ANNOT): 244 source = ''' 245 struct Y : public ConstructionTracker<Y> { 246 using Inject = Y(); 247 }; 248 249 struct X : public ConstructionTracker<X> { 250 INJECT(X(Y_PROVIDER_ANNOT provider)) : provider(provider) { 251 } 252 253 void run() { 254 Y* y(provider); 255 (void) y; 256 } 257 258 fruit::Provider<Y> provider; 259 }; 260 261 fruit::Component<X> getComponent() { 262 return fruit::createComponent(); 263 } 264 265 fruit::Component<> getEmptyComponent() { 266 return fruit::createComponent(); 267 } 268 269 int main() { 270 fruit::NormalizedComponent<> normalizedComponent(getEmptyComponent); 271 fruit::Injector<X> injector(normalizedComponent, getComponent); 272 273 Assert(X::num_objects_constructed == 0); 274 Assert(Y::num_objects_constructed == 0); 275 276 X* x(injector); 277 278 Assert(X::num_objects_constructed == 1); 279 Assert(Y::num_objects_constructed == 0); 280 281 x->run(); 282 283 Assert(X::num_objects_constructed == 1); 284 Assert(Y::num_objects_constructed == 1); 285 } 286 ''' 287 expect_success( 288 COMMON_DEFINITIONS, 289 source, 290 locals()) 291 292if __name__ == '__main__': 293 absltest.main() 294