#!/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. import pytest from fruit_test_common import * COMMON_DEFINITIONS = ''' #include "test_common.h" ''' @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_success( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): source = ''' fruit::Component getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .bindInstance(n); } fruit::Component getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .bindInstance(n); } fruit::Component getRootComponent() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) .install(ReplacedComponentInstallation); } int main() { fruit::Injector injector(getRootComponent); int n = injector.get(); Assert(n == 20); } ''' expect_success( COMMON_DEFINITIONS, 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_success_across_normalized_component( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): source = ''' fruit::Component getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .bindInstance(n); } fruit::Component getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .bindInstance(n); } fruit::Component<> getRootComponent1() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation); } fruit::Component getRootComponent2() { return fruit::createComponent() .install(ReplacedComponentInstallation); } int main() { fruit::NormalizedComponent<> normalizedComponent(getRootComponent1); fruit::Injector injector(normalizedComponent, getRootComponent2); int n = injector.get(); Assert(n == 20); } ''' expect_success( COMMON_DEFINITIONS, source, locals()) def test_replace_component_success_with_conversion(): source = ''' fruit::Component getReplacedComponent(std::string) { static int n = 10; return fruit::createComponent() .bindInstance(n); } fruit::Component getReplacementComponent(double, std::string, int) { static int n = 20; return fruit::createComponent() .bindInstance(n); } fruit::Component getRootComponent() { return fruit::createComponent() .replace(getReplacedComponent, "Hi").with(getReplacementComponent, 2.0, "Hello", 12) .install(getReplacedComponent, "Hi"); } int main() { fruit::Injector injector(getRootComponent); int n = injector.get(); 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'), ]) def test_replace_component_chain_success( ComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentInstallation, ReplacementReplacementComponentInstallation): source = ''' fruit::Component getReplacedComponent(ComponentParamTypes) { static int n = 10; return fruit::createComponent() .bindInstance(n); } fruit::Component getReplacementComponent(ComponentParamTypes) { static int n = 20; return fruit::createComponent() .bindInstance(n); } fruit::Component getReplacementReplacementComponent(ComponentParamTypes) { static int n = 30; return fruit::createComponent() .bindInstance(n); } fruit::Component getRootComponent() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) .replace(ReplacementComponentInstallation).with(ReplacementReplacementComponentInstallation) .install(ReplacedComponentInstallation); } int main() { fruit::Injector injector(getRootComponent); int n = injector.get(); Assert(n == 30); } ''' 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'), ]) def test_replace_component_chain_other_order_success( ComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentInstallation, ReplacementReplacementComponentInstallation): source = ''' fruit::Component getReplacedComponent(ComponentParamTypes) { static int n = 10; return fruit::createComponent() .bindInstance(n); } fruit::Component getReplacementComponent(ComponentParamTypes) { static int n = 20; return fruit::createComponent() .bindInstance(n); } fruit::Component getReplacementReplacementComponent(ComponentParamTypes) { static int n = 30; return fruit::createComponent() .bindInstance(n); } fruit::Component getRootComponent() { return fruit::createComponent() .replace(ReplacementComponentInstallation).with(ReplacementReplacementComponentInstallation) .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) .install(ReplacedComponentInstallation); } int main() { fruit::Injector injector(getRootComponent); int n = injector.get(); Assert(n == 30); } ''' expect_success( COMMON_DEFINITIONS, source, locals()) def test_replace_component_different_type_error(): source = ''' fruit::Component getReplacedComponent(); fruit::Component getReplacementComponent(); fruit::Component<> getRootComponent() { return fruit::createComponent() .replace(getReplacedComponent).with(getReplacementComponent); } ''' expect_generic_compile_error( # Clang 'candidate template ignored: could not match .Component. against .Component.' # GCC '|mismatched types .int. and .double.' # MSVC '|could not deduce template argument for .fruit::Component \(__cdecl \*\)\(FormalArgs...\). from .fruit::Component \(void\).', COMMON_DEFINITIONS, source) @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_already_replaced_consistent_ok( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): source = ''' fruit::Component getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .bindInstance(n); } fruit::Component getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .bindInstance(n); } fruit::Component getRootComponent() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) .install(ReplacedComponentInstallation); } int main() { fruit::Injector injector(getRootComponent); int n = injector.get(); Assert(n == 20); } ''' expect_success( COMMON_DEFINITIONS, 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_already_replaced_across_normalized_component_consistent_ok( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): source = ''' fruit::Component getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .bindInstance(n); } fruit::Component getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .bindInstance(n); } fruit::Component<> getRootComponent1() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation); } fruit::Component getRootComponent2() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) .install(ReplacedComponentInstallation); } int main() { fruit::NormalizedComponent<> normalizedComponent(getRootComponent1); fruit::Injector injector(normalizedComponent, getRootComponent2); int n = injector.get(); Assert(n == 20); } ''' expect_success( COMMON_DEFINITIONS, source, locals()) @pytest.mark.parametrize('ReplacedComponentParamTypes,ReplacedComponentInstallation', [ ('', 'getReplacedComponent'), ('double', 'getReplacedComponent, 1.0'), ]) @pytest.mark.parametrize('ReplacementComponentParamTypes,ReplacementComponentInstallation,OtherReplacementComponentInstallation', [ ('', 'getReplacementComponent', 'getOtherReplacementComponent'), ('std::string', 'getReplacementComponent, std::string("Hello, world")', 'getOtherReplacementComponent, std::string("Hello, world")'), ]) def test_replace_component_already_replaced_inconsistent_error( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation, OtherReplacementComponentInstallation): source = ''' fruit::Component getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .bindInstance(n); } fruit::Component getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .bindInstance(n); } fruit::Component getOtherReplacementComponent(ReplacementComponentParamTypes) { static int n = 30; return fruit::createComponent() .bindInstance(n); } fruit::Component<> getRootComponent() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) .replace(ReplacedComponentInstallation).with(OtherReplacementComponentInstallation); } int main() { fruit::Injector<> injector(getRootComponent); (void) injector; } ''' expect_runtime_error( 'Fatal injection error: the component function at (0x)?[0-9a-fA-F]* with signature ' + '(class )?fruit::Component \((__cdecl)?\*\)\((void)?ReplacedComponentParamTypes\) was replaced ' + '\(using .replace\(...\).with\(...\)\) with both the component function at (0x)?[0-9a-fA-F]* with signature ' + '(class )?fruit::Component \((__cdecl)?\*\)\(.*\) and the component function at ' + '(0x)?[0-9a-fA-F]* with signature (class )?fruit::Component \((__cdecl)?\*\)\(.*\) .', COMMON_DEFINITIONS, source, locals()) @pytest.mark.parametrize('ReplacedComponentParamTypes,ReplacedComponentInstallation', [ ('', 'getReplacedComponent'), ('double', 'getReplacedComponent, 1.0'), ]) @pytest.mark.parametrize('ReplacementComponentParamTypes,ReplacementComponentInstallation,OtherReplacementComponentInstallation', [ ('', 'getReplacementComponent', 'getOtherReplacementComponent'), ('std::string', 'getReplacementComponent, std::string("Hello, world")', 'getOtherReplacementComponent, std::string("Hello, world")'), ]) def test_replace_component_already_replaced_across_normalized_component_inconsistent_error( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation, OtherReplacementComponentInstallation): source = ''' fruit::Component getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .bindInstance(n); } fruit::Component getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .bindInstance(n); } fruit::Component getOtherReplacementComponent(ReplacementComponentParamTypes) { static int n = 30; return fruit::createComponent() .bindInstance(n); } fruit::Component<> getRootComponent1() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation); } fruit::Component<> getRootComponent2() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(OtherReplacementComponentInstallation); } int main() { fruit::NormalizedComponent<> normalizedComponent(getRootComponent1); fruit::Injector<> injector(normalizedComponent, getRootComponent2); (void) injector; } ''' expect_runtime_error( 'Fatal injection error: the component function at (0x)?[0-9a-fA-F]* with signature ' + '(class )?fruit::Component \((__cdecl)?\*\)\((void)?ReplacedComponentParamTypes\) was replaced ' + '\(using .replace\(...\).with\(...\)\) with both the component function at (0x)?[0-9a-fA-F]* with signature ' + '(class )?fruit::Component \((__cdecl)?\*\)\(.*\) and the component function at ' + '(0x)?[0-9a-fA-F]* with signature (class )?fruit::Component \((__cdecl)?\*\)\(.*\) .', COMMON_DEFINITIONS, 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_after_install_error( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): source = ''' fruit::Component getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .bindInstance(n); } fruit::Component getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .bindInstance(n); } fruit::Component getRootComponent() { return fruit::createComponent() .install(ReplacedComponentInstallation) .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation); } int main() { fruit::Injector injector(getRootComponent); (void) injector; } ''' expect_runtime_error( 'Fatal injection error: unable to replace \(using .replace\(...\).with\(...\)\) the component function at ' + '(0x)?[0-9a-fA-F]* with signature (class )?fruit::Component \((__cdecl)?\*\)\((void)?ReplacedComponentParamTypes\) with the ' + 'component function at (0x)?[0-9a-fA-F]* with signature ' + '(class )?fruit::Component \((__cdecl)?\*\)\(.*\) because the former component function ' + 'was installed before the .replace\(...\).with\(...\).', COMMON_DEFINITIONS, 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_after_install_across_normalized_component_error( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): source = ''' fruit::Component getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .bindInstance(n); } fruit::Component getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .bindInstance(n); } fruit::Component getRootComponent1() { return fruit::createComponent() .install(ReplacedComponentInstallation); } fruit::Component<> getRootComponent2() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation); } int main() { fruit::NormalizedComponent normalizedComponent(getRootComponent1); fruit::Injector injector(normalizedComponent, getRootComponent2); (void) injector; } ''' expect_runtime_error( 'Fatal injection error: unable to replace \(using .replace\(...\).with\(...\)\) the component function at ' + '(0x)?[0-9a-fA-F]* with signature (class )?fruit::Component \((__cdecl)?\*\)\((void)?ReplacedComponentParamTypes\) with the ' + 'component function at (0x)?[0-9a-fA-F]* with signature ' + '(class )?fruit::Component \((__cdecl)?\*\)\(.*\) because the former component function ' + 'was installed before the .replace\(...\).with\(...\).', COMMON_DEFINITIONS, source, locals()) @pytest.mark.parametrize('ReplacedComponentParamTypes,ReplacedComponentInstallation,ReplacementComponentParamTypes,ReplacementComponentInstallation', [ ('', 'getReplacedComponent', '', 'getReplacementComponent'), ('double', 'getReplacedComponent, 1.0', 'std::string', 'getReplacementComponent, std::string("Hello, world")'), ]) def test_replace_component_unused_ok( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): source = ''' fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getRootComponent() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation); } int main() { fruit::Injector<> injector(getRootComponent); std::vector multibindings = injector.getMultibindings(); Assert(multibindings.size() == 0); } ''' expect_success( COMMON_DEFINITIONS, 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_used_multiple_times_ok( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): source = ''' fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getRootComponent() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) .install(ReplacedComponentInstallation) .install(ReplacedComponentInstallation); } int main() { fruit::Injector<> injector(getRootComponent); std::vector multibindings = injector.getMultibindings(); Assert(multibindings.size() == 1); Assert(*(multibindings[0]) == 20); } ''' expect_success( COMMON_DEFINITIONS, 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_also_installed_directly_before_ok( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): source = ''' fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getRootComponent() { return fruit::createComponent() .install(ReplacementComponentInstallation) .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) .install(ReplacedComponentInstallation); } int main() { fruit::Injector<> injector(getRootComponent); std::vector multibindings = injector.getMultibindings(); Assert(multibindings.size() == 1); Assert(*(multibindings[0]) == 20); } ''' expect_success( COMMON_DEFINITIONS, 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_also_installed_directly_after_ok( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): source = ''' fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getRootComponent() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) .install(ReplacedComponentInstallation) .install(ReplacementComponentInstallation); } int main() { fruit::Injector<> injector(getRootComponent); std::vector multibindings = injector.getMultibindings(); Assert(multibindings.size() == 1); Assert(*(multibindings[0]) == 20); } ''' expect_success( COMMON_DEFINITIONS, 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_also_installed_directly_before_across_normalized_component_ok( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): source = ''' fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getRootComponent1() { return fruit::createComponent() .install(ReplacementComponentInstallation); } fruit::Component<> getRootComponent2() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) .install(ReplacedComponentInstallation); } int main() { fruit::NormalizedComponent<> normalizedComponent(getRootComponent1); fruit::Injector<> injector(normalizedComponent, getRootComponent2); std::vector multibindings = injector.getMultibindings(); Assert(multibindings.size() == 1); Assert(*(multibindings[0]) == 20); } ''' expect_success( COMMON_DEFINITIONS, 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_also_installed_directly_after_across_normalized_component_ok( ReplacedComponentParamTypes, ReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): source = ''' fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) { static int n = 20; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getRootComponent1() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) .install(ReplacedComponentInstallation); } fruit::Component<> getRootComponent2() { return fruit::createComponent() .install(ReplacementComponentInstallation); } int main() { fruit::NormalizedComponent<> normalizedComponent(getRootComponent1); fruit::Injector<> injector(normalizedComponent, getRootComponent2); std::vector multibindings = injector.getMultibindings(); Assert(multibindings.size() == 1); Assert(*(multibindings[0]) == 20); } ''' expect_success( COMMON_DEFINITIONS, source, locals()) @pytest.mark.parametrize('ReplacedComponentParamTypes,ReplacedComponentInstallation,OtherReplacedComponentInstallation', [ ('', 'getReplacedComponent', 'getOtherReplacementComponent'), ('double', 'getReplacedComponent, 1.0', 'getOtherReplacementComponent, 1.0'), ]) @pytest.mark.parametrize('ReplacementComponentParamTypes,ReplacementComponentInstallation', [ ('', 'getReplacementComponent'), ('std::string', 'getReplacementComponent, std::string("Hello, world")'), ]) def test_replace_multiple_components_with_same( ReplacedComponentParamTypes, ReplacedComponentInstallation, OtherReplacedComponentInstallation, ReplacementComponentParamTypes, ReplacementComponentInstallation): source = ''' fruit::Component<> getReplacedComponent(ReplacedComponentParamTypes) { static int n = 10; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getOtherReplacementComponent(ReplacedComponentParamTypes) { static int n = 20; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getReplacementComponent(ReplacementComponentParamTypes) { static int n = 30; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getRootComponent() { return fruit::createComponent() .replace(ReplacedComponentInstallation).with(ReplacementComponentInstallation) .replace(OtherReplacedComponentInstallation).with(ReplacementComponentInstallation) .install(ReplacedComponentInstallation) .install(OtherReplacedComponentInstallation); } int main() { fruit::Injector<> injector(getRootComponent); std::vector multibindings = injector.getMultibindings(); Assert(multibindings.size() == 1); Assert(*(multibindings[0]) == 30); } ''' expect_success( COMMON_DEFINITIONS, source, locals()) def test_replace_component_one_set_of_args_only(): source = ''' fruit::Component<> getReplacedComponent(double) { static int n = 10; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getReplacementComponent() { static int n = 20; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getRootComponent() { return fruit::createComponent() .replace(getReplacedComponent, 1.0).with(getReplacementComponent) .install(getReplacedComponent, 1.0) .install(getReplacedComponent, 5.0); } int main() { fruit::Injector<> injector(getRootComponent); std::vector multibindings = injector.getMultibindings(); Assert(multibindings.size() == 2); Assert(*(multibindings[0]) == 20); Assert(*(multibindings[1]) == 10); } ''' expect_success( COMMON_DEFINITIONS, source, locals()) def test_replace_component_already_replaced_with_different_args(): source = ''' fruit::Component<> getReplacedComponent(double) { static int n = 10; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getReplacementComponent() { static int n = 20; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getOtherReplacementComponent() { static int n = 30; return fruit::createComponent() .addInstanceMultibinding(n); } fruit::Component<> getRootComponent() { return fruit::createComponent() .replace(getReplacedComponent, 1.0).with(getReplacementComponent) .replace(getReplacedComponent, 5.0).with(getOtherReplacementComponent) .install(getReplacedComponent, 1.0) .install(getReplacedComponent, 5.0); } int main() { fruit::Injector<> injector(getRootComponent); std::vector multibindings = injector.getMultibindings(); Assert(multibindings.size() == 2); Assert(*(multibindings[0]) == 20); Assert(*(multibindings[1]) == 30); } ''' expect_success( COMMON_DEFINITIONS, source, locals()) if __name__== '__main__': main(__file__)