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 XAnnot1 = fruit::Annotated<Annotation1, X>; 26 27 struct Annotation2 {}; 28 using XAnnot2 = fruit::Annotated<Annotation2, X>; 29 ''' 30 31class TestInjector(parameterized.TestCase): 32 def test_empty_injector(self): 33 source = ''' 34 fruit::Component<> getComponent() { 35 return fruit::createComponent(); 36 } 37 38 int main() { 39 fruit::Injector<> injector(getComponent); 40 } 41 ''' 42 expect_success( 43 COMMON_DEFINITIONS, 44 source) 45 46 @parameterized.parameters([ 47 'X', 48 'fruit::Annotated<Annotation1, X>', 49 ]) 50 def test_error_component_with_requirements(self, XAnnot): 51 source = ''' 52 struct X {}; 53 54 fruit::Component<fruit::Required<XAnnot>> getComponent(); 55 56 void f(fruit::NormalizedComponent<XAnnot> normalizedComponent) { 57 fruit::Injector<XAnnot> injector(normalizedComponent, getComponent); 58 } 59 ''' 60 expect_compile_error( 61 'ComponentWithRequirementsInInjectorError<XAnnot>', 62 'When using the two-argument constructor of Injector, the component used as second parameter must not have requirements', 63 COMMON_DEFINITIONS, 64 source, 65 locals()) 66 67 @parameterized.parameters([ 68 'X', 69 'fruit::Annotated<Annotation1, X>', 70 ]) 71 def test_error_declared_types_not_provided(self, XAnnot): 72 source = ''' 73 struct X { 74 using Inject = X(); 75 }; 76 77 fruit::Component<> getEmptyComponent() { 78 return fruit::createComponent(); 79 } 80 81 int main() { 82 fruit::NormalizedComponent<> normalizedComponent(getEmptyComponent); 83 fruit::Injector<XAnnot> injector(normalizedComponent, getEmptyComponent); 84 } 85 ''' 86 expect_compile_error( 87 'TypesInInjectorNotProvidedError<XAnnot>', 88 'The types in TypesNotProvided are declared as provided by the injector, but none of the two components passed to the Injector constructor provides them.', 89 COMMON_DEFINITIONS, 90 source, 91 locals()) 92 93 @parameterized.parameters([ 94 ('X', 'const X'), 95 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'), 96 ]) 97 def test_error_declared_nonconst_types_provided_as_const(self, XAnnot, ConstXAnnot): 98 source = ''' 99 struct X { 100 using Inject = X(); 101 }; 102 103 fruit::Component<ConstXAnnot> getComponent(); 104 105 int main() { 106 fruit::Injector<XAnnot> injector(getComponent); 107 } 108 ''' 109 expect_generic_compile_error( 110 r'no matching constructor for initialization of .fruit::Injector<XAnnot>.' 111 r'|no matching function for call to .fruit::Injector<XAnnot>::Injector\(fruit::Component<ConstXAnnot> \(&\)\(\)\).' 112 # MSVC 113 r'|.fruit::Injector<XAnnot>::Injector.: no overloaded function could convert all the argument types' 114 r'|.fruit::Injector<XAnnot>::Injector.: none of the 2 overloads could convert all the argument types', 115 COMMON_DEFINITIONS, 116 source, 117 locals()) 118 119 @parameterized.parameters([ 120 ('X', 'const X'), 121 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'), 122 ]) 123 def test_error_declared_nonconst_types_provided_as_const_with_normalized_component(self, XAnnot, ConstXAnnot): 124 source = ''' 125 struct X {}; 126 127 fruit::Component<> getEmptyComponent(); 128 129 void f(fruit::NormalizedComponent<ConstXAnnot> normalizedComponent) { 130 fruit::Injector<XAnnot> injector(normalizedComponent, getEmptyComponent); 131 } 132 ''' 133 expect_compile_error( 134 'TypesInInjectorProvidedAsConstOnlyError<XAnnot>', 135 'The types in TypesProvidedAsConstOnly are declared as non-const provided types by the injector', 136 COMMON_DEFINITIONS, 137 source, 138 locals()) 139 140 @parameterized.parameters([ 141 ('X', 'Y'), 142 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, Y>'), 143 ]) 144 def test_injector_get_error_type_not_provided(self, XAnnot, YAnnot): 145 source = ''' 146 struct X { 147 using Inject = X(); 148 }; 149 150 struct Y {}; 151 152 fruit::Component<XAnnot> getComponent() { 153 return fruit::createComponent(); 154 } 155 156 int main() { 157 fruit::Injector<XAnnot> injector(getComponent); 158 injector.get<YAnnot>(); 159 } 160 ''' 161 expect_compile_error( 162 'TypeNotProvidedError<YAnnot>', 163 'Trying to get an instance of T, but it is not provided by this Provider/Injector.', 164 COMMON_DEFINITIONS, 165 source, 166 locals()) 167 168 @parameterized.parameters([ 169 ('const X', 'X&', r'X&'), 170 ('const X', 'X*', r'X\*'), 171 ('const X', 'std::shared_ptr<X>', r'std::shared_ptr<X>'), 172 ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X&>', r'fruit::Annotated<Annotation1, X&>'), 173 ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X*>', r'fruit::Annotated<Annotation1, X\*>'), 174 ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, std::shared_ptr<X>>', r'fruit::Annotated<Annotation1, std::shared_ptr<X>>'), 175 ]) 176 def test_injector_const_provided_type_does_not_allow_injecting_nonconst_variants(self, ConstXAnnot, XInjectorGetParam, XInjectorGetParamRegex): 177 source = ''' 178 void f(fruit::Injector<ConstXAnnot> injector) { 179 injector.get<XInjectorGetParam>(); 180 } 181 ''' 182 expect_compile_error( 183 'TypeProvidedAsConstOnlyError<XInjectorGetParamRegex>', 184 'Trying to get an instance of T, but it is only provided as a constant by this Provider/Injector', 185 COMMON_DEFINITIONS, 186 source, 187 locals()) 188 189 @parameterized.parameters([ 190 ('X', 'X'), 191 ('X', 'const X&'), 192 ('X', 'const X*'), 193 ('X', 'X&'), 194 ('X', 'X*'), 195 ('X', 'std::shared_ptr<X>'), 196 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'), 197 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X&>'), 198 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X*>'), 199 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X&>'), 200 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X*>'), 201 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, std::shared_ptr<X>>'), 202 ]) 203 def test_injector_get_ok(self, XBindingInInjector, XInjectorGetParam): 204 source = ''' 205 struct X { 206 using Inject = X(); 207 }; 208 209 fruit::Component<XBindingInInjector> getComponent() { 210 return fruit::createComponent(); 211 } 212 213 int main() { 214 fruit::Injector<XBindingInInjector> injector(getComponent); 215 216 auto x = injector.get<XInjectorGetParam>(); 217 (void)x; 218 } 219 ''' 220 expect_success( 221 COMMON_DEFINITIONS, 222 source, 223 locals()) 224 225 @parameterized.parameters([ 226 ('const X', 'X'), 227 ('const X', 'const X&'), 228 ('const X', 'const X*'), 229 ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X>'), 230 ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X&>'), 231 ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X*>'), 232 ]) 233 def test_injector_get_const_binding_ok(self, XBindingInInjector, XInjectorGetParam): 234 XBindingInInjectorWithoutConst = XBindingInInjector.replace('const ', '') 235 source = ''' 236 struct X {}; 237 238 const X x{}; 239 240 fruit::Component<XBindingInInjector> getComponent() { 241 return fruit::createComponent() 242 .bindInstance<XBindingInInjectorWithoutConst, X>(x); 243 } 244 245 int main() { 246 fruit::Injector<XBindingInInjector> injector(getComponent); 247 248 auto x = injector.get<XInjectorGetParam>(); 249 (void)x; 250 } 251 ''' 252 expect_success( 253 COMMON_DEFINITIONS, 254 source, 255 locals()) 256 257 @parameterized.parameters([ 258 ('X**', r'X\*\*'), 259 ('std::shared_ptr<X>*', r'std::shared_ptr<X>\*'), 260 ('const std::shared_ptr<X>', r'const std::shared_ptr<X>'), 261 ('X* const', r'X\* const'), 262 ('const X* const', r'const X\* const'), 263 ('std::nullptr_t', r'(std::)?nullptr(_t)?'), 264 ('X*&', r'X\*&'), 265 ('X(*)()', r'X(\((__cdecl)?\*\))?\((void)?\)'), 266 ('void', r'void'), 267 ('fruit::Annotated<Annotation1, X**>', r'X\*\*'), 268 ]) 269 def test_injector_get_error_type_not_injectable(self, XVariant, XVariantRegex): 270 source = ''' 271 struct X {}; 272 273 void f(fruit::Injector<X> injector) { 274 injector.get<XVariant>(); 275 } 276 ''' 277 expect_compile_error( 278 'NonInjectableTypeError<XVariantRegex>', 279 'The type T is not injectable.', 280 COMMON_DEFINITIONS, 281 source, 282 locals()) 283 284 @parameterized.parameters([ 285 ('X[]', r'X\[\]'), 286 ]) 287 def test_injector_get_error_array_type(self, XVariant, XVariantRegex): 288 source = ''' 289 struct X {}; 290 291 void f(fruit::Injector<X> injector) { 292 injector.get<XVariant>(); 293 } 294 ''' 295 expect_generic_compile_error( 296 'function cannot return array type' 297 '|function returning an array' 298 # MSVC 299 '|.fruit::Injector<X>::get.: no matching overloaded function found', 300 COMMON_DEFINITIONS, 301 source, 302 locals()) 303 304if __name__ == '__main__': 305 absltest.main() 306