xref: /aosp_15_r20/external/google-fruit/tests/test_multibindings_bind_interface.py (revision a65addddcf69f38db5b288d787b6b7571a57bb8f)
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