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. 15import pytest 16from absl.testing import parameterized 17from fruit_test_common import * 18from fruit_test_config import CXX_COMPILER_NAME 19import re 20 21COMMON_DEFINITIONS = ''' 22 #include "test_common.h" 23 24 struct Annotation {}; 25 struct Annotation1 {}; 26 struct Annotation2 {}; 27 ''' 28 29class TestMultibindingsBindInterface(parameterized.TestCase): 30 @parameterized.parameters([ 31 ('X', 'XImpl'), 32 ('X', 'fruit::Annotated<Annotation2, XImpl>'), 33 ('fruit::Annotated<Annotation1, X>', 'XImpl'), 34 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, XImpl>'), 35 ]) 36 def test_add_interface_multibinding_success(self, XAnnot, XImplAnnot): 37 source = ''' 38 struct X { 39 virtual int foo() = 0; 40 }; 41 42 struct XImpl : public X { 43 INJECT(XImpl()) = default; 44 45 int foo() override { 46 return 5; 47 } 48 }; 49 50 fruit::Component<> getComponent() { 51 return fruit::createComponent() 52 .addMultibinding<XAnnot, XImplAnnot>(); 53 } 54 55 int main() { 56 fruit::Injector<> injector(getComponent); 57 58 std::vector<X*> multibindings = injector.getMultibindings<XAnnot>(); 59 Assert(multibindings.size() == 1); 60 Assert(multibindings[0]->foo() == 5); 61 } 62 ''' 63 expect_success( 64 COMMON_DEFINITIONS, 65 source, 66 locals()) 67 68 @parameterized.parameters([ 69 ('X', 'XImpl', 'const XImpl'), 70 ('X', 'fruit::Annotated<Annotation2, XImpl>', 'fruit::Annotated<Annotation2, const XImpl>'), 71 ]) 72 def test_add_interface_multibinding_const_target_error_install_first(self, XAnnot, XImplAnnot, ConstXImplAnnot): 73 source = ''' 74 struct X { 75 virtual int foo() = 0; 76 }; 77 78 struct XImpl : public X { 79 int foo() override { 80 return 5; 81 } 82 }; 83 84 fruit::Component<ConstXImplAnnot> getXImplComponent(); 85 86 fruit::Component<> getComponent() { 87 return fruit::createComponent() 88 .install(getXImplComponent) 89 .addMultibinding<XAnnot, XImplAnnot>(); 90 } 91 ''' 92 expect_compile_error( 93 'NonConstBindingRequiredButConstBindingProvidedError<XImplAnnot>', 94 'The type T was provided as constant, however one of the constructors/providers/factories in this component', 95 COMMON_DEFINITIONS, 96 source, 97 locals()) 98 99 @parameterized.parameters([ 100 ('X', 'XImpl', 'const XImpl'), 101 ('X', 'fruit::Annotated<Annotation2, XImpl>', 'fruit::Annotated<Annotation2, const XImpl>'), 102 ]) 103 def test_add_interface_multibinding_const_target_error_binding_first(self, XAnnot, XImplAnnot, ConstXImplAnnot): 104 source = ''' 105 struct X { 106 virtual int foo() = 0; 107 }; 108 109 struct XImpl : public X { 110 int foo() override { 111 return 5; 112 } 113 }; 114 115 fruit::Component<ConstXImplAnnot> getXImplComponent(); 116 117 fruit::Component<> getComponent() { 118 return fruit::createComponent() 119 .addMultibinding<XAnnot, XImplAnnot>() 120 .install(getXImplComponent); 121 } 122 ''' 123 expect_compile_error( 124 'NonConstBindingRequiredButConstBindingProvidedError<XImplAnnot>', 125 'The type T was provided as constant, however one of the constructors/providers/factories in this component', 126 COMMON_DEFINITIONS, 127 source, 128 locals()) 129 130 @parameterized.parameters([ 131 ('X', 'int'), 132 ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation2, int>'), 133 ]) 134 def test_error_not_base(self, XAnnot, intAnnot): 135 source = ''' 136 struct X {}; 137 138 fruit::Component<> getComponent() { 139 return fruit::createComponent() 140 .addMultibinding<XAnnot, intAnnot>(); 141 } 142 ''' 143 expect_compile_error( 144 'NotABaseClassOfError<X,int>', 145 'I is not a base class of C.', 146 COMMON_DEFINITIONS, 147 source, 148 locals()) 149 150 @parameterized.parameters([ 151 ('Scaler', 'ScalerImpl'), 152 ('fruit::Annotated<Annotation1, Scaler>', 'fruit::Annotated<Annotation2, ScalerImpl>'), 153 ]) 154 def test_error_abstract_class(self, ScalerAnnot, ScalerImplAnnot): 155 source = ''' 156 struct Scaler { 157 virtual double scale(double x) = 0; 158 }; 159 160 struct ScalerImpl : public Scaler { 161 // Note: here we "forgot" to implement scale() (on purpose, for this test) so ScalerImpl is an abstract class. 162 }; 163 164 fruit::Component<> getComponent() { 165 return fruit::createComponent() 166 .addMultibinding<ScalerAnnot, ScalerImplAnnot>(); 167 } 168 ''' 169 expect_compile_error( 170 'NoBindingFoundForAbstractClassError<ScalerImplAnnot,ScalerImpl>', 171 'No explicit binding was found for T, and note that C is an abstract class', 172 COMMON_DEFINITIONS, 173 source, 174 locals()) 175 176 @parameterized.parameters([ 177 ('Scaler', 'ScalerImpl'), 178 ('fruit::Annotated<Annotation1, Scaler>', 'fruit::Annotated<Annotation2, ScalerImpl>'), 179 ]) 180 def test_error_abstract_class_clang(self, ScalerAnnot, ScalerImplAnnot): 181 if re.search('Clang', CXX_COMPILER_NAME) is None: 182 # This is Clang-only because GCC >=4.9 refuses to even mention the type C() when C is an abstract class, 183 # while Clang allows to mention the type (but of course there can be no functions with this type) 184 return 185 source = ''' 186 struct Scaler { 187 virtual double scale(double x) = 0; 188 }; 189 190 struct ScalerImpl : public Scaler { 191 INJECT(ScalerImpl()) = default; 192 193 // Note: here we "forgot" to implement scale() (on purpose, for this test) so ScalerImpl is an abstract class. 194 }; 195 196 fruit::Component<> getComponent() { 197 return fruit::createComponent() 198 .addMultibinding<ScalerAnnot, ScalerImplAnnot>(); 199 } 200 ''' 201 expect_compile_error( 202 'CannotConstructAbstractClassError<ScalerImpl>', 203 'The specified class can.t be constructed because it.s an abstract class.', 204 COMMON_DEFINITIONS, 205 source, 206 locals()) 207 208if __name__ == '__main__': 209 absltest.main() 210