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 struct Y; 24 struct Z; 25 26 struct Annotation1 {}; 27 using XAnnot1 = fruit::Annotated<Annotation1, X>; 28 using YAnnot1 = fruit::Annotated<Annotation1, Y>; 29 using ZAnnot1 = fruit::Annotated<Annotation1, Z>; 30 using ConstXAnnot1 = fruit::Annotated<Annotation1, const X>; 31 using ConstYAnnot1 = fruit::Annotated<Annotation1, const Y>; 32 using ConstZAnnot1 = fruit::Annotated<Annotation1, const Z>; 33 34 struct Annotation2 {}; 35 using XAnnot2 = fruit::Annotated<Annotation2, X>; 36 using YAnnot2 = fruit::Annotated<Annotation2, Y>; 37 using ZAnnot2 = fruit::Annotated<Annotation2, Z>; 38 using ConstXAnnot2 = fruit::Annotated<Annotation2, const X>; 39 using ConstYAnnot2 = fruit::Annotated<Annotation2, const Y>; 40 using ConstZAnnot2 = fruit::Annotated<Annotation2, const Z>; 41 42 struct Annotation3 {}; 43 ''' 44 45CONSTRUCTOR_BINDING = ( 46 '', 47 '.registerConstructor<XAnnot()>()') 48INTERFACE_BINDING = ( 49 ''' 50 struct Y : public X {}; 51 ''', 52 ''' 53 .bind<XAnnot, YAnnot>() 54 .registerConstructor<YAnnot()>() 55 ''') 56INTERFACE_BINDING2 = ( 57 ''' 58 struct Y2 : public X {}; 59 ''', 60 ''' 61 .bind<XAnnot, Y2Annot>() 62 .registerConstructor<Y2Annot()>() 63 ''') 64INSTALL = ( 65 ''' 66 fruit::Component<XAnnot> getParentComponent() { 67 return fruit::createComponent() 68 .registerConstructor<XAnnot()>(); 69 } 70 ''', 71 '.install(getParentComponent)') 72INSTALL2 = ( 73 ''' 74 fruit::Component<XAnnot> getParentComponent2() { 75 return fruit::createComponent() 76 .registerConstructor<XAnnot()>(); 77 } 78 ''', 79 '.install(getParentComponent2)') 80CONST_BINDING_FROM_INSTALL = ( 81 ''' 82 fruit::Component<const XAnnot> getParentComponent() { 83 return fruit::createComponent() 84 .registerConstructor<XAnnot()>(); 85 } 86 ''', 87 '.install(getParentComponent)') 88CONST_BINDING_FROM_INSTALL2 = ( 89 ''' 90 fruit::Component<const XAnnot> getParentComponent2() { 91 return fruit::createComponent() 92 .registerConstructor<XAnnot()>(); 93 } 94 ''', 95 '.install(getParentComponent2)') 96CONST_BINDING = ( 97 ''' 98 const X x{}; 99 ''', 100 '.bindInstance<XAnnot, X>(x)') 101CONST_BINDING2 = ( 102 ''' 103 const X x2{}; 104 ''', 105 '.bindInstance<XAnnot, X>(x2)') 106 107class TestBindingClash(parameterized.TestCase): 108 @multiple_named_parameters([ 109 ('CONSTRUCTOR_BINDING + INSTALL',) + CONSTRUCTOR_BINDING + INSTALL, 110 ('INTERFACE_BINDING + INSTALL',) + INTERFACE_BINDING + INSTALL, 111 ('INSTALL + INSTALL2',) + INSTALL + INSTALL2, 112 ('CONSTRUCTOR_BINDING + CONST_BINDING_FROM_INSTALL',) + CONSTRUCTOR_BINDING + CONST_BINDING_FROM_INSTALL, 113 ('INTERFACE_BINDING + CONST_BINDING_FROM_INSTALL',) + INTERFACE_BINDING + CONST_BINDING_FROM_INSTALL, 114 ('INSTALL2 + CONST_BINDING_FROM_INSTALL',) + INSTALL2 + CONST_BINDING_FROM_INSTALL, 115 ('CONST_BINDING_FROM_INSTALL + INSTALL2',) + CONST_BINDING_FROM_INSTALL + INSTALL2, 116 ('CONST_BINDING + INSTALL2',) + CONST_BINDING + INSTALL2, 117 ('CONST_BINDING_FROM_INSTALL + CONST_BINDING_FROM_INSTALL2',) + CONST_BINDING_FROM_INSTALL + CONST_BINDING_FROM_INSTALL2, 118 ('CONST_BINDING + CONST_BINDING_FROM_INSTALL',) + CONST_BINDING + CONST_BINDING_FROM_INSTALL, 119 ], [ 120 ('No annotation', 'X', 'Y', 'Y2'), 121 ('With annotation', 'fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, Y>', 'fruit::Annotated<Annotation3, Y2>'), 122 ]) 123 def test_clash_with_install(self, 124 binding1_preparation, binding1, binding2_preparation, binding2, XAnnot, YAnnot, Y2Annot): 125 source = ''' 126 struct X{}; 127 128 %s 129 %s 130 131 fruit::Component<XAnnot> getComponent() { 132 return fruit::createComponent() 133 %s 134 %s; 135 } 136 ''' % (binding1_preparation, binding2_preparation, binding1, binding2) 137 expect_compile_error( 138 'DuplicateTypesInComponentError<XAnnot>', 139 'The installed component provides some types that are already provided by the current component.', 140 COMMON_DEFINITIONS, 141 source, 142 locals()) 143 144 @multiple_named_parameters([ 145 ('CONSTRUCTOR_BINDING + CONSTRUCTOR_BINDING',) + CONSTRUCTOR_BINDING + CONSTRUCTOR_BINDING, 146 ('CONSTRUCTOR_BINDING + INTERFACE_BINDING',) + CONSTRUCTOR_BINDING + INTERFACE_BINDING, 147 ('INTERFACE_BINDING + CONSTRUCTOR_BINDING',) + INTERFACE_BINDING + CONSTRUCTOR_BINDING, 148 ('INTERFACE_BINDING + INTERFACE_BINDING2',) + INTERFACE_BINDING + INTERFACE_BINDING2, 149 ('INSTALL + CONSTRUCTOR_BINDING',) + INSTALL + CONSTRUCTOR_BINDING, 150 ('INSTALL + INTERFACE_BINDING',) + INSTALL + INTERFACE_BINDING, 151 ('CONST_BINDING_FROM_INSTALL + CONSTRUCTOR_BINDING',) + CONST_BINDING_FROM_INSTALL + CONSTRUCTOR_BINDING, 152 ('CONST_BINDING_FROM_INSTALL + INTERFACE_BINDING',) + CONST_BINDING_FROM_INSTALL + INTERFACE_BINDING, 153 ('CONST_BINDING + CONSTRUCTOR_BINDING',) + CONST_BINDING + CONSTRUCTOR_BINDING, 154 ('CONST_BINDING + INTERFACE_BINDING',) + CONST_BINDING + INTERFACE_BINDING, 155 ('CONSTRUCTOR_BINDING + CONST_BINDING',) + CONSTRUCTOR_BINDING + CONST_BINDING, 156 ('INTERFACE_BINDING + CONST_BINDING',) + INTERFACE_BINDING + CONST_BINDING, 157 ('INSTALL2 + CONST_BINDING',) + INSTALL2 + CONST_BINDING, 158 ('CONST_BINDING_FROM_INSTALL + CONST_BINDING',) + CONST_BINDING_FROM_INSTALL + CONST_BINDING, 159 ('CONST_BINDING + CONST_BINDING2',) + CONST_BINDING + CONST_BINDING2, 160 ], [ 161 ('No annotation', 'X', 'Y', 'Y2'), 162 ('With annotation', 'fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, Y>', 'fruit::Annotated<Annotation3, Y2>'), 163 ]) 164 def test_clash_with_binding(self, binding1_preparation, binding1, binding2_preparation, binding2, XAnnot, YAnnot, Y2Annot): 165 source = ''' 166 struct X{}; 167 168 %s 169 %s 170 171 fruit::Component<XAnnot> getComponent() { 172 return fruit::createComponent() 173 %s 174 %s; 175 } 176 177 ''' % (binding1_preparation, binding2_preparation, binding1, binding2) 178 expect_compile_error( 179 'TypeAlreadyBoundError<XAnnot>', 180 'Trying to bind C but it is already bound.', 181 COMMON_DEFINITIONS, 182 source, 183 locals()) 184 185 CONSTRUCTOR_BINDING_ANNOT1 = ( 186 '', 187 '.registerConstructor<XAnnot1()>()') 188 CONSTRUCTOR_BINDING_ANNOT2 = ( 189 '', 190 '.registerConstructor<XAnnot2()>()') 191 INTERFACE_BINDING_ANNOT1 = ( 192 ''' 193 struct Y : public X {}; 194 ''', 195 ''' 196 .bind<XAnnot1, YAnnot1>() 197 .registerConstructor<YAnnot1()>() 198 ''') 199 INTERFACE_BINDING_ANNOT2 = ( 200 ''' 201 struct Z : public X {}; 202 ''', 203 ''' 204 .bind<XAnnot2, ZAnnot2>() 205 .registerConstructor<ZAnnot2()>() 206 ''') 207 INSTALL_ANNOT1 = ( 208 ''' 209 fruit::Component<XAnnot1> getParentComponent1() { 210 return fruit::createComponent() 211 .registerConstructor<XAnnot1()>(); 212 } 213 ''', 214 '.install(getParentComponent1)') 215 INSTALL_ANNOT2 = ( 216 ''' 217 fruit::Component<XAnnot2> getParentComponent2() { 218 return fruit::createComponent() 219 .registerConstructor<XAnnot2()>(); 220 } 221 ''', 222 '.install(getParentComponent2)') 223 CONST_BINDING_FROM_INSTALL_ANNOT1 = ( 224 ''' 225 fruit::Component<ConstXAnnot1> getParentComponent1() { 226 return fruit::createComponent() 227 .registerConstructor<XAnnot1()>(); 228 } 229 ''', 230 '.install(getParentComponent1)') 231 CONST_BINDING_FROM_INSTALL_ANNOT2 = ( 232 ''' 233 fruit::Component<ConstXAnnot2> getParentComponent2() { 234 return fruit::createComponent() 235 .registerConstructor<XAnnot2()>(); 236 } 237 ''', 238 '.install(getParentComponent2)') 239 CONST_BINDING_ANNOT1 = ( 240 ''' 241 const X x1{}; 242 ''', 243 '.bindInstance<XAnnot1, X>(x1)') 244 CONST_BINDING_ANNOT2 = ( 245 ''' 246 const X x2{}; 247 ''', 248 '.bindInstance<XAnnot2, X>(x2)') 249 250 @parameterized.named_parameters([ 251 ('CONSTRUCTOR_BINDING_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2',) + CONSTRUCTOR_BINDING_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2, 252 ('CONSTRUCTOR_BINDING_ANNOT1 + INTERFACE_BINDING_ANNOT2',) + CONSTRUCTOR_BINDING_ANNOT1 + INTERFACE_BINDING_ANNOT2, 253 ('INTERFACE_BINDING_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2',) + INTERFACE_BINDING_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2, 254 ('INTERFACE_BINDING_ANNOT1 + INTERFACE_BINDING_ANNOT2',) + INTERFACE_BINDING_ANNOT1 + INTERFACE_BINDING_ANNOT2, 255 ('INSTALL_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2',) + INSTALL_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2, 256 ('INSTALL_ANNOT1 + INTERFACE_BINDING_ANNOT2',) + INSTALL_ANNOT1 + INTERFACE_BINDING_ANNOT2, 257 ('CONST_BINDING_FROM_INSTALL_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2',) + CONST_BINDING_FROM_INSTALL_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2, 258 ('CONST_BINDING_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2',) + CONST_BINDING_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2, 259 ('CONST_BINDING_FROM_INSTALL_ANNOT1 + INTERFACE_BINDING_ANNOT2',) + CONST_BINDING_FROM_INSTALL_ANNOT1 + INTERFACE_BINDING_ANNOT2, 260 ('CONST_BINDING_ANNOT1 + INTERFACE_BINDING_ANNOT2',) + CONST_BINDING_ANNOT1 + INTERFACE_BINDING_ANNOT2, 261 ('CONSTRUCTOR_BINDING_ANNOT1 + INSTALL_ANNOT2',) + CONSTRUCTOR_BINDING_ANNOT1 + INSTALL_ANNOT2, 262 ('INTERFACE_BINDING_ANNOT1 + INSTALL_ANNOT2',) + INTERFACE_BINDING_ANNOT1 + INSTALL_ANNOT2, 263 ('CONSTRUCTOR_BINDING_ANNOT1 + CONST_BINDING_FROM_INSTALL_ANNOT2',) + CONSTRUCTOR_BINDING_ANNOT1 + CONST_BINDING_FROM_INSTALL_ANNOT2, 264 ('CONSTRUCTOR_BINDING_ANNOT1 + CONST_BINDING_ANNOT2',) + CONSTRUCTOR_BINDING_ANNOT1 + CONST_BINDING_ANNOT2, 265 ('INTERFACE_BINDING_ANNOT1 + CONST_BINDING_FROM_INSTALL_ANNOT2',) + INTERFACE_BINDING_ANNOT1 + CONST_BINDING_FROM_INSTALL_ANNOT2, 266 ('INTERFACE_BINDING_ANNOT1 + CONST_BINDING_ANNOT2',) + INTERFACE_BINDING_ANNOT1 + CONST_BINDING_ANNOT2, 267 ('INSTALL_ANNOT1 + INSTALL_ANNOT2',) + INSTALL_ANNOT1 + INSTALL_ANNOT2, 268 ('CONST_BINDING_FROM_INSTALL_ANNOT1 + INSTALL_ANNOT2',) + CONST_BINDING_FROM_INSTALL_ANNOT1 + INSTALL_ANNOT2, 269 ('CONST_BINDING_ANNOT1 + INSTALL_ANNOT2',) + CONST_BINDING_ANNOT1 + INSTALL_ANNOT2, 270 ('INSTALL_ANNOT1 + CONST_BINDING_FROM_INSTALL_ANNOT2',) + INSTALL_ANNOT1 + CONST_BINDING_FROM_INSTALL_ANNOT2, 271 ('INSTALL_ANNOT1 + CONST_BINDING_ANNOT2',) + INSTALL_ANNOT1 + CONST_BINDING_ANNOT2, 272 ('CONST_BINDING_FROM_INSTALL_ANNOT1 + CONST_BINDING_FROM_INSTALL_ANNOT2',) + CONST_BINDING_FROM_INSTALL_ANNOT1 + CONST_BINDING_FROM_INSTALL_ANNOT2, 273 ('CONST_BINDING_ANNOT1 + CONST_BINDING_ANNOT2',) + CONST_BINDING_ANNOT1 + CONST_BINDING_ANNOT2, 274 ('CONST_BINDING_ANNOT1 + CONST_BINDING_FROM_INSTALL_ANNOT2',) + CONST_BINDING_ANNOT1 + CONST_BINDING_FROM_INSTALL_ANNOT2, 275 ]) 276 def test_no_clash_with_different_annotations(self, binding1_preparation, binding1, binding2_preparation, binding2): 277 source = ''' 278 struct X {}; 279 280 %s 281 %s 282 283 fruit::Component<const XAnnot1, const XAnnot2> getComponent() { 284 return fruit::createComponent() 285 %s 286 %s; 287 } 288 289 int main() { 290 fruit::Injector<const XAnnot1, const XAnnot2> injector(getComponent); 291 injector.get<XAnnot1>(); 292 injector.get<XAnnot2>(); 293 } 294 ''' % (binding1_preparation, binding2_preparation, binding1, binding2) 295 expect_success( 296 COMMON_DEFINITIONS, 297 source) 298 299 @parameterized.parameters([ 300 ('X', 'X', 'X'), 301 ('const X', 'X', 'X'), 302 ('X', 'const X', 'X'), 303 ('const X', 'const X', 'X'), 304 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'), 305 ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'), 306 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X>'), 307 ('fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, X>'), 308 ]) 309 def test_during_component_merge(self, NormalizedComponentXAnnot, ComponentXAnnot, XAnnot): 310 source = ''' 311 struct X {}; 312 313 fruit::Component<NormalizedComponentXAnnot> getComponent1() { 314 return fruit::createComponent() 315 .registerConstructor<XAnnot()>(); 316 } 317 318 fruit::Component<ComponentXAnnot> getComponent2() { 319 return fruit::createComponent() 320 .registerConstructor<XAnnot()>(); 321 } 322 323 void f() { 324 fruit::NormalizedComponent<NormalizedComponentXAnnot> nc(getComponent1); 325 fruit::Injector<> injector(nc, getComponent2); 326 (void) injector; 327 } 328 ''' 329 expect_compile_error( 330 'DuplicateTypesInComponentError<XAnnot>', 331 'The installed component provides some types that are already provided', 332 COMMON_DEFINITIONS, 333 source, 334 locals()) 335 336 def test_during_component_merge_with_different_annotation_ok(self): 337 source = ''' 338 struct X {}; 339 340 fruit::Component<XAnnot1> getComponent1() { 341 return fruit::createComponent() 342 .registerConstructor<XAnnot1()>(); 343 } 344 345 fruit::Component<XAnnot2> getComponent2() { 346 return fruit::createComponent() 347 .registerConstructor<XAnnot2()>(); 348 } 349 350 int main() { 351 fruit::NormalizedComponent<XAnnot1> nc(getComponent1); 352 fruit::Injector<XAnnot1, XAnnot2> injector(nc, getComponent2); 353 injector.get<XAnnot1>(); 354 injector.get<XAnnot2>(); 355 } 356 ''' 357 expect_success( 358 COMMON_DEFINITIONS, 359 source) 360 361 @parameterized.parameters([ 362 ('X', '(struct )?X'), 363 ('fruit::Annotated<Annotation1, X>', '(struct )?fruit::Annotated<(struct )?Annotation1, ?(struct )?X>'), 364 ]) 365 def test_bind_instance_and_bind_instance_runtime(self, XAnnot, XAnnotRegex): 366 source = ''' 367 struct X {}; 368 369 fruit::Component<> getComponentForInstanceHelper() { 370 // Note: don't do this in real code, leaks memory. 371 return fruit::createComponent() 372 .bindInstance<XAnnot, X>(*(new X())); 373 } 374 375 fruit::Component<XAnnot> getComponentForInstance() { 376 // Note: don't do this in real code, leaks memory. 377 return fruit::createComponent() 378 .install(getComponentForInstanceHelper) 379 .bindInstance<XAnnot, X>(*(new X())); 380 } 381 382 int main() { 383 fruit::Injector<XAnnot> injector(getComponentForInstance); 384 injector.get<XAnnot>(); 385 } 386 ''' 387 expect_runtime_error( 388 'Fatal injection error: the type XAnnotRegex was provided more than once, with different bindings.', 389 COMMON_DEFINITIONS, 390 source, 391 locals()) 392 393 @parameterized.parameters([ 394 ('X', '(struct )?X'), 395 ('fruit::Annotated<Annotation1, X>', '(struct )?fruit::Annotated<(struct )?Annotation1, ?(struct )?X>'), 396 ]) 397 def test_bind_instance_and_binding_runtime(self, XAnnot, XAnnotRegex): 398 source = ''' 399 struct X {}; 400 401 fruit::Component<> getComponentForInstanceHelper(X* x) { 402 return fruit::createComponent() 403 .bindInstance<XAnnot, X>(*x); 404 } 405 406 fruit::Component<XAnnot> getComponentForInstance(X* x) { 407 return fruit::createComponent() 408 .install(getComponentForInstanceHelper, x) 409 .registerConstructor<XAnnot()>(); 410 } 411 412 int main() { 413 X x; 414 fruit::Injector<XAnnot> injector(getComponentForInstance, &x); 415 injector.get<XAnnot>(); 416 } 417 ''' 418 expect_runtime_error( 419 'Fatal injection error: the type XAnnotRegex was provided more than once, with different bindings.', 420 COMMON_DEFINITIONS, 421 source, 422 locals()) 423 424 @parameterized.parameters([ 425 'X', 426 'fruit::Annotated<Annotation1, X>', 427 ]) 428 def test_during_component_merge_consistent_ok(self, XAnnot): 429 source = ''' 430 struct X : public ConstructionTracker<X> { 431 using Inject = X(); 432 }; 433 434 fruit::Component<XAnnot> getComponent() { 435 return fruit::createComponent(); 436 } 437 438 fruit::Component<> getRootComponent() { 439 return fruit::createComponent() 440 .install(getComponent); 441 } 442 443 int main() { 444 fruit::NormalizedComponent<> normalizedComponent(getRootComponent); 445 fruit::Injector<XAnnot> injector(normalizedComponent, getComponent); 446 447 Assert(X::num_objects_constructed == 0); 448 injector.get<XAnnot>(); 449 Assert(X::num_objects_constructed == 1); 450 } 451 ''' 452 expect_success( 453 COMMON_DEFINITIONS, 454 source, 455 locals()) 456 457if __name__ == '__main__': 458 absltest.main() 459