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.: none of the 2 overloads could convert all the argument types', 114 COMMON_DEFINITIONS, 115 source, 116 locals()) 117 118 @parameterized.parameters([ 119 ('X', 'const X'), 120 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'), 121 ]) 122 def test_error_declared_nonconst_types_provided_as_const_with_normalized_component(self, XAnnot, ConstXAnnot): 123 source = ''' 124 struct X {}; 125 126 fruit::Component<> getEmptyComponent(); 127 128 void f(fruit::NormalizedComponent<ConstXAnnot> normalizedComponent) { 129 fruit::Injector<XAnnot> injector(normalizedComponent, getEmptyComponent); 130 } 131 ''' 132 expect_compile_error( 133 'TypesInInjectorProvidedAsConstOnlyError<XAnnot>', 134 'The types in TypesProvidedAsConstOnly are declared as non-const provided types by the injector', 135 COMMON_DEFINITIONS, 136 source, 137 locals()) 138 139 @parameterized.parameters([ 140 ('X', 'Y'), 141 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, Y>'), 142 ]) 143 def test_injector_get_error_type_not_provided(self, XAnnot, YAnnot): 144 source = ''' 145 struct X { 146 using Inject = X(); 147 }; 148 149 struct Y {}; 150 151 fruit::Component<XAnnot> getComponent() { 152 return fruit::createComponent(); 153 } 154 155 int main() { 156 fruit::Injector<XAnnot> injector(getComponent); 157 injector.get<YAnnot>(); 158 } 159 ''' 160 expect_compile_error( 161 'TypeNotProvidedError<YAnnot>', 162 'Trying to get an instance of T, but it is not provided by this Provider/Injector.', 163 COMMON_DEFINITIONS, 164 source, 165 locals()) 166 167 @parameterized.parameters([ 168 ('const X', 'X&', r'X&'), 169 ('const X', 'X*', r'X\*'), 170 ('const X', 'std::shared_ptr<X>', r'std::shared_ptr<X>'), 171 ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X&>', r'fruit::Annotated<Annotation1, 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, std::shared_ptr<X>>', r'fruit::Annotated<Annotation1, std::shared_ptr<X>>'), 174 ]) 175 def test_injector_const_provided_type_does_not_allow_injecting_nonconst_variants(self, ConstXAnnot, XInjectorGetParam, XInjectorGetParamRegex): 176 source = ''' 177 void f(fruit::Injector<ConstXAnnot> injector) { 178 injector.get<XInjectorGetParam>(); 179 } 180 ''' 181 expect_compile_error( 182 'TypeProvidedAsConstOnlyError<XInjectorGetParamRegex>', 183 'Trying to get an instance of T, but it is only provided as a constant by this Provider/Injector', 184 COMMON_DEFINITIONS, 185 source, 186 locals()) 187 188 @parameterized.parameters([ 189 ('X', 'X'), 190 ('X', 'const X&'), 191 ('X', 'const X*'), 192 ('X', 'X&'), 193 ('X', 'X*'), 194 ('X', 'std::shared_ptr<X>'), 195 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'), 196 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X&>'), 197 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X*>'), 198 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X&>'), 199 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X*>'), 200 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, std::shared_ptr<X>>'), 201 ]) 202 def test_injector_get_ok(self, XBindingInInjector, XInjectorGetParam): 203 source = ''' 204 struct X { 205 using Inject = X(); 206 }; 207 208 fruit::Component<XBindingInInjector> getComponent() { 209 return fruit::createComponent(); 210 } 211 212 int main() { 213 fruit::Injector<XBindingInInjector> injector(getComponent); 214 215 auto x = injector.get<XInjectorGetParam>(); 216 (void)x; 217 } 218 ''' 219 expect_success( 220 COMMON_DEFINITIONS, 221 source, 222 locals()) 223 224 @parameterized.parameters([ 225 ('const X', 'X'), 226 ('const X', 'const X&'), 227 ('const X', 'const X*'), 228 ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X>'), 229 ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X&>'), 230 ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X*>'), 231 ]) 232 def test_injector_get_const_binding_ok(self, XBindingInInjector, XInjectorGetParam): 233 XBindingInInjectorWithoutConst = XBindingInInjector.replace('const ', '') 234 source = ''' 235 struct X {}; 236 237 const X x{}; 238 239 fruit::Component<XBindingInInjector> getComponent() { 240 return fruit::createComponent() 241 .bindInstance<XBindingInInjectorWithoutConst, X>(x); 242 } 243 244 int main() { 245 fruit::Injector<XBindingInInjector> injector(getComponent); 246 247 auto x = injector.get<XInjectorGetParam>(); 248 (void)x; 249 } 250 ''' 251 expect_success( 252 COMMON_DEFINITIONS, 253 source, 254 locals()) 255 256 @parameterized.parameters([ 257 ('X**', r'X\*\*'), 258 ('std::shared_ptr<X>*', r'std::shared_ptr<X>\*'), 259 ('const std::shared_ptr<X>', r'const std::shared_ptr<X>'), 260 ('X* const', r'X\* const'), 261 ('const X* const', r'const X\* const'), 262 ('std::nullptr_t', r'(std::)?nullptr(_t)?'), 263 ('X*&', r'X\*&'), 264 ('X(*)()', r'X(\((__cdecl)?\*\))?\((void)?\)'), 265 ('void', r'void'), 266 ('fruit::Annotated<Annotation1, X**>', r'X\*\*'), 267 ]) 268 def test_injector_get_error_type_not_injectable(self, XVariant, XVariantRegex): 269 source = ''' 270 struct X {}; 271 272 void f(fruit::Injector<X> injector) { 273 injector.get<XVariant>(); 274 } 275 ''' 276 expect_compile_error( 277 'NonInjectableTypeError<XVariantRegex>', 278 'The type T is not injectable.', 279 COMMON_DEFINITIONS, 280 source, 281 locals()) 282 283 @parameterized.parameters([ 284 ('X[]', r'X\[\]'), 285 ]) 286 def test_injector_get_error_array_type(self, XVariant, XVariantRegex): 287 source = ''' 288 struct X {}; 289 290 void f(fruit::Injector<X> injector) { 291 injector.get<XVariant>(); 292 } 293 ''' 294 expect_generic_compile_error( 295 'function cannot return array type' 296 '|function returning an array' 297 # MSVC 298 '|.fruit::Injector<X>::get.: no matching overloaded function found', 299 COMMON_DEFINITIONS, 300 source, 301 locals()) 302 303if __name__ == '__main__': 304 absltest.main() 305