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