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