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 Annotation1 {}; 23 struct Annotation2 {}; 24 ''' 25 26class TestBindInstance(parameterized.TestCase): 27 @parameterized.parameters([ 28 ('X', 'X', 'const X&', 'Y'), 29 ('X', 'const X', 'const X&', 'Y'), 30 ('X', 'X', 'const X&', 'fruit::Annotated<Annotation1, Y>'), 31 ('X', 'const X', 'const X&', 'fruit::Annotated<Annotation1, Y>'), 32 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X&>', 'Y'), 33 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X&>', 'Y'), 34 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X&>', 'fruit::Annotated<Annotation1, Y>'), 35 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X&>', 'fruit::Annotated<Annotation1, Y>'), 36 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X&>', 'fruit::Annotated<Annotation2, Y>'), 37 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X&>', 'fruit::Annotated<Annotation2, Y>'), 38 ]) 39 def test_bind_interface(self, XAnnot, MaybeConstXAnnot, XConstRefAnnot, YAnnot): 40 source = ''' 41 struct X { 42 virtual void f() const = 0; 43 }; 44 45 struct Y : public X { 46 INJECT(Y()) = default; 47 48 void f() const override { 49 } 50 }; 51 52 fruit::Component<MaybeConstXAnnot> getComponent() { 53 return fruit::createComponent() 54 .bind<XAnnot, YAnnot>(); 55 } 56 57 int main() { 58 fruit::Injector<MaybeConstXAnnot> injector(getComponent); 59 const X& x = injector.get<XConstRefAnnot>(); 60 x.f(); 61 } 62 ''' 63 expect_success( 64 COMMON_DEFINITIONS, 65 source, 66 locals()) 67 68 @parameterized.parameters([ 69 ('X', 'const X', 'const X&', 'Y'), 70 ('X', 'const X', 'const X&', 'fruit::Annotated<Annotation1, Y>'), 71 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X&>', 'Y'), 72 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X&>', 'fruit::Annotated<Annotation1, Y>'), 73 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>', 'fruit::Annotated<Annotation1, const X&>', 'fruit::Annotated<Annotation2, Y>'), 74 ]) 75 def test_bind_interface_to_constant(self, XAnnot, ConstXAnnot, XConstRefAnnot, YAnnot): 76 source = ''' 77 struct X { 78 virtual void f() const = 0; 79 }; 80 81 struct Y : public X { 82 void f() const override { 83 } 84 }; 85 86 const Y y{}; 87 88 fruit::Component<ConstXAnnot> getComponent() { 89 return fruit::createComponent() 90 .bindInstance<YAnnot, Y>(y) 91 .bind<XAnnot, YAnnot>(); 92 } 93 94 int main() { 95 fruit::Injector<ConstXAnnot> injector(getComponent); 96 const X& x = injector.get<XConstRefAnnot>(); 97 x.f(); 98 } 99 ''' 100 expect_success( 101 COMMON_DEFINITIONS, 102 source, 103 locals()) 104 105 @parameterized.parameters([ 106 ('X', 'X&', 'Y'), 107 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X&>', 'fruit::Annotated<Annotation2, Y>'), 108 ]) 109 def test_bind_interface_target_bound_in_other_component(self, XAnnot, XRefAnnot, YAnnot): 110 source = ''' 111 struct X { 112 virtual void f() = 0; 113 }; 114 115 struct Y : public X { 116 void f() override { 117 } 118 }; 119 120 fruit::Component<fruit::Required<YAnnot>, XAnnot> getComponent() { 121 return fruit::createComponent() 122 .bind<XAnnot, YAnnot>(); 123 } 124 125 fruit::Component<XAnnot> getRootComponent() { 126 return fruit::createComponent() 127 .registerConstructor<YAnnot()>() 128 .install(getComponent); 129 } 130 131 int main() { 132 fruit::Injector<XAnnot> injector(getRootComponent); 133 X& x = injector.get<XRefAnnot>(); 134 x.f(); 135 } 136 ''' 137 expect_success( 138 COMMON_DEFINITIONS, 139 source, 140 locals()) 141 142 @parameterized.parameters([ 143 ('X', 'X&', 'Y'), 144 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X&>', 'fruit::Annotated<Annotation2, Y>'), 145 ]) 146 def test_bind_nonconst_interface_requires_nonconst_target(self, XAnnot, XRefAnnot, YAnnot): 147 source = ''' 148 struct X { 149 virtual void f() = 0; 150 }; 151 152 struct Y : public X { 153 void f() override { 154 } 155 }; 156 157 fruit::Component<fruit::Required<const YAnnot>, XAnnot> getComponent() { 158 return fruit::createComponent() 159 .bind<XAnnot, YAnnot>(); 160 } 161 ''' 162 expect_compile_error( 163 'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<YAnnot>', 164 'The type T was declared as a const Required type in the returned Component, however a non-const binding', 165 COMMON_DEFINITIONS, 166 source, 167 locals()) 168 169 @parameterized.parameters([ 170 ('X', 'Y'), 171 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, Y>'), 172 ]) 173 def test_bind_interface_to_constant_nonconst_required_const_bound_error(self, XAnnot, YAnnot): 174 source = ''' 175 struct X { 176 virtual void f() const = 0; 177 }; 178 179 struct Y : public X { 180 void f() const override { 181 } 182 }; 183 184 const Y y{}; 185 186 fruit::Component<XAnnot> getComponent() { 187 return fruit::createComponent() 188 .bindInstance<YAnnot, Y>(y) 189 .bind<XAnnot, YAnnot>(); 190 } 191 ''' 192 expect_compile_error( 193 'NonConstBindingRequiredButConstBindingProvidedError<YAnnot>', 194 'The type T was provided as constant, however one of the constructors/providers/factories in this component', 195 COMMON_DEFINITIONS, 196 source, 197 locals()) 198 199 @parameterized.parameters([ 200 ('X', 'X&', 'Y'), 201 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X&>', 'fruit::Annotated<Annotation2, Y>'), 202 ]) 203 def test_bind_nonconst_interface_requires_nonconst_target_abstract(self, XAnnot, XRefAnnot, YAnnot): 204 source = ''' 205 struct X { 206 virtual void f() = 0; 207 }; 208 209 struct Y : public X {}; 210 211 fruit::Component<fruit::Required<const YAnnot>, XAnnot> getComponent() { 212 return fruit::createComponent() 213 .bind<XAnnot, YAnnot>(); 214 } 215 ''' 216 expect_compile_error( 217 'ConstBindingDeclaredAsRequiredButNonConstBindingRequiredError<YAnnot>', 218 'The type T was declared as a const Required type in the returned Component, however a non-const binding', 219 COMMON_DEFINITIONS, 220 source, 221 locals()) 222 223 @parameterized.parameters([ 224 ('X', 'int'), 225 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, int>'), 226 ]) 227 def test_error_not_base(self, XAnnot, intAnnot): 228 source = ''' 229 struct X {}; 230 231 fruit::Component<intAnnot> getComponent() { 232 return fruit::createComponent() 233 .bind<XAnnot, intAnnot>(); 234 } 235 ''' 236 expect_compile_error( 237 'NotABaseClassOfError<X,int>', 238 'I is not a base class of C.', 239 COMMON_DEFINITIONS, 240 source, 241 locals()) 242 243 # TODO: maybe the error should include the annotation here. 244 @parameterized.parameters([ 245 'X', 246 'fruit::Annotated<Annotation1, X>', 247 ]) 248 def test_error_bound_to_itself(self, XAnnot): 249 source = ''' 250 struct X {}; 251 252 fruit::Component<X> getComponent() { 253 return fruit::createComponent() 254 .bind<XAnnot, XAnnot>(); 255 } 256 ''' 257 expect_compile_error( 258 'InterfaceBindingToSelfError<X>', 259 'The type C was bound to itself.', 260 COMMON_DEFINITIONS, 261 source, 262 locals()) 263 264 def test_bound_to_itself_with_annotation_error(self): 265 source = ''' 266 struct X {}; 267 268 fruit::Component<> getComponent() { 269 return fruit::createComponent() 270 .registerConstructor<X()>() 271 .bind<fruit::Annotated<Annotation1, X>, X>(); 272 } 273 ''' 274 expect_compile_error( 275 'InterfaceBindingToSelfError<X>', 276 'The type C was bound to itself.', 277 COMMON_DEFINITIONS, 278 source) 279 280 def test_bound_chain_ok(self): 281 source = ''' 282 struct X { 283 virtual void f() = 0; 284 }; 285 286 struct Y : public X {}; 287 288 struct Z : public Y { 289 INJECT(Z()) = default; 290 void f() override { 291 } 292 }; 293 294 fruit::Component<X> getComponent() { 295 return fruit::createComponent() 296 .bind<X, Y>() 297 .bind<Y, Z>(); 298 } 299 300 int main() { 301 fruit::Injector<X> injector(getComponent); 302 X& x = injector.get<X&>(); 303 x.f(); 304 } 305 ''' 306 expect_success(COMMON_DEFINITIONS, source) 307 308 def test_bind_non_normalized_types_error(self): 309 source = ''' 310 struct X {}; 311 312 struct Y : public std::shared_ptr<X> {}; 313 314 fruit::Component<> getComponent() { 315 return fruit::createComponent() 316 .bind<std::shared_ptr<X>, Y>(); 317 } 318 ''' 319 expect_compile_error( 320 'NonClassTypeError<std::shared_ptr<X>,X>', 321 'A non-class type T was specified. Use C instead', 322 COMMON_DEFINITIONS, 323 source) 324 325if __name__ == '__main__': 326 absltest.main() 327