diff options
author | Marco Poletti <poletti.marco@gmail.com> | 2016-10-08 18:49:04 +0100 |
---|---|---|
committer | Marco Poletti <poletti.marco@gmail.com> | 2016-10-08 18:52:56 +0100 |
commit | f9b2c6f586a84610890a1917f7c6cf84d3070271 (patch) | |
tree | fc49e5a3ef9d53ca45d8e1367b758c55bc565971 /tests/test_binding_clash.py | |
parent | 2d34eacda3bef73b75d640c712c262ddc34f5ccd (diff) | |
download | google-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-x | tests/test_binding_clash.py | 463 |
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() |