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.
15import pytest
16
17from fruit_test_common import *
18
19COMMON_DEFINITIONS = '''
20    #include "test_common.h"
21
22    struct X;
23
24    struct Annotation1 {};
25    using XAnnot1 = fruit::Annotated<Annotation1, X>;
26
27    struct Annotation2 {};
28    using XAnnot2 = fruit::Annotated<Annotation2, X>;
29    '''
30
31@pytest.mark.parametrize('XAnnot', [
32    'X',
33    'fruit::Annotated<Annotation1, X>',
34])
35def test_move(XAnnot):
36    source = '''
37        struct X {
38          using Inject = X();
39        };
40
41        fruit::Component<XAnnot> getComponent() {
42          fruit::Component<XAnnot> c = fruit::createComponent();
43          fruit::Component<XAnnot> c2 = std::move(c);
44          return fruit::Component<XAnnot>(std::move(c2));
45        }
46
47        int main() {
48          fruit::Injector<XAnnot> injector(getComponent);
49          injector.get<XAnnot>();
50        }
51        '''
52    expect_success(
53        COMMON_DEFINITIONS,
54        source,
55        locals())
56
57@pytest.mark.parametrize('XAnnot', [
58    'X',
59    'fruit::Annotated<Annotation1, X>',
60])
61def test_move_partial_component(XAnnot):
62    source = '''
63        struct X {
64          using Inject = X();
65        };
66
67        fruit::Component<XAnnot> getComponent() {
68          auto c = fruit::createComponent();
69          auto c1 = std::move(c);
70          return std::move(c1);
71        }
72
73        int main() {
74          fruit::Injector<XAnnot> injector(getComponent);
75          injector.get<XAnnot>();
76        }
77        '''
78    expect_generic_compile_error(
79        'error: use of deleted function .fruit::PartialComponent<Bindings>::PartialComponent\(fruit::PartialComponent<Bindings>&&\).'
80            + '|error: call to deleted constructor of .fruit::PartialComponent<>.'
81            # MSVC 2017
82            + '|error C2280: .fruit::PartialComponent<>::PartialComponent\(fruit::PartialComponent<> &&\).: attempting to reference a deleted function'
83            # MSVC 2015
84            + '|error C2248: .fruit::PartialComponent<>::PartialComponent.: cannot access private member declared in class .fruit::PartialComponent<>.',
85        COMMON_DEFINITIONS,
86        source,
87        locals())
88
89@pytest.mark.parametrize('XAnnot,ConstXAnnot', [
90    ('X', 'X'),
91    ('X', 'const X'),
92    ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'),
93    ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'),
94])
95def test_error_no_binding_found(XAnnot, ConstXAnnot):
96    source = '''
97        struct X {};
98
99        fruit::Component<ConstXAnnot> getComponent() {
100          return fruit::createComponent();
101        }
102        '''
103    expect_compile_error(
104        'NoBindingFoundError<XAnnot>',
105        'No explicit binding nor C::Inject definition was found for T.',
106        COMMON_DEFINITIONS,
107        source,
108        locals())
109
110@pytest.mark.parametrize('XAnnot,ConstXAnnot', [
111    ('X', 'X'),
112    ('X', 'const X'),
113    ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, X>'),
114    ('fruit::Annotated<Annotation1, X>', 'fruit::Annotated<Annotation1, const X>'),
115])
116def test_error_no_binding_found_abstract_class(XAnnot, ConstXAnnot):
117    source = '''
118        struct X {
119          virtual void f() = 0;
120        };
121
122        fruit::Component<ConstXAnnot> getComponent() {
123          return fruit::createComponent();
124        }
125        '''
126    expect_compile_error(
127        'NoBindingFoundForAbstractClassError<XAnnot,X>',
128        'No explicit binding was found for T, and note that C is an abstract class',
129        COMMON_DEFINITIONS,
130        source,
131        locals())
132
133@pytest.mark.parametrize('MaybeConst', [
134    '',
135    'const',
136])
137def test_error_no_factory_binding_found(MaybeConst):
138    source = '''
139        struct X {};
140
141        fruit::Component<MaybeConst std::function<std::unique_ptr<X>()>> getComponent() {
142          return fruit::createComponent();
143        }
144        '''
145    expect_compile_error(
146        'NoBindingFoundError<std::function<std::unique_ptr<X(,std::default_delete<X>)?>\((void)?\)>',
147        'No explicit binding nor C::Inject definition was found for T.',
148        COMMON_DEFINITIONS,
149        source,
150        locals())
151
152@pytest.mark.parametrize('MaybeConst', [
153    '',
154    'const',
155])
156def test_error_no_factory_binding_found_with_annotation(MaybeConst):
157    source = '''
158        struct X {};
159
160        fruit::Component<fruit::Annotated<Annotation1, MaybeConst std::function<std::unique_ptr<X>()>>> getComponent() {
161          return fruit::createComponent();
162        }
163        '''
164    expect_compile_error(
165        'NoBindingFoundError<fruit::Annotated<Annotation1,std::function<std::unique_ptr<X(,std::default_delete<X>)?>\((void)?\)>>',
166        'No explicit binding nor C::Inject definition was found for T.',
167        COMMON_DEFINITIONS,
168        source,
169        locals())
170
171if __name__== '__main__':
172    main(__file__)
173