diff options
author | Marco Poletti <poletti.marco@gmail.com> | 2018-08-18 21:49:27 +0100 |
---|---|---|
committer | Marco Poletti <poletti.marco@gmail.com> | 2018-08-18 21:49:27 +0100 |
commit | 3c9c517cd469d8e3caf1f27b581432fbeccdd0bf (patch) | |
tree | 0546930b051050bee28471e5eef598f065bd4887 /tests | |
parent | 45abc5865c967100e72e603102ceb6393a7530ea (diff) | |
download | google-fruit-3c9c517cd469d8e3caf1f27b581432fbeccdd0bf.tar.gz |
Add a PartialComponent::installComponentFunctions() method that allows to install a variable number of components (typically by expanding a template parameter pack).
Diffstat (limited to 'tests')
-rwxr-xr-x | tests/test_component_functions.py | 552 | ||||
-rwxr-xr-x | tests/test_component_replacement.py | 71 | ||||
-rwxr-xr-x | tests/test_install_component_functions.py | 357 |
3 files changed, 980 insertions, 0 deletions
diff --git a/tests/test_component_functions.py b/tests/test_component_functions.py new file mode 100755 index 0000000..88a9cbc --- /dev/null +++ b/tests/test_component_functions.py @@ -0,0 +1,552 @@ +#!/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 * + +COMMON_DEFINITIONS = ''' + #include "test_common.h" + ''' + +def test_component_function_success(): + source = ''' + struct X { + int n; + X(int n) : n(n) {} + }; + + struct Arg { + Arg(int) {} + Arg() = default; + Arg(const Arg&) = default; + Arg(Arg&&) = default; + Arg& operator=(const Arg&) = default; + Arg& operator=(Arg&&) = default; + }; + + bool operator==(const Arg&, const Arg&) { + return true; + } + + namespace std { + template <> + struct hash<Arg> { + size_t operator()(const Arg&) { + return 0; + } + }; + } + + fruit::Component<X> getParentComponent(int, std::string, Arg, Arg) { + return fruit::createComponent() + .registerProvider([]() { return X(5); }); + } + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{}, 15)); + } + + int main() { + fruit::Injector<X> injector(getComponent); + X x = injector.get<X>(); + Assert(x.n == 5); + } + ''' + expect_success(COMMON_DEFINITIONS, source) + +def test_component_function_no_args_success(): + source = ''' + struct X { + int n; + X(int n) : n(n) {} + }; + + fruit::Component<X> getParentComponent() { + return fruit::createComponent() + .registerProvider([]() { return X(5); }); + } + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent)); + } + + int main() { + fruit::Injector<X> injector(getComponent); + X x = injector.get<X>(); + Assert(x.n == 5); + } + ''' + expect_success(COMMON_DEFINITIONS, source) + +def test_component_function_one_arg_success(): + source = ''' + struct X { + int n; + X(int n) : n(n) {} + }; + + fruit::Component<X> getParentComponent(std::string) { + return fruit::createComponent() + .registerProvider([]() { return X(5); }); + } + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, std::string("Hello"))); + } + + int main() { + fruit::Injector<X> injector(getComponent); + X x = injector.get<X>(); + Assert(x.n == 5); + } + ''' + expect_success(COMMON_DEFINITIONS, source) + +def test_component_function_error_not_move_constructible(): + source = ''' + struct X {}; + + struct Arg { + Arg() = default; + Arg(const Arg&) = default; + Arg(Arg&&) = delete; + Arg& operator=(const Arg&) = default; + Arg& operator=(Arg&&) = default; + }; + + bool operator==(const Arg&, const Arg&); + + namespace std { + template <> + struct hash<Arg> { + size_t operator()(const Arg&); + }; + } + + fruit::Component<X> getParentComponent(int, std::string, Arg); + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{})); + } + ''' + expect_generic_compile_error( + 'error: use of deleted function .Arg::Arg\(Arg&&\).' + + '|error: call to deleted constructor of .Arg.' + + '|.Arg::Arg\(Arg &&\).: cannot convert argument 1 from .std::_Tuple_val<_This>. to .const Arg &.', + COMMON_DEFINITIONS, + source) + +def test_component_function_error_not_move_constructible_with_conversion(): + source = ''' + struct X {}; + + struct Arg { + Arg(int) {} + Arg() = default; + Arg(const Arg&) = default; + Arg(Arg&&) = delete; + Arg& operator=(const Arg&) = default; + Arg& operator=(Arg&&) = default; + }; + + bool operator==(const Arg&, const Arg&); + + namespace std { + template <> + struct hash<Arg> { + size_t operator()(const Arg&); + }; + } + + fruit::Component<X> getParentComponent(int, std::string, Arg); + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), 15)); + } + ''' + expect_generic_compile_error( + 'error: use of deleted function .Arg::Arg\(Arg&&\).' + + '|error: call to deleted constructor of .Arg.' + + '|.Arg::Arg\(Arg &&\).: cannot convert argument 1 from .std::_Tuple_val<_This>. to .int.', + COMMON_DEFINITIONS, + source) + +def test_component_function_error_not_copy_constructible(): + source = ''' + struct X { + int n; + X(int n) : n(n) {} + }; + + struct Arg { + Arg() = default; + Arg(const Arg&) = delete; + Arg(Arg&&) = default; + Arg& operator=(const Arg&) = default; + Arg& operator=(Arg&&) = default; + }; + + bool operator==(const Arg&, const Arg&); + + namespace std { + template <> + struct hash<Arg> { + size_t operator()(const Arg&); + }; + } + + fruit::Component<X> getParentComponent(int, std::string, Arg); + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{})); + } + ''' + expect_generic_compile_error( + 'error: use of deleted function .Arg::Arg\(const Arg&\).' + + '|error: call to deleted constructor of .Arg.' + + '|error C2280: .Arg::Arg\(const Arg &\).: attempting to reference a deleted function', + COMMON_DEFINITIONS, + source) + +def test_component_function_error_not_copy_constructible_with_conversion(): + source = ''' + struct X { + int n; + X(int n) : n(n) {} + }; + + struct Arg { + Arg(int) {} + Arg() = default; + Arg(const Arg&) = delete; + Arg(Arg&&) = default; + Arg& operator=(const Arg&) = default; + Arg& operator=(Arg&&) = default; + }; + + bool operator==(const Arg&, const Arg&); + + namespace std { + template <> + struct hash<Arg> { + size_t operator()(const Arg&); + }; + } + + fruit::Component<X> getParentComponent(int, std::string, Arg); + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), 15)); + } + ''' + expect_generic_compile_error( + 'error: use of deleted function .Arg::Arg\(const Arg&\).' + + '|error: call to deleted constructor of .Arg.' + + '|error C2280: .Arg::Arg\(const Arg &\).: attempting to reference a deleted function', + COMMON_DEFINITIONS, + source) + +def test_component_function_error_not_move_assignable(): + source = ''' + struct X {}; + + struct Arg { + Arg() = default; + Arg(const Arg&) = default; + Arg(Arg&&) = default; + Arg& operator=(const Arg&) = default; + Arg& operator=(Arg&&) = delete; + }; + + bool operator==(const Arg&, const Arg&); + + namespace std { + template <> + struct hash<Arg> { + size_t operator()(const Arg&); + }; + } + + fruit::Component<X> getParentComponent(int, std::string, Arg); + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{})); + } + ''' + expect_generic_compile_error( + 'error: use of deleted function .Arg& Arg::operator=\(Arg&&\).' + + '|error: overload resolution selected deleted operator .=.' + + '|error C2280: .Arg &Arg::operator =\(Arg &&\).: attempting to reference a deleted function', + COMMON_DEFINITIONS, + source) + +def test_component_function_error_not_move_assignable_with_conversion(): + source = ''' + struct X {}; + + struct Arg { + Arg(int) {} + Arg() = default; + Arg(const Arg&) = default; + Arg(Arg&&) = default; + Arg& operator=(const Arg&) = default; + Arg& operator=(Arg&&) = delete; + }; + + bool operator==(const Arg&, const Arg&); + + namespace std { + template <> + struct hash<Arg> { + size_t operator()(const Arg&); + }; + } + + fruit::Component<X> getParentComponent(int, std::string, Arg); + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), 15)); + } + ''' + expect_generic_compile_error( + 'error: use of deleted function .Arg& Arg::operator=\(Arg&&\).' + + '|error: overload resolution selected deleted operator .=.' + + '|error C2280: .Arg &Arg::operator =\(Arg &&\).: attempting to reference a deleted function', + COMMON_DEFINITIONS, + source) + +def test_component_function_error_not_copy_assignable(): + source = ''' + struct X { + int n; + X(int n) : n(n) {} + }; + + struct Arg { + Arg() = default; + Arg(const Arg&) = default; + Arg(Arg&&) = default; + Arg& operator=(const Arg&) = delete; + Arg& operator=(Arg&&) = default; + }; + + bool operator==(const Arg&, const Arg&); + + namespace std { + template <> + struct hash<Arg> { + size_t operator()(const Arg&); + }; + } + + fruit::Component<X> getParentComponent(int, std::string, Arg); + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{})); + } + ''' + expect_generic_compile_error( + 'error: use of deleted function .Arg& Arg::operator=\(const Arg&\).' + + '|error: overload resolution selected deleted operator .=.' + + '|error C2280: .Arg &Arg::operator =\(const Arg &\).: attempting to reference a deleted function', + COMMON_DEFINITIONS, + source) + +def test_component_function_error_not_copy_assignable_with_conversion(): + source = ''' + struct X { + int n; + X(int n) : n(n) {} + }; + + struct Arg { + Arg(int) {} + Arg() = default; + Arg(const Arg&) = default; + Arg(Arg&&) = default; + Arg& operator=(const Arg&) = delete; + Arg& operator=(Arg&&) = default; + }; + + bool operator==(const Arg&, const Arg&); + + namespace std { + template <> + struct hash<Arg> { + size_t operator()(const Arg&); + }; + } + + fruit::Component<X> getParentComponent(int, std::string, Arg); + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), 15)); + } + ''' + expect_generic_compile_error( + 'error: use of deleted function .Arg& Arg::operator=\(const Arg&\).' + + '|error: overload resolution selected deleted operator .=.' + + '|error C2280: .Arg &Arg::operator =\(const Arg &\).: attempting to reference a deleted function', + COMMON_DEFINITIONS, + source) + +def test_component_function_error_not_equality_comparable(): + source = ''' + struct X { + int n; + X(int n) : n(n) {} + }; + + struct Arg { + Arg() = default; + Arg(const Arg&) = default; + Arg(Arg&&) = default; + Arg& operator=(const Arg&) = default; + Arg& operator=(Arg&&) = default; + }; + + namespace std { + template <> + struct hash<Arg> { + size_t operator()(const Arg&); + }; + } + + fruit::Component<X> getParentComponent(int, std::string, Arg); + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{})); + } + ''' + expect_generic_compile_error( + 'error: no match for .operator==. \(operand types are .const Arg. and .const Arg.\)' + + '|error: invalid operands to binary expression \(.const Arg. and .const Arg.\)' + + '|error C2676: binary .==.: .const Arg. does not define this operator', + COMMON_DEFINITIONS, + source) + +def test_component_function_error_not_equality_comparable_with_conversion(): + source = ''' + struct X { + int n; + X(int n) : n(n) {} + }; + + struct Arg { + Arg(int) {} + Arg() = default; + Arg(const Arg&) = default; + Arg(Arg&&) = default; + Arg& operator=(const Arg&) = default; + Arg& operator=(Arg&&) = default; + }; + + namespace std { + template <> + struct hash<Arg> { + size_t operator()(const Arg&); + }; + } + + fruit::Component<X> getParentComponent(int, std::string, Arg); + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), 15)); + } + ''' + expect_generic_compile_error( + 'error: no match for .operator==. \(operand types are .const Arg. and .const Arg.\)' + + '|error: invalid operands to binary expression \(.const Arg. and .const Arg.\)' + + '|error C2676: binary .==.: .const Arg. does not define this operator', + COMMON_DEFINITIONS, + source) + +def test_component_function_error_not_hashable(): + source = ''' + struct X {}; + + struct Arg { + Arg() = default; + Arg(const Arg&) = default; + Arg(Arg&&) = default; + Arg& operator=(const Arg&) = default; + Arg& operator=(Arg&&) = default; + }; + + bool operator==(const Arg&, const Arg&); + + fruit::Component<X> getParentComponent(int, std::string, Arg); + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), Arg{})); + } + ''' + expect_generic_compile_error( + 'error: use of deleted function .std::hash<Arg>::hash\(\).' + + '|error: call to implicitly-deleted default constructor of .std::hash<Arg>.' + + '|error: invalid use of incomplete type .struct std::hash<Arg>.' + + '|error: implicit instantiation of undefined template .std::(__1::)?hash<Arg>.' + + '|error C2338: The C\+\+ Standard doesn.t provide a hash for this type.' + + '|error C2064: term does not evaluate to a function taking 1 arguments', + COMMON_DEFINITIONS, + source) + +def test_component_function_error_not_hashable_with_conversion(): + source = ''' + struct X {}; + + struct Arg { + Arg(int) {} + Arg() = default; + Arg(const Arg&) = default; + Arg(Arg&&) = default; + Arg& operator=(const Arg&) = default; + Arg& operator=(Arg&&) = default; + }; + + bool operator==(const Arg&, const Arg&); + + fruit::Component<X> getParentComponent(int, std::string, Arg); + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, 5, std::string("Hello"), 15)); + } + ''' + expect_generic_compile_error( + 'error: use of deleted function .std::hash<Arg>::hash\(\).' + + '|error: call to implicitly-deleted default constructor of .std::hash<Arg>.' + + '|error: invalid use of incomplete type .struct std::hash<Arg>.' + + '|error: implicit instantiation of undefined template .std::(__1::)?hash<Arg>.' + + '|error C2338: The C\+\+ Standard doesn.t provide a hash for this type.' + + '|error C2064: term does not evaluate to a function taking 1 arguments', + COMMON_DEFINITIONS, + source) + +if __name__== '__main__': + main(__file__) diff --git a/tests/test_component_replacement.py b/tests/test_component_replacement.py index f2f3e57..46c52a7 100755 --- a/tests/test_component_replacement.py +++ b/tests/test_component_replacement.py @@ -106,6 +106,46 @@ def test_replace_component_success_across_normalized_component( source, locals()) +@pytest.mark.parametrize('ReplacedComponentParamTypes,ReplacedComponentInstallation', [ + ('', 'getReplacedComponent'), + ('double', 'getReplacedComponent, 1.0'), +]) +@pytest.mark.parametrize('ReplacementComponentParamTypes,ReplacementComponentInstallation', [ + ('', 'getReplacementComponent'), + ('std::string', 'getReplacementComponent, std::string("Hello, world")'), +]) +def test_replace_component_installed_using_component_function_success( + ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): + source = ''' + fruit::Component<int> getReplacedComponent(ReplacedComponentParamTypes) { + static int n = 10; + return fruit::createComponent() + .bindInstance(n); + } + + fruit::Component<int> getReplacementComponent(ReplacementComponentParamTypes) { + static int n = 20; + return fruit::createComponent() + .bindInstance(n); + } + + fruit::Component<int> getRootComponent() { + return fruit::createComponent() + .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) + .installComponentFunctions(fruit::componentFunction(ReplacedComponentInstallation)); + } + + int main() { + fruit::Injector<int> injector(getRootComponent); + int n = injector.get<int>(); + Assert(n == 20); + } + ''' + expect_success( + COMMON_DEFINITIONS, + source, + locals()) + def test_replace_component_success_with_conversion(): source = ''' fruit::Component<int> getReplacedComponent(std::string) { @@ -137,6 +177,37 @@ def test_replace_component_success_with_conversion(): source, locals()) +def test_replace_component_installed_using_component_function_success_with_conversion(): + source = ''' + fruit::Component<int> getReplacedComponent(std::string) { + static int n = 10; + return fruit::createComponent() + .bindInstance(n); + } + + fruit::Component<int> getReplacementComponent(double, std::string, int) { + static int n = 20; + return fruit::createComponent() + .bindInstance(n); + } + + fruit::Component<int> getRootComponent() { + return fruit::createComponent() + .replace(getReplacedComponent, "Hi").with(getReplacementComponent, 2.0, "Hello", 12) + .installComponentFunctions(fruit::componentFunction(getReplacedComponent, "Hi")); + } + + int main() { + fruit::Injector<int> injector(getRootComponent); + int n = injector.get<int>(); + Assert(n == 20); + } + ''' + expect_success( + COMMON_DEFINITIONS, + source, + locals()) + @pytest.mark.parametrize('ComponentParamTypes,ReplacedComponentInstallation,ReplacementComponentInstallation,ReplacementReplacementComponentInstallation', [ ('', 'getReplacedComponent', 'getReplacementComponent', 'getReplacementReplacementComponent'), ('double', 'getReplacedComponent, 1.0', 'getReplacementComponent, 1.0', 'getReplacementReplacementComponent, 1.0'), diff --git a/tests/test_install_component_functions.py b/tests/test_install_component_functions.py new file mode 100755 index 0000000..ff3931e --- /dev/null +++ b/tests/test_install_component_functions.py @@ -0,0 +1,357 @@ +#!/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 * + +COMMON_DEFINITIONS = ''' + #include "test_common.h" + + struct X; + + struct Annotation1 {}; + using XAnnot1 = fruit::Annotated<Annotation1, X>; + ''' + +def test_install_component_functions_deduped_against_previous_install_no_args(): + source = ''' + int num_executions = 0; + + fruit::Component<int> getChildComponent() { + static int n = 5; + ++num_executions; + return fruit::createComponent() + .bindInstance(n); + } + + fruit::Component<> getMiddleComponent() { + return fruit::createComponent() + .install(getChildComponent); + } + + fruit::Component<int> getMainComponent() { + return fruit::createComponent() + .install(getMiddleComponent) + .installComponentFunctions(fruit::componentFunction(getChildComponent)); + } + + int main() { + fruit::Injector<int> injector(getMainComponent); + int n = injector.get<int>(); + Assert(n == 5); + Assert(num_executions == 1); + } + ''' + expect_success( + COMMON_DEFINITIONS, + source, + locals()) + +def test_install_component_functions_deduped_against_following_install_no_args(): + source = ''' + int num_executions = 0; + + fruit::Component<int> getChildComponent() { + static int n = 5; + ++num_executions; + return fruit::createComponent() + .bindInstance(n); + } + + fruit::Component<> getMiddleComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getChildComponent)); + } + + fruit::Component<int> getMainComponent() { + return fruit::createComponent() + .install(getMiddleComponent) + .install(getChildComponent); + } + + int main() { + fruit::Injector<int> injector(getMainComponent); + int n = injector.get<int>(); + Assert(n == 5); + Assert(num_executions == 1); + } + ''' + expect_success( + COMMON_DEFINITIONS, + source, + locals()) + +def test_install_component_functions_deduped_against_previous_install_with_args(): + source = ''' + int num_executions = 0; + + fruit::Component<int> getChildComponent(int) { + static int n = 5; + ++num_executions; + return fruit::createComponent() + .bindInstance(n); + } + + fruit::Component<> getMiddleComponent() { + return fruit::createComponent() + .install(getChildComponent, 42); + } + + fruit::Component<int> getMainComponent() { + return fruit::createComponent() + .install(getMiddleComponent) + .installComponentFunctions(fruit::componentFunction(getChildComponent, 42)); + } + + int main() { + fruit::Injector<int> injector(getMainComponent); + int n = injector.get<int>(); + Assert(n == 5); + Assert(num_executions == 1); + } + ''' + expect_success( + COMMON_DEFINITIONS, + source, + locals()) + +def test_install_component_functions_deduped_against_following_install_with_args(): + source = ''' + int num_executions = 0; + + fruit::Component<int> getChildComponent(int) { + static int n = 5; + ++num_executions; + return fruit::createComponent() + .bindInstance(n); + } + + fruit::Component<> getMiddleComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getChildComponent, 42)); + } + + fruit::Component<int> getMainComponent() { + return fruit::createComponent() + .install(getMiddleComponent) + .install(getChildComponent, 42); + } + + int main() { + fruit::Injector<int> injector(getMainComponent); + int n = injector.get<int>(); + Assert(n == 5); + Assert(num_executions == 1); + } + ''' + expect_success( + COMMON_DEFINITIONS, + source, + locals()) + +def test_install_component_functions_same_as_with_previous_install_with_different_args(): + source = ''' + int num_executions = 0; + + fruit::Component<int> getChildComponent(int) { + static int n = 5; + ++num_executions; + return fruit::createComponent() + .bindInstance(n); + } + + fruit::Component<> getMiddleComponent() { + return fruit::createComponent() + .install(getChildComponent, 42); + } + + fruit::Component<int> getMainComponent() { + return fruit::createComponent() + .install(getMiddleComponent) + .installComponentFunctions(fruit::componentFunction(getChildComponent, 2)); + } + + int main() { + fruit::Injector<int> injector(getMainComponent); + int n = injector.get<int>(); + Assert(n == 5); + Assert(num_executions == 2); + } + ''' + expect_success( + COMMON_DEFINITIONS, + source, + locals()) + +def test_install_component_functions_same_as_following_install_with_different_args(): + source = ''' + int num_executions = 0; + + fruit::Component<int> getChildComponent(int) { + static int n = 5; + ++num_executions; + return fruit::createComponent() + .bindInstance(n); + } + + fruit::Component<> getMiddleComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getChildComponent, 42)); + } + + fruit::Component<int> getMainComponent() { + return fruit::createComponent() + .install(getMiddleComponent) + .install(getChildComponent, 2); + } + + int main() { + fruit::Injector<int> injector(getMainComponent); + (void)injector; + Assert(num_executions == 2); + } + ''' + expect_success( + COMMON_DEFINITIONS, + source, + locals()) + +def test_install_component_functions_no_component_functions(): + source = ''' + fruit::Component<> getComponent() { + return fruit::createComponent() + .installComponentFunctions(); + } + + int main() { + fruit::Injector<> injector(getComponent); + (void)injector; + } + ''' + expect_success(COMMON_DEFINITIONS, source) + +def test_install_component_functions_one_component_function(): + source = ''' + struct X { + int n; + X(int n) : n(n) {} + }; + + fruit::Component<X> getParentComponent(std::string) { + return fruit::createComponent() + .registerProvider([]() { return X(5); }); + } + + fruit::Component<X> getComponent() { + return fruit::createComponent() + .installComponentFunctions(fruit::componentFunction(getParentComponent, std::string("Hello"))); + } + + int main() { + fruit::Injector<X> injector(getComponent); + X x = injector.get<X>(); + Assert(x.n == 5); + } + ''' + expect_success(COMMON_DEFINITIONS, source) + +def test_install_component_functions_two_component_functions(): + source = ''' + struct X { + int n; + X(int n) : n(n) {} + }; + + struct Y { + int n; + Y(int n) : n(n) {} + }; + + fruit::Component<X> getParentComponent1(std::string) { + return fruit::createComponent() + .registerProvider([]() { return X(5); }); + } + + fruit::Component<Y> getParentComponent2(std::string) { + return fruit::createComponent() + .registerProvider([]() { return Y(42); }); + } + + fruit::Component<X, Y> getComponent() { + return fruit::createComponent() + .installComponentFunctions( + fruit::componentFunction(getParentComponent1, std::string("Hello")), + fruit::componentFunction(getParentComponent2, std::string("World"))); + } + + int main() { + fruit::Injector<X, Y> injector(getComponent); + X x = injector.get<X>(); + Y y = injector.get<Y>(); + Assert(x.n == 5); + Assert(y.n == 42); + } + ''' + expect_success(COMMON_DEFINITIONS, source) + +def test_install_component_functions_with_template_parameter_pack_unpacking(): + source = ''' + template <typename T> + struct GetComponentHolder; + + struct X { + int n; + X(int n) : n(n) {} + }; + + struct Y { + int n; + Y(int n) : n(n) {} + }; + + template <> + struct GetComponentHolder<X> { + static fruit::Component<X> getComponent(std::string) { + return fruit::createComponent() + .registerProvider([]() { return X(5); }); + } + }; + + template <> + struct GetComponentHolder<Y> { + static fruit::Component<Y> getComponent(std::string) { + return fruit::createComponent() + .registerProvider([]() { return Y(42); }); + } + }; + + template <typename... Ts> + fruit::Component<Ts...> getComponent() { + return fruit::createComponent() + .installComponentFunctions( + fruit::componentFunction(GetComponentHolder<Ts>::getComponent, std::string("Hello"))...); + } + + int main() { + fruit::Injector<X, Y> injector(getComponent<X, Y>); + X x = injector.get<X>(); + Y y = injector.get<Y>(); + Assert(x.n == 5); + Assert(y.n == 42); + } + ''' + expect_success(COMMON_DEFINITIONS, source) + +if __name__== '__main__': + main(__file__) |