aboutsummaryrefslogtreecommitdiff
path: root/tests/test_binding_clash.py
diff options
context:
space:
mode:
authorMarco Poletti <poletti.marco@gmail.com>2016-10-08 18:49:04 +0100
committerMarco Poletti <poletti.marco@gmail.com>2016-10-08 18:52:56 +0100
commitf9b2c6f586a84610890a1917f7c6cf84d3070271 (patch)
treefc49e5a3ef9d53ca45d8e1367b758c55bc565971 /tests/test_binding_clash.py
parent2d34eacda3bef73b75d640c712c262ddc34f5ccd (diff)
downloadgoogle-fruit-f9b2c6f586a84610890a1917f7c6cf84d3070271.tar.gz
Port all end-to-end C++ tests to be nose2-based python tests, so that:
* A single file can contain multiple testcases (also making it easier to share common setup between testcases). * The CMakeLists.txt file doesn't need to be updated for each test case. * It will be possible to introduce parameterized tests in the future. Running these tests under Bazel is no longer supported (support might however be re-introduced in the future).
Diffstat (limited to 'tests/test_binding_clash.py')
-rwxr-xr-xtests/test_binding_clash.py463
1 files changed, 463 insertions, 0 deletions
diff --git a/tests/test_binding_clash.py b/tests/test_binding_clash.py
new file mode 100755
index 0000000..8ac60dc
--- /dev/null
+++ b/tests/test_binding_clash.py
@@ -0,0 +1,463 @@
+#!/usr/bin/env python3
+# Copyright 2016 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS-IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from fruit_test_common import *
+
+def test_binding_and_binding():
+ expect_compile_error(
+ 'TypeAlreadyBoundError<int>',
+ 'Trying to bind C but it is already bound.',
+ '''
+Component<int> getComponent() {
+ return fruit::createComponent()
+ .registerConstructor<int()>()
+ .registerConstructor<int()>();
+}
+''')
+
+def test_binding_and_binding_with_annotation():
+ expect_compile_error(
+ 'TypeAlreadyBoundError<fruit::Annotated<Annotation,int>>',
+ 'Trying to bind C but it is already bound.',
+ '''
+struct Annotation {};
+
+using intAnnot = fruit::Annotated<Annotation, int>;
+
+Component<intAnnot> getComponent() {
+ return fruit::createComponent()
+ .registerConstructor<intAnnot()>()
+ .registerConstructor<intAnnot()>();
+}
+''')
+
+def test_binding_and_binding_with_different_annotation_ok():
+ expect_success(
+ '''
+struct Annotation1 {};
+struct Annotation2 {};
+
+using intAnnot1 = fruit::Annotated<Annotation1, int>;
+using intAnnot2 = fruit::Annotated<Annotation2, int>;
+
+Component<intAnnot1, intAnnot2> getComponent() {
+ return fruit::createComponent()
+ .registerConstructor<intAnnot1()>()
+ .registerConstructor<intAnnot2()>();
+}
+
+int main() {
+ return 0;
+}
+''')
+
+def test_binding_and_install():
+ expect_compile_error(
+ 'DuplicateTypesInComponentError<int>',
+ 'The installed component provides some types that are already provided by the current component.',
+ '''
+Component<int> getParentComponent() {
+ return fruit::createComponent()
+ .registerConstructor<int()>();
+}
+
+Component<int> getComponent() {
+ return fruit::createComponent()
+ .registerConstructor<int()>()
+ .install(getParentComponent());
+}
+''')
+
+def test_binding_and_install_with_annotation():
+ expect_compile_error(
+ 'DuplicateTypesInComponentError<fruit::Annotated<Annotation,int>>',
+ 'The installed component provides some types that are already provided by the current component.',
+ '''
+struct Annotation {};
+
+using intAnnot = fruit::Annotated<Annotation, int>;
+
+Component<intAnnot> getParentComponent() {
+ return fruit::createComponent()
+ .registerConstructor<intAnnot()>();
+}
+
+Component<intAnnot> getComponent() {
+ return fruit::createComponent()
+ .registerConstructor<intAnnot()>()
+ .install(getParentComponent());
+}
+''')
+
+def test_binding_and_install_with_different_annotation_ok():
+ expect_success(
+ '''
+struct Annotation1 {};
+struct Annotation2 {};
+
+using intAnnot1 = fruit::Annotated<Annotation1, int>;
+using intAnnot2 = fruit::Annotated<Annotation2, int>;
+
+Component<intAnnot1> getParentComponent() {
+ return fruit::createComponent()
+ .registerConstructor<intAnnot1()>();
+}
+
+Component<intAnnot1, intAnnot2> getComponent() {
+ return fruit::createComponent()
+ .registerConstructor<intAnnot2()>()
+ .install(getParentComponent());
+}
+
+int main() {
+ fruit::Injector<intAnnot1, intAnnot2> injector(getComponent());
+ int& n1 = injector.get<fruit::Annotated<Annotation1, int&>>();
+ int& n2 = injector.get<fruit::Annotated<Annotation2, int&>>();
+ Assert(&n1 != &n2);
+ return 0;
+}
+''')
+
+def test_type_already_bound_install_and_install():
+ expect_compile_error(
+ 'DuplicateTypesInComponentError<int>',
+ 'The installed component provides some types that are already provided',
+ '''
+Component<int> getParentComponent() {
+ return fruit::createComponent()
+ .registerConstructor<int()>();
+}
+
+Component<int> getComponent() {
+ return fruit::createComponent()
+ .install(getParentComponent())
+ .install(getParentComponent());
+}
+''')
+
+def test_install_and_install_with_annotation():
+ expect_compile_error(
+ 'DuplicateTypesInComponentError<fruit::Annotated<Annotation,int>>',
+ 'The installed component provides some types that are already provided',
+ '''
+struct Annotation {};
+
+using intAnnot = fruit::Annotated<Annotation, int>;
+
+Component<intAnnot> getParentComponent() {
+ return fruit::createComponent()
+ .registerConstructor<intAnnot()>();
+}
+
+Component<intAnnot> getComponent() {
+ return fruit::createComponent()
+ .install(getParentComponent())
+ .install(getParentComponent());
+}
+''')
+
+def test_install_and_install_with_different_annotation_ok():
+ expect_success(
+ '''
+struct Annotation1 {};
+struct Annotation2 {};
+
+using intAnnot1 = fruit::Annotated<Annotation1, int>;
+using intAnnot2 = fruit::Annotated<Annotation2, int>;
+
+Component<intAnnot1> getParentComponent1() {
+ return fruit::createComponent()
+ .registerConstructor<intAnnot1()>();
+}
+
+Component<intAnnot2> getParentComponent2() {
+ return fruit::createComponent()
+ .registerConstructor<intAnnot2()>();
+}
+
+Component<intAnnot1, intAnnot2> getComponent() {
+ return fruit::createComponent()
+ .install(getParentComponent1())
+ .install(getParentComponent2());
+}
+
+int main() {
+ fruit::Injector<intAnnot1, intAnnot2> injector(getComponent());
+ injector.get<intAnnot1>();
+ injector.get<intAnnot2>();
+ return 0;
+}
+''')
+
+def test_binding_and_interface_binding():
+ expect_compile_error(
+ 'TypeAlreadyBoundError<X>',
+ 'Trying to bind C but it is already bound.',
+ '''
+struct X {};
+
+struct Y : public X {};
+
+Component<Y> getComponent() {
+ return fruit::createComponent()
+ .registerConstructor<X()>()
+ .registerConstructor<Y()>()
+ .bind<X, Y>();
+}
+''')
+
+def test_interface_binding_and_binding():
+ expect_compile_error(
+ 'TypeAlreadyBoundError<X>',
+ 'Trying to bind C but it is already bound.',
+ '''
+struct X {};
+
+struct Y : public X {};
+
+Component<Y> getComponent() {
+ return fruit::createComponent()
+ .registerConstructor<Y()>()
+ .bind<X, Y>()
+ .registerConstructor<X()>();
+}
+''')
+
+def test_during_component_merge():
+ expect_compile_error(
+ 'DuplicateTypesInComponentError<int>',
+ 'The installed component provides some types that are already provided',
+ '''
+Component<int> getComponent() {
+ return fruit::createComponent()
+ .registerConstructor<int()>();
+}
+
+void f() {
+ fruit::NormalizedComponent<int> nc(getComponent());
+ fruit::Injector<int> injector(nc, getComponent());
+ (void) injector;
+}
+''')
+
+def test_during_component_merge_with_annotation():
+ expect_compile_error(
+ 'DuplicateTypesInComponentError<fruit::Annotated<Annotation,int>>',
+ 'The installed component provides some types that are already provided',
+ '''
+struct Annotation {};
+
+using intAnnot = fruit::Annotated<Annotation, int>;
+
+Component<intAnnot> getComponent() {
+ return fruit::createComponent()
+ .registerConstructor<intAnnot()>();
+}
+
+void f() {
+ fruit::NormalizedComponent<intAnnot> nc(getComponent());
+ fruit::Injector<intAnnot> injector(nc, getComponent());
+ (void) injector;
+}
+''')
+
+def test_during_component_merge_with_different_annotation_ok():
+ expect_success(
+ '''
+struct Annotation1 {};
+struct Annotation2 {};
+
+using intAnnot1 = fruit::Annotated<Annotation1, int>;
+using intAnnot2 = fruit::Annotated<Annotation2, int>;
+
+Component<intAnnot1> getComponent1() {
+ return fruit::createComponent()
+ .registerConstructor<intAnnot1()>();
+}
+
+Component<intAnnot2> getComponent2() {
+ return fruit::createComponent()
+ .registerConstructor<intAnnot2()>();
+}
+
+int main() {
+ fruit::NormalizedComponent<intAnnot1> nc(getComponent1());
+ fruit::Injector<intAnnot1, intAnnot2> injector(nc, getComponent2());
+ injector.get<intAnnot1>();
+ injector.get<intAnnot2>();
+}
+''')
+
+def test_bind_instance_and_bind_instance_runtime():
+ expect_runtime_error(
+ 'Fatal injection error: the type int was provided more than once, with different bindings.',
+ '''
+Component<int> getComponentForInstance() {
+ // Note: don't do this in real code, leaks memory.
+ Component<> comp = fruit::createComponent()
+ .bindInstance(*(new int(5)));
+ return fruit::createComponent()
+ .install(comp)
+ .bindInstance(*(new int(5)));
+}
+
+int main() {
+ Injector<int> injector(getComponentForInstance());
+ injector.get<int*>();
+ return 0;
+}
+'''
+)
+
+def test_bind_instance_and_bind_instance_annotated_runtime():
+ expect_runtime_error(
+ 'Fatal injection error: the type fruit::Annotated<Annotation, int> was provided more than once, with different bindings.',
+ '''
+struct Annotation {};
+
+using intAnnot = fruit::Annotated<Annotation, int>;
+
+Component<intAnnot> getComponentForInstance() {
+ // Note: don't do this in real code, leaks memory.
+ Component<> comp = fruit::createComponent()
+ .bindInstance<intAnnot>(*(new int(5)));
+ return fruit::createComponent()
+ .install(comp)
+ .bindInstance<intAnnot>(*(new int(5)));
+}
+
+int main() {
+ Injector<intAnnot> injector(getComponentForInstance());
+ injector.get<intAnnot>();
+ return 0;
+}
+'''
+)
+
+def test_bind_instance_and_binding_runtime():
+ expect_runtime_error(
+ 'Fatal injection error: the type int was provided more than once, with different bindings.',
+ '''
+Component<int> getComponentForInstance(int& n) {
+ Component<> comp = fruit::createComponent()
+ .bindInstance(n);
+ return fruit::createComponent()
+ .install(comp)
+ .registerConstructor<int()>();
+}
+
+int main() {
+ int n = 5;
+ Injector<int> injector(getComponentForInstance(n));
+ if (injector.get<int*>() != &n)
+ abort();
+ return 0;
+}
+''')
+
+def test_bind_instance_and_binding_annotated_runtime():
+ expect_runtime_error(
+ 'Fatal injection error: the type fruit::Annotated<Annotation, ?int> was provided more than once, with different bindings.',
+ '''
+struct Annotation {};
+
+using intAnnot = fruit::Annotated<Annotation, int>;
+
+Component<intAnnot> getComponentForInstance(int& n) {
+ Component<> comp = fruit::createComponent()
+ .bindInstance<intAnnot>(n);
+ return fruit::createComponent()
+ .install(comp)
+ .registerConstructor<intAnnot()>();
+}
+
+int main() {
+ int n = 5;
+ Injector<intAnnot> injector(getComponentForInstance(n));
+ injector.get<intAnnot>();
+ return 0;
+}
+''')
+
+def test_during_component_merge_consistent_ok():
+ expect_success(
+ '''
+struct X {
+ INJECT(X()) {
+ Assert(!constructed);
+ constructed = true;
+ }
+
+ static bool constructed;
+};
+
+bool X::constructed = false;
+
+fruit::Component<X> getComponent() {
+ return fruit::createComponent();
+}
+
+int main() {
+
+ fruit::NormalizedComponent<> normalizedComponent(getComponent());
+ Injector<X> injector(normalizedComponent, getComponent());
+
+ Assert(!X::constructed);
+ injector.get<X>();
+ Assert(X::constructed);
+
+ return 0;
+}
+''')
+
+def test_during_component_merge_consistent_with_annotation_ok():
+ expect_success(
+ '''
+struct Annotation {};
+
+struct X {
+ using Inject = X();
+ X() {
+ Assert(!constructed);
+ constructed = true;
+ }
+
+ static bool constructed;
+};
+
+using XAnnot = fruit::Annotated<Annotation, X>;
+
+bool X::constructed = false;
+
+fruit::Component<XAnnot> getComponent() {
+ return fruit::createComponent();
+}
+
+int main() {
+
+ fruit::NormalizedComponent<> normalizedComponent(getComponent());
+ Injector<XAnnot> injector(normalizedComponent, getComponent());
+
+ Assert(!X::constructed);
+ injector.get<XAnnot>();
+ Assert(X::constructed);
+
+ return 0;
+}
+''')
+
+if __name__ == '__main__':
+ import nose2
+ nose2.main()