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
22def test_component_function_success():
23    source = '''
24        struct X {
25          int n;
26          X(int n) : n(n) {}
27        };
28
29        struct Arg {
30          Arg(int) {}
31          Arg() = default;
32          Arg(const Arg&) = default;
33          Arg(Arg&&) = default;
34          Arg& operator=(const Arg&) = default;
35          Arg& operator=(Arg&&) = default;
36        };
37
38        bool operator==(const Arg&, const Arg&) {
39          return true;
40        }
41
42        namespace std {
43          template <>
44          struct hash<Arg> {
45            size_t operator()(const Arg&) {
46              return 0;
47            }
48          };
49        }
50
51        fruit::Component<X> getParentComponent(int, std::string, Arg, Arg) {
52          return fruit::createComponent()
53            .registerProvider([]() { return X(5); });
54        }
55
56        fruit::Component<X> getComponent() {
57          return fruit::createComponent()
58            .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{}, 15));
59        }
60
61        int main() {
62          fruit::Injector<X> injector(getComponent);
63          X x = injector.get<X>();
64          Assert(x.n == 5);
65        }
66        '''
67    expect_success(COMMON_DEFINITIONS, source)
68
69def test_component_function_no_args_success():
70    source = '''
71        struct X {
72          int n;
73          X(int n) : n(n) {}
74        };
75
76        fruit::Component<X> getParentComponent() {
77          return fruit::createComponent()
78            .registerProvider([]() { return X(5); });
79        }
80
81        fruit::Component<X> getComponent() {
82          return fruit::createComponent()
83            .installComponentFunctions(fruit::componentFunction(getParentComponent));
84        }
85
86        int main() {
87          fruit::Injector<X> injector(getComponent);
88          X x = injector.get<X>();
89          Assert(x.n == 5);
90        }
91        '''
92    expect_success(COMMON_DEFINITIONS, source)
93
94def test_component_function_one_arg_success():
95    source = '''
96        struct X {
97          int n;
98          X(int n) : n(n) {}
99        };
100
101        fruit::Component<X> getParentComponent(std::string) {
102          return fruit::createComponent()
103            .registerProvider([]() { return X(5); });
104        }
105
106        fruit::Component<X> getComponent() {
107          return fruit::createComponent()
108            .installComponentFunctions(fruit::componentFunction(getParentComponent, std::string("Hello")));
109        }
110
111        int main() {
112          fruit::Injector<X> injector(getComponent);
113          X x = injector.get<X>();
114          Assert(x.n == 5);
115        }
116        '''
117    expect_success(COMMON_DEFINITIONS, source)
118
119def test_component_function_error_not_move_constructible():
120    source = '''
121        struct X {};
122
123        struct Arg {
124          Arg() = default;
125          Arg(const Arg&) = default;
126          Arg(Arg&&) = delete;
127          Arg& operator=(const Arg&) = default;
128          Arg& operator=(Arg&&) = default;
129        };
130
131        bool operator==(const Arg&, const Arg&);
132
133        namespace std {
134          template <>
135          struct hash<Arg> {
136            size_t operator()(const Arg&);
137          };
138        }
139
140        fruit::Component<X> getParentComponent(int, std::string, Arg);
141
142        fruit::Component<X> getComponent() {
143          return fruit::createComponent()
144            .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{}));
145        }
146        '''
147    expect_generic_compile_error(
148        'error: use of deleted function .Arg::Arg\(Arg&&\).'
149        + '|error: call to deleted constructor of .Arg.'
150        + '|.Arg::Arg\(Arg &&\).: cannot convert argument 1 from .std::_Tuple_val<Arg>. to .const Arg &.'
151        + '|.Arg::Arg\(Arg &&\).: attempting to reference a deleted function',
152        COMMON_DEFINITIONS,
153        source)
154
155def test_component_function_error_not_move_constructible_with_conversion():
156    source = '''
157        struct X {};
158
159        struct Arg {
160          Arg(int) {}
161          Arg() = default;
162          Arg(const Arg&) = default;
163          Arg(Arg&&) = delete;
164          Arg& operator=(const Arg&) = default;
165          Arg& operator=(Arg&&) = default;
166        };
167
168        bool operator==(const Arg&, const Arg&);
169
170        namespace std {
171          template <>
172          struct hash<Arg> {
173            size_t operator()(const Arg&);
174          };
175        }
176
177        fruit::Component<X> getParentComponent(int, std::string, Arg);
178
179        fruit::Component<X> getComponent() {
180          return fruit::createComponent()
181            .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), 15));
182        }
183        '''
184    expect_generic_compile_error(
185        'error: use of deleted function .Arg::Arg\(Arg&&\).'
186        + '|error: call to deleted constructor of .Arg.'
187        + '|.Arg::Arg\(Arg &&\).: cannot convert argument 1 from .std::_Tuple_val<Arg>. to .int.'
188        + '|error: copying parameter of type .Arg. invokes deleted constructor',
189        COMMON_DEFINITIONS,
190        source)
191
192def test_component_function_error_not_copy_constructible():
193    source = '''
194        struct X {
195          int n;
196          X(int n) : n(n) {}
197        };
198
199        struct Arg {
200          Arg() = default;
201          Arg(const Arg&) = delete;
202          Arg(Arg&&) = default;
203          Arg& operator=(const Arg&) = default;
204          Arg& operator=(Arg&&) = default;
205        };
206
207        bool operator==(const Arg&, const Arg&);
208
209        namespace std {
210          template <>
211          struct hash<Arg> {
212            size_t operator()(const Arg&);
213          };
214        }
215
216        fruit::Component<X> getParentComponent(int, std::string, Arg);
217
218        fruit::Component<X> getComponent() {
219          return fruit::createComponent()
220            .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{}));
221        }
222        '''
223    expect_generic_compile_error(
224        'error: use of deleted function .Arg::Arg\(const Arg&\).'
225        + '|error: call to deleted constructor of .Arg.'
226        + '|error C2280: .Arg::Arg\(const Arg &\).: attempting to reference a deleted function'
227        # This is the error printed by MSVC. It's not great but I couldn't find a way to have it print
228        # a more useful error.
229        + '|cannot convert argument 1 from .int. to .std::allocator_arg_t.',
230        COMMON_DEFINITIONS,
231        source)
232
233def test_component_function_error_not_copy_constructible_with_conversion():
234    source = '''
235        struct X {
236          int n;
237          X(int n) : n(n) {}
238        };
239
240        struct Arg {
241          Arg(int) {}
242          Arg() = default;
243          Arg(const Arg&) = delete;
244          Arg(Arg&&) = default;
245          Arg& operator=(const Arg&) = default;
246          Arg& operator=(Arg&&) = default;
247        };
248
249        bool operator==(const Arg&, const Arg&);
250
251        namespace std {
252          template <>
253          struct hash<Arg> {
254            size_t operator()(const Arg&);
255          };
256        }
257
258        fruit::Component<X> getParentComponent(int, std::string, Arg);
259
260        fruit::Component<X> getComponent() {
261          return fruit::createComponent()
262            .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), 15));
263        }
264        '''
265    expect_generic_compile_error(
266        'error: use of deleted function .Arg::Arg\(const Arg&\).'
267        + '|error: call to deleted constructor of .Arg.'
268        + '|error C2280: .Arg::Arg\(const Arg &\).: attempting to reference a deleted function'
269        # This is the error printed by MSVC. It's not great but I couldn't find a way to have it print
270        # a more useful error.
271        + '|cannot convert argument 1 from .int. to .std::allocator_arg_t.',
272        COMMON_DEFINITIONS,
273        source)
274
275def test_component_function_error_not_move_assignable():
276    source = '''
277        struct X {};
278
279        struct Arg {
280          Arg() = default;
281          Arg(const Arg&) = default;
282          Arg(Arg&&) = default;
283          Arg& operator=(const Arg&) = default;
284          Arg& operator=(Arg&&) = delete;
285        };
286
287        bool operator==(const Arg&, const Arg&);
288
289        namespace std {
290          template <>
291          struct hash<Arg> {
292            size_t operator()(const Arg&);
293          };
294        }
295
296        fruit::Component<X> getParentComponent(int, std::string, Arg);
297
298        fruit::Component<X> getComponent() {
299          return fruit::createComponent()
300            .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{}));
301        }
302        '''
303    expect_generic_compile_error(
304        'error: use of deleted function .Arg& Arg::operator=\(Arg&&\).'
305        + '|error: overload resolution selected deleted operator .=.'
306        + '|error C2280: .Arg &Arg::operator =\(Arg &&\).: attempting to reference a deleted function',
307        COMMON_DEFINITIONS,
308        source)
309
310def test_component_function_error_not_move_assignable_with_conversion():
311    source = '''
312        struct X {};
313
314        struct Arg {
315          Arg(int) {}
316          Arg() = default;
317          Arg(const Arg&) = default;
318          Arg(Arg&&) = default;
319          Arg& operator=(const Arg&) = default;
320          Arg& operator=(Arg&&) = delete;
321        };
322
323        bool operator==(const Arg&, const Arg&);
324
325        namespace std {
326          template <>
327          struct hash<Arg> {
328            size_t operator()(const Arg&);
329          };
330        }
331
332        fruit::Component<X> getParentComponent(int, std::string, Arg);
333
334        fruit::Component<X> getComponent() {
335          return fruit::createComponent()
336            .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), 15));
337        }
338        '''
339    expect_generic_compile_error(
340        'error: use of deleted function .Arg& Arg::operator=\(Arg&&\).'
341        + '|error: overload resolution selected deleted operator .=.'
342        + '|error C2280: .Arg &Arg::operator =\(Arg &&\).: attempting to reference a deleted function',
343        COMMON_DEFINITIONS,
344        source)
345
346def test_component_function_error_not_copy_assignable():
347    source = '''
348        struct X {
349          int n;
350          X(int n) : n(n) {}
351        };
352
353        struct Arg {
354          Arg() = default;
355          Arg(const Arg&) = default;
356          Arg(Arg&&) = default;
357          Arg& operator=(const Arg&) = delete;
358          Arg& operator=(Arg&&) = default;
359        };
360
361        bool operator==(const Arg&, const Arg&);
362
363        namespace std {
364          template <>
365          struct hash<Arg> {
366            size_t operator()(const Arg&);
367          };
368        }
369
370        fruit::Component<X> getParentComponent(int, std::string, Arg);
371
372        fruit::Component<X> getComponent() {
373          return fruit::createComponent()
374            .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{}));
375        }
376        '''
377    expect_generic_compile_error(
378        'error: use of deleted function .Arg& Arg::operator=\(const Arg&\).'
379        + '|error: overload resolution selected deleted operator .=.'
380        + '|error C2280: .Arg &Arg::operator =\(const Arg &\).: attempting to reference a deleted function',
381        COMMON_DEFINITIONS,
382        source)
383
384def test_component_function_error_not_copy_assignable_with_conversion():
385    source = '''
386        struct X {
387          int n;
388          X(int n) : n(n) {}
389        };
390
391        struct Arg {
392          Arg(int) {}
393          Arg() = default;
394          Arg(const Arg&) = default;
395          Arg(Arg&&) = default;
396          Arg& operator=(const Arg&) = delete;
397          Arg& operator=(Arg&&) = default;
398        };
399
400        bool operator==(const Arg&, const Arg&);
401
402        namespace std {
403          template <>
404          struct hash<Arg> {
405            size_t operator()(const Arg&);
406          };
407        }
408
409        fruit::Component<X> getParentComponent(int, std::string, Arg);
410
411        fruit::Component<X> getComponent() {
412          return fruit::createComponent()
413            .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), 15));
414        }
415        '''
416    expect_generic_compile_error(
417        'error: use of deleted function .Arg& Arg::operator=\(const Arg&\).'
418        + '|error: overload resolution selected deleted operator .=.'
419        + '|error C2280: .Arg &Arg::operator =\(const Arg &\).: attempting to reference a deleted function',
420        COMMON_DEFINITIONS,
421        source)
422
423def test_component_function_error_not_equality_comparable():
424    source = '''
425        struct X {
426          int n;
427          X(int n) : n(n) {}
428        };
429
430        struct Arg {
431          Arg() = default;
432          Arg(const Arg&) = default;
433          Arg(Arg&&) = default;
434          Arg& operator=(const Arg&) = default;
435          Arg& operator=(Arg&&) = default;
436        };
437
438        namespace std {
439          template <>
440          struct hash<Arg> {
441            size_t operator()(const Arg&);
442          };
443        }
444
445        fruit::Component<X> getParentComponent(int, std::string, Arg);
446
447        fruit::Component<X> getComponent() {
448          return fruit::createComponent()
449            .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{}));
450        }
451        '''
452    expect_generic_compile_error(
453        'error: no match for .operator==. \(operand types are .const Arg. and .const Arg.\)'
454        + '|error: invalid operands to binary expression \(.const Arg. and .const Arg.\)'
455        + '|error C2676: binary .==.: .const Arg. does not define this operator',
456        COMMON_DEFINITIONS,
457        source)
458
459def test_component_function_error_not_equality_comparable_with_conversion():
460    source = '''
461        struct X {
462          int n;
463          X(int n) : n(n) {}
464        };
465
466        struct Arg {
467          Arg(int) {}
468          Arg() = default;
469          Arg(const Arg&) = default;
470          Arg(Arg&&) = default;
471          Arg& operator=(const Arg&) = default;
472          Arg& operator=(Arg&&) = default;
473        };
474
475        namespace std {
476          template <>
477          struct hash<Arg> {
478            size_t operator()(const Arg&);
479          };
480        }
481
482        fruit::Component<X> getParentComponent(int, std::string, Arg);
483
484        fruit::Component<X> getComponent() {
485          return fruit::createComponent()
486            .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), 15));
487        }
488        '''
489    expect_generic_compile_error(
490        'error: no match for .operator==. \(operand types are .const Arg. and .const Arg.\)'
491        + '|error: invalid operands to binary expression \(.const Arg. and .const Arg.\)'
492        + '|error C2676: binary .==.: .const Arg. does not define this operator',
493        COMMON_DEFINITIONS,
494        source)
495
496def test_component_function_error_not_hashable():
497    source = '''
498        struct X {};
499
500        struct Arg {
501          Arg() = default;
502          Arg(const Arg&) = default;
503          Arg(Arg&&) = default;
504          Arg& operator=(const Arg&) = default;
505          Arg& operator=(Arg&&) = default;
506        };
507
508        bool operator==(const Arg&, const Arg&);
509
510        fruit::Component<X> getParentComponent(int, std::string, Arg);
511
512        fruit::Component<X> getComponent() {
513          return fruit::createComponent()
514            .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{}));
515        }
516        '''
517    expect_generic_compile_error(
518        'error: use of deleted function .std::hash<Arg>::hash\(\).'
519        + '|error: call to implicitly-deleted default constructor of .std::hash<Arg>.'
520        + '|error: invalid use of incomplete type .struct std::hash<Arg>.'
521        + '|error: implicit instantiation of undefined template .std::(__1::)?hash<Arg>.'
522        + '|error C2338: The C\+\+ Standard doesn.t provide a hash for this type.'
523        + '|error C2064: term does not evaluate to a function taking 1 arguments',
524        COMMON_DEFINITIONS,
525        source)
526
527def test_component_function_error_not_hashable_with_conversion():
528    source = '''
529        struct X {};
530
531        struct Arg {
532          Arg(int) {}
533          Arg() = default;
534          Arg(const Arg&) = default;
535          Arg(Arg&&) = default;
536          Arg& operator=(const Arg&) = default;
537          Arg& operator=(Arg&&) = default;
538        };
539
540        bool operator==(const Arg&, const Arg&);
541
542        fruit::Component<X> getParentComponent(int, std::string, Arg);
543
544        fruit::Component<X> getComponent() {
545          return fruit::createComponent()
546            .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), 15));
547        }
548        '''
549    expect_generic_compile_error(
550        'error: use of deleted function .std::hash<Arg>::hash\(\).'
551        + '|error: call to implicitly-deleted default constructor of .std::hash<Arg>.'
552        + '|error: invalid use of incomplete type .struct std::hash<Arg>.'
553        + '|error: implicit instantiation of undefined template .std::(__1::)?hash<Arg>.'
554        + '|error C2338: The C\+\+ Standard doesn.t provide a hash for this type.'
555        + '|error C2064: term does not evaluate to a function taking 1 arguments',
556        COMMON_DEFINITIONS,
557        source)
558
559if __name__== '__main__':
560    main(__file__)
561