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    template <typename T>
23    class V {};
24
25    template <typename T>
26    class X {
27    private:
28      X() {}
29
30    public:
31      INJECT(X(ASSISTED(int))) {
32      }
33    };
34
35    using XFactory = std::function<X<V<float>>(int)>;
36    '''
37
38class TestMisc(parameterized.TestCase):
39
40    def test_misc(self):
41        source = '''
42            fruit::Component<X<V<float>>> getXProvider2() {
43              return fruit::createComponent()
44                  .registerProvider([](){return X<V<float>>(1);});
45            }
46
47            struct AssistedMultiparamExample {
48              INJECT(AssistedMultiparamExample(ASSISTED(std::map<int, float>))) {}
49            };
50
51            struct Implementation1 {
52              bool constructed = true;
53
54              Implementation1(V<int>&&, XFactory) {
55                std::cout << "Called Implementation1() for object " << this << std::endl;
56              }
57
58              Implementation1() = delete;
59              Implementation1(const Implementation1&) = delete;
60
61              Implementation1& operator=(const Implementation1&) = delete;
62              Implementation1& operator=(Implementation1&&) = delete;
63
64              Implementation1(Implementation1&&) {
65                std::cout << "Moving an Implementation1 into object" << this << std::endl;
66              }
67
68              ~Implementation1() {
69                std::cout << "Called ~Implementation1() for object " << this << std::endl;
70                constructed = 0;
71              }
72
73              int x;
74            };
75
76            struct Interface2 {
77              virtual void f() = 0;
78            };
79
80            struct Implementation2 : public Interface2 {
81              INJECT(Implementation2(std::function<Implementation1(int)>)) {
82                std::cout << "Called Implementation2()" << std::endl;
83              }
84
85              virtual ~Implementation2() {}
86
87              virtual void f() {};
88            };
89
90            fruit::Component<Interface2, XFactory, std::function<Implementation1(int)>> getParentComponent() {
91              return fruit::createComponent()
92                  .registerFactory<Implementation1(fruit::Assisted<int>, XFactory)>(
93                    [](int, XFactory xFactory) {
94                      return Implementation1(V<int>(), xFactory);
95                    })
96                  .bind<Interface2, Implementation2>();
97            }
98
99            //*************************************
100
101            struct Interface3 {
102              virtual void f() = 0;
103            };
104
105            struct Implementation3 : public Interface3 {
106              INJECT(Implementation3(Implementation2*, fruit::Provider<Implementation2> provider)) {
107                (void) provider.get();
108                std::cout << "Called Implementation2()" << std::endl;
109              }
110
111              virtual ~Implementation3() {}
112
113              virtual void f() {};
114            };
115
116            fruit::Component<Interface3, std::function<Implementation1(int)>> getMyComponent() {
117              return fruit::createComponent()
118                  // Must fail at runtime.
119                  // .install(getXProvider2)
120                  .bind<Interface3, Implementation3>()
121                  .install(getParentComponent);
122            }
123
124            fruit::Component<std::function<AssistedMultiparamExample(std::map<int, float>)>> getAssistedMultiparamExampleComponent() {
125              return fruit::createComponent();
126            }
127
128            int main() {
129              fruit::Injector<
130                Interface3,
131                // XFactory,
132                std::function<Implementation1(int)>
133                > oldInjector(getMyComponent);
134
135              // The move is completely unnecessary, it's just to check that it works.
136              fruit::Injector<
137                Interface3,
138                // XFactory,
139                std::function<Implementation1(int)>
140                > injector(std::move(oldInjector));
141
142              std::cout << "Constructing an Interface3" << std::endl;
143              Interface3* interface3(injector);
144              std::cout << std::endl;
145              (void) interface3;
146
147              std::cout << "Constructing another Interface3" << std::endl;
148              Interface3* interface3_obj2 = injector.get<Interface3*>();
149              std::cout << std::endl;
150              (void) interface3_obj2;
151
152              std::function<Implementation1(int)> implementation1Factory(injector);
153              {
154                 std::cout << "Constructing another Implementation1" << std::endl;
155                 Implementation1 implementation1 = implementation1Factory(12);
156                 (void) implementation1;
157              }
158              std::cout << "Destroying injector" << std::endl;
159
160              fruit::Injector<std::function<AssistedMultiparamExample(std::map<int, float>)>> assistedMultiparamExampleInjector(
161                getAssistedMultiparamExampleComponent);
162
163              return 0;
164            }
165            '''
166        expect_success(
167            COMMON_DEFINITIONS,
168            source,
169            locals())
170
171if __name__ == '__main__':
172    absltest.main()
173