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 fruit_test_common import *
17
18COMMON_DEFINITIONS = '''
19    #include "test_common.h"
20
21    struct X;
22
23    struct Annotation1 {};
24    using XAnnot1 = fruit::Annotated<Annotation1, X>;
25    '''
26
27def test_install_component_functions_deduped_against_previous_install_no_args():
28    source = '''
29        int num_executions = 0;
30
31        fruit::Component<int> getChildComponent() {
32          static int n = 5;
33          ++num_executions;
34          return fruit::createComponent()
35              .bindInstance(n);
36        }
37
38        fruit::Component<> getMiddleComponent() {
39          return fruit::createComponent()
40              .install(getChildComponent);
41        }
42
43        fruit::Component<int> getMainComponent() {
44          return fruit::createComponent()
45              .install(getMiddleComponent)
46              .installComponentFunctions(fruit::componentFunction(getChildComponent));
47        }
48
49        int main() {
50          fruit::Injector<int> injector(getMainComponent);
51          int n = injector.get<int>();
52          Assert(n == 5);
53          Assert(num_executions == 1);
54        }
55        '''
56    expect_success(
57        COMMON_DEFINITIONS,
58        source,
59        locals())
60
61def test_install_component_functions_deduped_against_following_install_no_args():
62    source = '''
63        int num_executions = 0;
64
65        fruit::Component<int> getChildComponent() {
66          static int n = 5;
67          ++num_executions;
68          return fruit::createComponent()
69              .bindInstance(n);
70        }
71
72        fruit::Component<> getMiddleComponent() {
73          return fruit::createComponent()
74              .installComponentFunctions(fruit::componentFunction(getChildComponent));
75        }
76
77        fruit::Component<int> getMainComponent() {
78          return fruit::createComponent()
79              .install(getMiddleComponent)
80              .install(getChildComponent);
81        }
82
83        int main() {
84          fruit::Injector<int> injector(getMainComponent);
85          int n = injector.get<int>();
86          Assert(n == 5);
87          Assert(num_executions == 1);
88        }
89        '''
90    expect_success(
91        COMMON_DEFINITIONS,
92        source,
93        locals())
94
95def test_install_component_functions_deduped_against_previous_install_with_args():
96    source = '''
97        int num_executions = 0;
98
99        fruit::Component<int> getChildComponent(int) {
100          static int n = 5;
101          ++num_executions;
102          return fruit::createComponent()
103              .bindInstance(n);
104        }
105
106        fruit::Component<> getMiddleComponent() {
107          return fruit::createComponent()
108              .install(getChildComponent, 42);
109        }
110
111        fruit::Component<int> getMainComponent() {
112          return fruit::createComponent()
113              .install(getMiddleComponent)
114              .installComponentFunctions(fruit::componentFunction(getChildComponent, 42));
115        }
116
117        int main() {
118          fruit::Injector<int> injector(getMainComponent);
119          int n = injector.get<int>();
120          Assert(n == 5);
121          Assert(num_executions == 1);
122        }
123        '''
124    expect_success(
125        COMMON_DEFINITIONS,
126        source,
127        locals())
128
129def test_install_component_functions_deduped_against_following_install_with_args():
130    source = '''
131        int num_executions = 0;
132
133        fruit::Component<int> getChildComponent(int) {
134          static int n = 5;
135          ++num_executions;
136          return fruit::createComponent()
137              .bindInstance(n);
138        }
139
140        fruit::Component<> getMiddleComponent() {
141          return fruit::createComponent()
142              .installComponentFunctions(fruit::componentFunction(getChildComponent, 42));
143        }
144
145        fruit::Component<int> getMainComponent() {
146          return fruit::createComponent()
147              .install(getMiddleComponent)
148              .install(getChildComponent, 42);
149        }
150
151        int main() {
152          fruit::Injector<int> injector(getMainComponent);
153          int n = injector.get<int>();
154          Assert(n == 5);
155          Assert(num_executions == 1);
156        }
157        '''
158    expect_success(
159        COMMON_DEFINITIONS,
160        source,
161        locals())
162
163def test_install_component_functions_same_as_with_previous_install_with_different_args():
164    source = '''
165        int num_executions = 0;
166
167        fruit::Component<int> getChildComponent(int) {
168          static int n = 5;
169          ++num_executions;
170          return fruit::createComponent()
171              .bindInstance(n);
172        }
173
174        fruit::Component<> getMiddleComponent() {
175          return fruit::createComponent()
176              .install(getChildComponent, 42);
177        }
178
179        fruit::Component<int> getMainComponent() {
180          return fruit::createComponent()
181              .install(getMiddleComponent)
182              .installComponentFunctions(fruit::componentFunction(getChildComponent, 2));
183        }
184
185        int main() {
186          fruit::Injector<int> injector(getMainComponent);
187          int n = injector.get<int>();
188          Assert(n == 5);
189          Assert(num_executions == 2);
190        }
191        '''
192    expect_success(
193        COMMON_DEFINITIONS,
194        source,
195        locals())
196
197def test_install_component_functions_same_as_following_install_with_different_args():
198    source = '''
199        int num_executions = 0;
200
201        fruit::Component<int> getChildComponent(int) {
202          static int n = 5;
203          ++num_executions;
204          return fruit::createComponent()
205              .bindInstance(n);
206        }
207
208        fruit::Component<> getMiddleComponent() {
209          return fruit::createComponent()
210              .installComponentFunctions(fruit::componentFunction(getChildComponent, 42));
211        }
212
213        fruit::Component<int> getMainComponent() {
214          return fruit::createComponent()
215              .install(getMiddleComponent)
216              .install(getChildComponent, 2);
217        }
218
219        int main() {
220          fruit::Injector<int> injector(getMainComponent);
221          (void)injector;
222          Assert(num_executions == 2);
223        }
224        '''
225    expect_success(
226        COMMON_DEFINITIONS,
227        source,
228        locals())
229
230def test_install_component_functions_no_component_functions():
231    source = '''
232        fruit::Component<> getComponent() {
233          return fruit::createComponent()
234            .installComponentFunctions();
235        }
236
237        int main() {
238          fruit::Injector<> injector(getComponent);
239          (void)injector;
240        }
241        '''
242    expect_success(COMMON_DEFINITIONS, source)
243
244def test_install_component_functions_one_component_function():
245    source = '''
246        struct X {
247          int n;
248          X(int n) : n(n) {}
249        };
250
251        fruit::Component<X> getParentComponent(std::string) {
252          return fruit::createComponent()
253            .registerProvider([]() { return X(5); });
254        }
255
256        fruit::Component<X> getComponent() {
257          return fruit::createComponent()
258            .installComponentFunctions(fruit::componentFunction(getParentComponent, std::string("Hello")));
259        }
260
261        int main() {
262          fruit::Injector<X> injector(getComponent);
263          X x = injector.get<X>();
264          Assert(x.n == 5);
265        }
266        '''
267    expect_success(COMMON_DEFINITIONS, source)
268
269def test_install_component_functions_two_component_functions():
270    source = '''
271        struct X {
272          int n;
273          X(int n) : n(n) {}
274        };
275
276        struct Y {
277          int n;
278          Y(int n) : n(n) {}
279        };
280
281        fruit::Component<X> getParentComponent1(std::string) {
282          return fruit::createComponent()
283            .registerProvider([]() { return X(5); });
284        }
285
286        fruit::Component<Y> getParentComponent2(std::string) {
287          return fruit::createComponent()
288              .registerProvider([]() { return Y(42); });
289        }
290
291        fruit::Component<X, Y> getComponent() {
292          return fruit::createComponent()
293              .installComponentFunctions(
294                  fruit::componentFunction(getParentComponent1, std::string("Hello")),
295                  fruit::componentFunction(getParentComponent2, std::string("World")));
296        }
297
298        int main() {
299          fruit::Injector<X, Y> injector(getComponent);
300          X x = injector.get<X>();
301          Y y = injector.get<Y>();
302          Assert(x.n == 5);
303          Assert(y.n == 42);
304        }
305        '''
306    expect_success(COMMON_DEFINITIONS, source)
307
308def test_install_component_functions_with_template_parameter_pack_unpacking():
309    source = '''
310        template <typename T>
311        struct GetComponentHolder;
312
313        struct X {
314          int n;
315          X(int n) : n(n) {}
316        };
317
318        struct Y {
319          int n;
320          Y(int n) : n(n) {}
321        };
322
323        template <>
324        struct GetComponentHolder<X> {
325            static fruit::Component<X> getComponent(std::string) {
326              return fruit::createComponent()
327                .registerProvider([]() { return X(5); });
328            }
329        };
330
331        template <>
332        struct GetComponentHolder<Y> {
333            static fruit::Component<Y> getComponent(std::string) {
334              return fruit::createComponent()
335                  .registerProvider([]() { return Y(42); });
336            }
337        };
338
339        template <typename... Ts>
340        fruit::Component<Ts...> getComponent() {
341          return fruit::createComponent()
342              .installComponentFunctions(
343                  fruit::componentFunction(GetComponentHolder<Ts>::getComponent, std::string("Hello"))...);
344        }
345
346        int main() {
347          fruit::Injector<X, Y> injector(getComponent<X, Y>);
348          X x = injector.get<X>();
349          Y y = injector.get<Y>();
350          Assert(x.n == 5);
351          Assert(y.n == 42);
352        }
353        '''
354    expect_success(COMMON_DEFINITIONS, source)
355
356def test_install_component_functions_wrong_argument_type():
357    source = '''
358        fruit::Component<> getMainComponent() {
359          return fruit::createComponent()
360              .installComponentFunctions(42);
361        }
362        '''
363    expect_compile_error(
364        'IncorrectArgTypePassedToInstallComponentFuntionsError<int>',
365        'All arguments passed to installComponentFunctions.. must be fruit::ComponentFunction<...> objects but an '
366        'argument with type Arg was passed instead.',
367        COMMON_DEFINITIONS,
368        source,
369        locals())
370
371if __name__== '__main__':
372    main(__file__)
373