• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 absl.testing import parameterized
17from fruit_test_common import *
18
19COMMON_DEFINITIONS = '''
20    #include "test_common.h"
21
22    struct Listener;
23
24    struct X {};
25
26    struct Annotation {};
27    struct Annotation1 {};
28    using ListenerAnnot = fruit::Annotated<Annotation, Listener>;
29    '''
30
31class TestMultibindingsMisc(parameterized.TestCase):
32    def test_get_none(self):
33        source = '''
34            fruit::Component<> getComponent() {
35              return fruit::createComponent();
36            }
37
38            int main() {
39              fruit::Injector<> injector(getComponent);
40
41              std::vector<X*> multibindings = injector.getMultibindings<X>();
42              (void) multibindings;
43              Assert(multibindings.empty());
44            }
45            '''
46        expect_success(
47            COMMON_DEFINITIONS,
48            source)
49
50    def test_multiple_various_kinds(self):
51        source = '''
52            static int numNotificationsToListener1 = 0;
53            static int numNotificationsToListener2 = 0;
54            static int numNotificationsToListener3 = 0;
55
56            struct Listener {
57            public:
58              virtual ~Listener() = default;
59
60              virtual void notify() = 0;
61            };
62
63            struct Listener1 : public Listener {
64            public:
65              INJECT(Listener1()) = default;
66
67              virtual ~Listener1() = default;
68
69              void notify() override {
70                ++numNotificationsToListener1;
71              }
72            };
73
74            struct Writer {
75            public:
76              virtual void write(std::string s) = 0;
77            };
78
79            struct StdoutWriter : public Writer {
80            public:
81              INJECT(StdoutWriter()) = default;
82
83              void write(std::string s) override {
84                std::cout << s << std::endl;
85              }
86            };
87
88            struct Listener2 : public Listener {
89            private:
90              Writer* writer;
91
92            public:
93              INJECT(Listener2(Writer* writer))
94                : writer(writer) {
95              }
96
97              virtual ~Listener2() = default;
98
99              void notify() override {
100                (void) writer;
101                ++numNotificationsToListener2;
102              }
103            };
104
105            struct Listener3 : public Listener {
106            private:
107              Writer* writer;
108
109            public:
110              INJECT(Listener3(Writer* writer))
111                : writer(writer) {
112              }
113
114              virtual ~Listener3() = default;
115
116              void notify() override {
117                (void) writer;
118                ++numNotificationsToListener3;
119              }
120            };
121
122            fruit::Component<> getListenersComponent() {
123              return fruit::createComponent()
124                .bind<Writer, StdoutWriter>()
125                // Note: this is just to exercise the other method, but in real code you should split this in
126                // an addMultibinding<Listener, Listener1> and a registerProvider with the lambda.
127                .addMultibindingProvider([]() {
128                  Listener1* listener1 = new Listener1();
129                  return static_cast<Listener*>(listener1);
130                })
131                .addMultibinding<Listener, Listener2>()
132                .addMultibinding<ListenerAnnot, Listener3>();
133            }
134
135            int main() {
136              fruit::Injector<> injector(getListenersComponent);
137              std::vector<Listener*> listeners = injector.getMultibindings<Listener>();
138              for (Listener* listener : listeners) {
139                listener->notify();
140              }
141
142              std::vector<Listener*> listeners2 = injector.getMultibindings<Listener>();
143              Assert(listeners == listeners2);
144
145              if (numNotificationsToListener1 != 1 || numNotificationsToListener2 != 1
146                || numNotificationsToListener3 != 0) {
147                abort();
148              }
149
150              std::vector<Listener*> listenersWithAnnotation = injector.getMultibindings<ListenerAnnot>();
151              for (Listener* listener : listenersWithAnnotation) {
152                listener->notify();
153              }
154
155              if (numNotificationsToListener1 != 1 || numNotificationsToListener2 != 1
156                || numNotificationsToListener3 != 1) {
157                abort();
158              }
159            }
160            '''
161        expect_success(
162            COMMON_DEFINITIONS,
163            source)
164
165    def test_order(self):
166        source = '''
167            std::vector<int> numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
168            // *
169            // |-- 0
170            // |-- A
171            // |   |-- 1
172            // |   |-- B
173            // |   |   |-- 2
174            // |   |   `-- 3
175            // |   |-- 4
176            // |   |-- C
177            // |   |   |-- 5
178            // |   |   |-- 6
179            // |   |   |-- D
180            // |   |   |   |-- 7
181            // |   |   |   |-- E
182            // |   |   |   |   |-- 8
183            // |   |   |   |   `-- 9
184            // |   |   |   `-- 10
185            // |   |   |-- 11
186            // |   |   |-- F
187            // |   |   |   |-- 12
188            // |   |   |   `-- 13
189            // |   |   `-- 14
190            // |   |-- 15
191            // |   |-- C (won't be expanded)
192            // |   `-- 16
193            // |-- 17
194            // |-- C (won't be expanded)
195            // `-- 18
196
197            fruit::Component<> getRootComponent();
198            fruit::Component<> getComponentA();
199            fruit::Component<> getComponentB();
200            fruit::Component<> getComponentC();
201            fruit::Component<> getComponentD();
202            fruit::Component<> getComponentE();
203            fruit::Component<> getComponentF();
204
205            fruit::Component<> getRootComponent() {
206              return fruit::createComponent()
207                .addInstanceMultibinding(numbers[0])
208                .install(getComponentA)
209                .addInstanceMultibinding(numbers[17])
210                .install(getComponentC)
211                .addInstanceMultibinding(numbers[18]);
212            }
213
214            fruit::Component<> getComponentA() {
215              return fruit::createComponent()
216                .addInstanceMultibinding(numbers[1])
217                .install(getComponentB)
218                .addInstanceMultibinding(numbers[4])
219                .install(getComponentC)
220                .addInstanceMultibinding(numbers[15])
221                .install(getComponentC)
222                .addInstanceMultibinding(numbers[16]);
223            }
224
225            fruit::Component<> getComponentB() {
226              return fruit::createComponent()
227                .addInstanceMultibinding(numbers[2])
228                .addInstanceMultibinding(numbers[3]);
229            }
230
231            fruit::Component<> getComponentC() {
232              return fruit::createComponent()
233                .addInstanceMultibinding(numbers[5])
234                .addInstanceMultibinding(numbers[6])
235                .install(getComponentD)
236                .addInstanceMultibinding(numbers[11])
237                .install(getComponentF)
238                .addInstanceMultibinding(numbers[14]);
239            }
240
241            fruit::Component<> getComponentD() {
242              return fruit::createComponent()
243                .addInstanceMultibinding(numbers[7])
244                .install(getComponentE)
245                .addInstanceMultibinding(numbers[10]);
246            }
247
248            fruit::Component<> getComponentE() {
249              return fruit::createComponent()
250                .addInstanceMultibinding(numbers[8])
251                .addInstanceMultibinding(numbers[9]);
252            }
253
254            fruit::Component<> getComponentF() {
255              return fruit::createComponent()
256                .addInstanceMultibinding(numbers[12])
257                .addInstanceMultibinding(numbers[13]);
258            }
259
260            int main() {
261              fruit::Injector<> injector(getRootComponent);
262              std::vector<int*> result_ptrs = injector.getMultibindings<int>();
263              std::vector<int> results;
264              std::cout << "Results: ";
265              for (int* result : result_ptrs) {
266                std::cout << *result << ", ";
267                results.push_back(*result);
268              }
269              std::cout << std::endl;
270              Assert(results == numbers);
271            }
272            '''
273        expect_success(
274            COMMON_DEFINITIONS,
275            source)
276
277
278    def test_order_with_normalized_component(self):
279        source = '''
280            std::vector<int> numbers = {
281                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
282                19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37};
283            // root1
284            // |-- 0
285            // |-- A
286            // |   |-- 1
287            // |   |-- B
288            // |   |   |-- 2
289            // |   |   `-- 3
290            // |   |-- 4
291            // |   |-- C
292            // |   |   |-- 5
293            // |   |   |-- 6
294            // |   |   |-- D
295            // |   |   |   |-- 7
296            // |   |   |   |-- E
297            // |   |   |   |   |-- 8
298            // |   |   |   |   `-- 9
299            // |   |   |   `-- 10
300            // |   |   |-- 11
301            // |   |   |-- F
302            // |   |   |   |-- 12
303            // |   |   |   `-- 13
304            // |   |   `-- 14
305            // |   |-- 15
306            // |   |-- C (won't be expanded)
307            // |   `-- 16
308            // |-- 17
309            // |-- C (won't be expanded)
310            // `-- 18
311
312            // root2
313            // |-- 19
314            // |-- A2
315            // |   |-- 20
316            // |   |-- B2
317            // |   |   |-- 21
318            // |   |   `-- 22
319            // |   |-- 23
320            // |   |-- C2
321            // |   |   |-- 24
322            // |   |   |-- 25
323            // |   |   |-- D2
324            // |   |   |   |-- 26
325            // |   |   |   |-- E2
326            // |   |   |   |   |-- 27
327            // |   |   |   |   `-- 28
328            // |   |   |   `-- 29
329            // |   |   |-- 30
330            // |   |   |-- F2
331            // |   |   |   |-- 31
332            // |   |   |   `-- 32
333            // |   |   `-- 33
334            // |   |-- 34
335            // |   |-- C2 (won't be expanded)
336            // |   `-- 35
337            // |-- 36
338            // |-- C2 (won't be expanded)
339            // `-- 37
340
341            fruit::Component<> getRootComponent();
342            fruit::Component<> getComponentA();
343            fruit::Component<> getComponentB();
344            fruit::Component<> getComponentC();
345            fruit::Component<> getComponentD();
346            fruit::Component<> getComponentE();
347            fruit::Component<> getComponentF();
348
349            fruit::Component<> getRootComponent2();
350            fruit::Component<> getComponentA2();
351            fruit::Component<> getComponentB2();
352            fruit::Component<> getComponentC2();
353            fruit::Component<> getComponentD2();
354            fruit::Component<> getComponentE2();
355            fruit::Component<> getComponentF2();
356
357            fruit::Component<> getRootComponent() {
358              return fruit::createComponent()
359                .addInstanceMultibinding(numbers[0])
360                .install(getComponentA)
361                .addInstanceMultibinding(numbers[17])
362                .install(getComponentC)
363                .addInstanceMultibinding(numbers[18]);
364            }
365
366            fruit::Component<> getComponentA() {
367              return fruit::createComponent()
368                .addInstanceMultibinding(numbers[1])
369                .install(getComponentB)
370                .addInstanceMultibinding(numbers[4])
371                .install(getComponentC)
372                .addInstanceMultibinding(numbers[15])
373                .install(getComponentC)
374                .addInstanceMultibinding(numbers[16]);
375            }
376
377            fruit::Component<> getComponentB() {
378              return fruit::createComponent()
379                .addInstanceMultibinding(numbers[2])
380                .addInstanceMultibinding(numbers[3]);
381            }
382
383            fruit::Component<> getComponentC() {
384              return fruit::createComponent()
385                .addInstanceMultibinding(numbers[5])
386                .addInstanceMultibinding(numbers[6])
387                .install(getComponentD)
388                .addInstanceMultibinding(numbers[11])
389                .install(getComponentF)
390                .addInstanceMultibinding(numbers[14]);
391            }
392
393            fruit::Component<> getComponentD() {
394              return fruit::createComponent()
395                .addInstanceMultibinding(numbers[7])
396                .install(getComponentE)
397                .addInstanceMultibinding(numbers[10]);
398            }
399
400            fruit::Component<> getComponentE() {
401              return fruit::createComponent()
402                .addInstanceMultibinding(numbers[8])
403                .addInstanceMultibinding(numbers[9]);
404            }
405
406            fruit::Component<> getComponentF() {
407              return fruit::createComponent()
408                .addInstanceMultibinding(numbers[12])
409                .addInstanceMultibinding(numbers[13]);
410            }
411
412            fruit::Component<> getRootComponent2() {
413              return fruit::createComponent()
414                .addInstanceMultibinding(numbers[19])
415                .install(getComponentA2)
416                .addInstanceMultibinding(numbers[36])
417                .install(getComponentC2)
418                .addInstanceMultibinding(numbers[37]);
419            }
420
421            fruit::Component<> getComponentA2() {
422              return fruit::createComponent()
423                .addInstanceMultibinding(numbers[20])
424                .install(getComponentB2)
425                .addInstanceMultibinding(numbers[23])
426                .install(getComponentC2)
427                .addInstanceMultibinding(numbers[34])
428                .install(getComponentC2)
429                .addInstanceMultibinding(numbers[35]);
430            }
431
432            fruit::Component<> getComponentB2() {
433              return fruit::createComponent()
434                .addInstanceMultibinding(numbers[21])
435                .addInstanceMultibinding(numbers[22]);
436            }
437
438            fruit::Component<> getComponentC2() {
439              return fruit::createComponent()
440                .addInstanceMultibinding(numbers[24])
441                .addInstanceMultibinding(numbers[25])
442                .install(getComponentD2)
443                .addInstanceMultibinding(numbers[30])
444                .install(getComponentF2)
445                .addInstanceMultibinding(numbers[33]);
446            }
447
448            fruit::Component<> getComponentD2() {
449              return fruit::createComponent()
450                .addInstanceMultibinding(numbers[26])
451                .install(getComponentE2)
452                .addInstanceMultibinding(numbers[29]);
453            }
454
455            fruit::Component<> getComponentE2() {
456              return fruit::createComponent()
457                .addInstanceMultibinding(numbers[27])
458                .addInstanceMultibinding(numbers[28]);
459            }
460
461            fruit::Component<> getComponentF2() {
462              return fruit::createComponent()
463                .addInstanceMultibinding(numbers[31])
464                .addInstanceMultibinding(numbers[32]);
465            }
466
467            int main() {
468              fruit::NormalizedComponent<> normalizedComponent(getRootComponent);
469              fruit::Injector<> injector(normalizedComponent, getRootComponent2);
470              std::vector<int*> result_ptrs = injector.getMultibindings<int>();
471              std::vector<int> results;
472              std::cout << "Results: ";
473              for (int* result : result_ptrs) {
474                std::cout << *result << ", ";
475                results.push_back(*result);
476              }
477              std::cout << std::endl;
478              Assert(results == numbers);
479            }
480            '''
481        expect_success(
482            COMMON_DEFINITIONS,
483            source)
484
485    def test_with_normalized_component_lazy_components_not_deduped_across(self):
486        source = '''
487            std::vector<int> numbers = {0, 1, 2, 3, 4};
488
489            // *
490            // |-- 0
491            // |-- A (lazy)
492            // |   |-- 1
493            // |   `-- 2
494            // |-- 3
495            // |-- A (lazy, won't be expanded)
496            // `-- 4
497
498            fruit::Component<> getRootComponent();
499            fruit::Component<> getComponentA();
500
501            fruit::Component<> getRootComponent() {
502              return fruit::createComponent()
503                .addInstanceMultibinding(numbers[0])
504                .install(getComponentA)
505                .addInstanceMultibinding(numbers[3])
506                .install(getComponentA)
507                .addInstanceMultibinding(numbers[4]);
508            }
509
510            fruit::Component<> getComponentA() {
511              return fruit::createComponent()
512                .addInstanceMultibinding(numbers[1])
513                .addInstanceMultibinding(numbers[2]);
514            }
515
516            int main() {
517              fruit::NormalizedComponent<> normalizedComponent(getRootComponent);
518              fruit::Injector<> injector(normalizedComponent, getRootComponent);
519              std::vector<int*> result_ptrs = injector.getMultibindings<int>();
520              std::vector<int> results;
521              std::cout << "Results: ";
522              for (int* result : result_ptrs) {
523                std::cout << *result << ", ";
524                results.push_back(*result);
525              }
526              std::cout << std::endl;
527              std::vector<int> expected_numbers = {0, 1, 2, 3, 4};
528              Assert(results == expected_numbers);
529            }
530            '''
531        expect_success(
532            COMMON_DEFINITIONS,
533            source)
534
535    @parameterized.parameters([
536        ('const X', r'const X'),
537        ('X*', r'X\*'),
538        ('const X*', r'const X\*'),
539        ('std::shared_ptr<X>', r'std::shared_ptr<X>'),
540        ('fruit::Annotated<Annotation1, const X>', r'const X'),
541        ('fruit::Annotated<Annotation1, X*>', r'X\*'),
542        ('fruit::Annotated<Annotation1, const X*>', r'const X\*'),
543        ('fruit::Annotated<Annotation1, std::shared_ptr<X>>', r'std::shared_ptr<X>'),
544    ])
545    def test_multibindings_get_error_non_class_type(self, XVariantAnnot, XVariantRegexp):
546        source = '''
547            void f(fruit::Injector<> injector) {
548              injector.getMultibindings<XVariantAnnot>();
549            }
550            '''
551        expect_compile_error(
552            'NonClassTypeError<XVariantRegexp,X>',
553            'A non-class type T was specified. Use C instead.',
554            COMMON_DEFINITIONS,
555            source,
556            locals())
557
558    @parameterized.parameters([
559        ('X&', 'X&'),
560        ('const X&', 'const X&'),
561        ('fruit::Annotated<Annotation1, X&>', 'X&'),
562        ('fruit::Annotated<Annotation1, const X&>', 'const X&'),
563    ])
564    def test_multibindings_get_error_reference_type(self, XVariantAnnot, XVariantRegexp):
565        source = '''
566            void f(fruit::Injector<> injector) {
567              injector.getMultibindings<XVariantAnnot>();
568            }
569            '''
570        expect_generic_compile_error(
571            'declared as a pointer to a reference of type'
572            '|forming pointer to reference type'
573            '|fruit::Injector<.*>::getMultibindings.: no matching overloaded function found',
574            COMMON_DEFINITIONS,
575            source,
576            locals())
577
578if __name__ == '__main__':
579    absltest.main()
580