From c9e7a0b7e3ca6a4e58ed59567d5e5aa229d1cf77 Mon Sep 17 00:00:00 2001 From: Marco Poletti Date: Sun, 11 Jun 2017 20:04:03 +0100 Subject: Mark the old PartialComponent::install() method as deprecated. --- configuration/CMakeLists.txt | 34 +++++ configuration/bazel/fruit/impl/fruit-config-base.h | 6 + configuration/fruit-config-base.h.in | 4 + include/fruit/component.h | 8 +- include/fruit/impl/component.defn.h | 17 ++- include/fruit/impl/fruit-config.h | 10 ++ tests/CMakeLists.txt | 2 +- tests/fruit_test_common.py | 77 ++++++++---- tests/install_component_swap_optimization.cpp | 58 --------- tests/test_binding_clash.py | 137 +++++++++++++++++---- tests/test_install.py | 32 ++++- tests/test_install_component_swap_optimization.py | 65 ++++++++++ tests/test_required_types.py | 2 +- 13 files changed, 343 insertions(+), 109 deletions(-) delete mode 100644 tests/install_component_swap_optimization.cpp create mode 100644 tests/test_install_component_swap_optimization.py diff --git a/configuration/CMakeLists.txt b/configuration/CMakeLists.txt index e8a8407..3103e03 100644 --- a/configuration/CMakeLists.txt +++ b/configuration/CMakeLists.txt @@ -134,6 +134,36 @@ int main() { " FRUIT_HAS_FORCEINLINE) +CHECK_CXX_SOURCE_COMPILES(" +[[deprecated]] void f() { +} + +int main() { + return 0; +} +" +FRUIT_HAS_ATTRIBUTE_DEPRECATED) + +CHECK_CXX_SOURCE_COMPILES(" +void f() __attribute__((deprecated)) { +} + +int main() { + return 0; +} +" +FRUIT_HAS_GCC_ATTRIBUTE_DEPRECATED) + +CHECK_CXX_SOURCE_COMPILES(" +__declspec(deprecated) void f() { +} + +int main() { + return 0; +} +" +FRUIT_HAS_DECLSPEC_DEPRECATED) + if (NOT "${FRUIT_HAS_STD_MAX_ALIGN_T}" AND NOT "${FRUIT_HAS_MAX_ALIGN_T}") message(WARNING "The current C++ standard library doesn't support std::max_align_t nor ::max_align_t. Attempting to use std::max_align_t anyway, but it most likely won't work.") endif() @@ -143,6 +173,10 @@ if(NOT "${FRUIT_HAS_STD_IS_TRIVIALLY_COPYABLE}" AND NOT "${FRUIT_HAS_IS_TRIVIALL message(WARNING "The current standard library doesn't support std::is_trivially_copyable, and the current compiler doesn't support __is_trivially_copyable(T) nor __has_trivial_copy(T). Attemping to use std::is_trivially_copyable anyway, but it most likely won't work.") endif() +if (NOT "${FRUIT_HAS_ATTRIBUTE_DEPRECATED}" AND NOT "${FRUIT_HAS_GCC_ATTRIBUTE_DEPRECATED}" AND NOT "${FRUIT_HAS_DECLSPEC_DEPRECATED}") + message(WARNING "No supported way to mark functions as deprecated was found. Continuing anyway, without the 'deprecated' markers.") +endif() + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fruit-config-base.h.in ${CMAKE_CURRENT_BINARY_DIR}/../include/fruit/impl/fruit-config-base.h) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/../include/fruit/impl/fruit-config-base.h diff --git a/configuration/bazel/fruit/impl/fruit-config-base.h b/configuration/bazel/fruit/impl/fruit-config-base.h index 9cd392f..65b5261 100644 --- a/configuration/bazel/fruit/impl/fruit-config-base.h +++ b/configuration/bazel/fruit/impl/fruit-config-base.h @@ -57,4 +57,10 @@ #define FRUIT_HAS_FORCEINLINE 0 +#define FRUIT_HAS_ATTRIBUTE_DEPRECATED 0 + +#define FRUIT_HAS_GCC_ATTRIBUTE_DEPRECATED 1 + +#define FRUIT_HAS_DECLSPEC_DEPRECATED 0 + #endif // FRUIT_CONFIG_BASE_H diff --git a/configuration/fruit-config-base.h.in b/configuration/fruit-config-base.h.in index c710a22..9f59195 100644 --- a/configuration/fruit-config-base.h.in +++ b/configuration/fruit-config-base.h.in @@ -30,5 +30,9 @@ #cmakedefine FRUIT_USES_BOOST 1 #cmakedefine FRUIT_HAS_ALWAYS_INLINE_ATTRIBUTE 1 #cmakedefine FRUIT_HAS_FORCEINLINE 1 +#cmakedefine FRUIT_HAS_ATTRIBUTE_DEPRECATED 1 +#cmakedefine FRUIT_HAS_GCC_ATTRIBUTE_DEPRECATED 1 +#cmakedefine FRUIT_HAS_DECLSPEC_DEPRECATED 1 + #endif // FRUIT_CONFIG_BASE_H diff --git a/include/fruit/component.h b/include/fruit/component.h index a058db2..9e35907 100644 --- a/include/fruit/component.h +++ b/include/fruit/component.h @@ -68,6 +68,9 @@ class Component { // Do not use. Use fruit::createComponent() instead. Component() = default; + template + friend class Component; + template friend class PartialComponent; @@ -481,7 +484,10 @@ class PartialComponent { * As in the example, the template parameters will be inferred by the compiler, it's not necessary to specify them explicitly. */ template - PartialComponent>, Bindings...> install(const Component& component); + FRUIT_DEPRECATED( + PartialComponent>, Bindings...> + install(const Component& component) + ); /** * Adds the bindings (and multibindings) in the Component obtained by calling fun(params...) to the current component. diff --git a/include/fruit/impl/component.defn.h b/include/fruit/impl/component.defn.h index fdd266e..2d1f01c 100644 --- a/include/fruit/impl/component.defn.h +++ b/include/fruit/impl/component.defn.h @@ -73,7 +73,22 @@ inline Component::Component(PartialComponent component) template template inline Component::Component(Component component) - : Component(fruit::createComponent().install(std::move(component))) { + : storage(std::move(component.storage)) { + (void)typename fruit::impl::meta::CheckIfError::type(); + + using InstallBinding = fruit::impl::InstallComponent>; + + using Op1 = typename fruit::impl::meta::OpForComponent<>::template AddBinding; + (void)typename fruit::impl::meta::CheckIfError::type(); + + using Op2 = typename fruit::impl::meta::OpForComponent::template ConvertTo; + (void)typename fruit::impl::meta::CheckIfError::type(); + + Op2()(storage); + +#ifndef FRUIT_NO_LOOP_CHECK + (void)typename fruit::impl::meta::CheckIfError>::type(); +#endif // !FRUIT_NO_LOOP_CHECK } template diff --git a/include/fruit/impl/fruit-config.h b/include/fruit/impl/fruit-config.h index fc5a763..ec243ed 100644 --- a/include/fruit/impl/fruit-config.h +++ b/include/fruit/impl/fruit-config.h @@ -66,4 +66,14 @@ #define FRUIT_ALWAYS_INLINE #endif +#if FRUIT_HAS_ATTRIBUTE_DEPRECATED +#define FRUIT_DEPRECATED(...) [[deprecated]] __VA_ARGS__ +#elif FRUIT_HAS_GCC_ATTRIBUTE_DEPRECATED +#define FRUIT_DEPRECATED(...) __VA_ARGS__ __attribute__((deprecated)) +#elif FRUIT_HAS_DECLSPEC_DEPRECATED +#define FRUIT_DEPRECATED(...) __declspec(deprecated) __VA_ARGS__ +#else +#define FRUIT_DEPRECATED(...) __VA_ARGS__ +#endif + #endif // FRUIT_CONFIG_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6da5ac2..bbf5e4c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -157,7 +157,6 @@ add_fruit_tests("root" class_destruction.cpp class_destruction_with_annotation.cpp eager_injection.cpp - install_component_swap_optimization.cpp semistatic_map_hash_selection.cpp test1.cpp test1_old_style_install.cpp @@ -218,6 +217,7 @@ add_pytest_based_fruit_tests("root" "test_injector.py" "test_injector_unsafe_get.py" "test_install.py" + "test_install_component_swap_optimization.py" "test_multibindings_bind_instance.py" "test_multibindings_bind_interface.py" "test_multibindings_bind_provider.py" diff --git a/tests/fruit_test_common.py b/tests/fruit_test_common.py index 72869e8..60deac2 100644 --- a/tests/fruit_test_common.py +++ b/tests/fruit_test_common.py @@ -75,13 +75,8 @@ class PosixCompiler: def compile_discarding_output(self, source, include_dirs, args=[]): try: - self._compile( - include_dirs, - args = ( - args - + ['-c', source] - + ['-o', os.path.devnull] - )) + args = args + ['-c', source, '-o', os.path.devnull] + self._compile(include_dirs, args=args) except CommandFailedException as e: raise CompilationFailedException(e.command, e.stderr) @@ -105,6 +100,9 @@ class PosixCompiler: ) run_command(self.executable, args) + def get_disable_deprecation_warning_flags(self): + return ['-Wno-deprecated-declarations'] + class MsvcCompiler: def __init__(self): self.executable = CXX @@ -112,12 +110,8 @@ class MsvcCompiler: def compile_discarding_output(self, source, include_dirs, args=[]): try: - self._compile( - include_dirs, - args = ( - args - + ['/c', source] - )) + args = args + ['/c', source] + self._compile(include_dirs, args = args) except CommandFailedException as e: # Note that we use stdout here, unlike above. MSVC reports compilation warnings and errors on stdout. raise CompilationFailedException(e.command, e.stdout) @@ -141,6 +135,9 @@ class MsvcCompiler: ) run_command(self.executable, args) + def get_disable_deprecation_warning_flags(self): + return ['/wd4996'] + if CXX_COMPILER_NAME == 'MSVC': compiler = MsvcCompiler() if PATH_TO_COMPILED_FRUIT_LIB.endswith('.dll'): @@ -200,13 +197,24 @@ def try_remove_temporary_file(filename): # This shouldn't cause the tests to fail, so we ignore the exception and go ahead. pass -def expect_compile_error_helper(check_error_fun, setup_source_code, source_code, test_params={}): +def expect_compile_error_helper( + check_error_fun, + setup_source_code, + source_code, + test_params={}, + ignore_deprecation_warnings=False): source_code = _construct_final_source_code(setup_source_code, source_code, test_params) source_file_name = _create_temporary_file(source_code, file_name_suffix='.cpp') try: - compiler.compile_discarding_output(source=source_file_name, include_dirs=fruit_tests_include_dirs) + args = [] + if ignore_deprecation_warnings: + args += compiler.get_disable_deprecation_warning_flags() + compiler.compile_discarding_output( + source=source_file_name, + include_dirs=fruit_tests_include_dirs, + args=args) raise Exception('The test should have failed to compile, but it compiled successfully') except CompilationFailedException as e1: e = e1 @@ -255,7 +263,13 @@ def expect_generic_compile_error(expected_error_regex, setup_source_code, source expect_compile_error_helper(check_error, setup_source_code, source_code, test_params) -def expect_compile_error(expected_fruit_error_regex, expected_fruit_error_desc_regex, setup_source_code, source_code, test_params={}): +def expect_compile_error( + expected_fruit_error_regex, + expected_fruit_error_desc_regex, + setup_source_code, + source_code, + test_params={}, + ignore_deprecation_warnings=False): """ Tests that the given source produces the expected error during compilation. @@ -271,6 +285,7 @@ def expect_compile_error(expected_fruit_error_regex, expected_fruit_error_desc_r :param test_params: A dict containing the definition of some identifiers. Each identifier in expected_fruit_error_regex and source_code will be replaced (textually) with its definition (if a definition was provided). + :param ignore_deprecation_warnings: A boolean. If True, deprecation warnings will be ignored. """ if '\n' in expected_fruit_error_regex: raise Exception('expected_fruit_error_regex should not contain newlines') @@ -395,10 +410,15 @@ def expect_compile_error(expected_fruit_error_regex, expected_fruit_error_desc_r raise Exception( 'The compilation failed with the expected message, but the error message contained some metaprogramming types in the output (besides Error). Error message:\n%s' + error_message_head) - expect_compile_error_helper(check_error, setup_source_code, source_code, test_params) + expect_compile_error_helper(check_error, setup_source_code, source_code, test_params, ignore_deprecation_warnings) -def expect_runtime_error(expected_error_regex, setup_source_code, source_code, test_params={}): +def expect_runtime_error( + expected_error_regex, + setup_source_code, + source_code, + test_params={}, + ignore_deprecation_warnings=False): """ Tests that the given source (compiles successfully and) produces the expected error at runtime. @@ -421,9 +441,15 @@ def expect_runtime_error(expected_error_regex, setup_source_code, source_code, t source_file_name = _create_temporary_file(source_code, file_name_suffix='.cpp') executable_suffix = {'posix': '', 'nt': '.exe'}[os.name] output_file_name = _create_temporary_file('', executable_suffix) + + args = fruit_tests_linker_flags + if ignore_deprecation_warnings: + args += compiler.get_disable_deprecation_warning_flags() compiler.compile_and_link( - source=source_file_name, include_dirs=fruit_tests_include_dirs, output_file_name=output_file_name, - args=fruit_tests_linker_flags) + source=source_file_name, + include_dirs=fruit_tests_include_dirs, + output_file_name=output_file_name, + args=args) try: run_command(output_file_name) @@ -451,7 +477,7 @@ def expect_runtime_error(expected_error_regex, setup_source_code, source_code, t try_remove_temporary_file(output_file_name) -def expect_success(setup_source_code, source_code, test_params={}): +def expect_success(setup_source_code, source_code, test_params={}, ignore_deprecation_warnings=False): """ Tests that the given source compiles and runs successfully. @@ -474,9 +500,14 @@ def expect_success(setup_source_code, source_code, test_params={}): executable_suffix = {'posix': '', 'nt': '.exe'}[os.name] output_file_name = _create_temporary_file('', executable_suffix) + args = fruit_tests_linker_flags + if ignore_deprecation_warnings: + args += compiler.get_disable_deprecation_warning_flags() compiler.compile_and_link( - source=source_file_name, include_dirs=fruit_tests_include_dirs, output_file_name=output_file_name, - args=fruit_tests_linker_flags) + source=source_file_name, + include_dirs=fruit_tests_include_dirs, + output_file_name=output_file_name, + args=args) if RUN_TESTS_UNDER_VALGRIND.lower() in ('false', 'off', 'no', '0', ''): run_command(output_file_name) diff --git a/tests/install_component_swap_optimization.cpp b/tests/install_component_swap_optimization.cpp deleted file mode 100644 index 7faece9..0000000 --- a/tests/install_component_swap_optimization.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2014 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. - */ - -#include "test_common.h" - -using namespace std; - -fruit::Component getParentComponent() { - static int x = 0; - static float y = 0; - static double z = 0; - static unsigned u = 0; - return fruit::createComponent() - .bindInstance(x) - .bindInstance(y) - .bindInstance(z) - .bindInstance(u); -} - -fruit::Component, vector, vector, vector> getParentComponent2() { - static vector x; - static vector y; - static vector z; - static vector u; - return fruit::createComponent() - .bindInstance(x) - .bindInstance(y) - .bindInstance(z) - .bindInstance(u) - .addInstanceMultibinding(x); -} - -fruit::Component getComponent() { - return fruit::createComponent() - .install(getParentComponent()) - .install(getParentComponent2()); -} - -int main() { - fruit::Injector injector(getComponent()); - - injector.get(); - - return 0; -} diff --git a/tests/test_binding_clash.py b/tests/test_binding_clash.py index 666177c..0675777 100755 --- a/tests/test_binding_clash.py +++ b/tests/test_binding_clash.py @@ -97,8 +97,6 @@ OLD_STYLE_INSTALL2=( INTERFACE_BINDING + INTERFACE_BINDING2, INSTALL + CONSTRUCTOR_BINDING, INSTALL + INTERFACE_BINDING, - OLD_STYLE_INSTALL + CONSTRUCTOR_BINDING, - OLD_STYLE_INSTALL + INTERFACE_BINDING, ], ids= [ 'CONSTRUCTOR_BINDING + CONSTRUCTOR_BINDING', @@ -107,8 +105,6 @@ OLD_STYLE_INSTALL2=( 'INTERFACE_BINDING + INTERFACE_BINDING2', 'INSTALL + CONSTRUCTOR_BINDING', 'INSTALL + INTERFACE_BINDING', - 'OLD_STYLE_INSTALL + CONSTRUCTOR_BINDING', - 'OLD_STYLE_INSTALL + INTERFACE_BINDING', ]) @pytest.mark.parametrize('XAnnot,YAnnot,Y2Annot', [ ('X', 'Y', 'Y2'), @@ -135,12 +131,83 @@ def test_clash_with_binding(binding1_preparation, binding1, binding2_preparation source, locals()) +@pytest.mark.parametrize( + 'binding1_preparation,binding1,binding2_preparation,binding2', + [ + OLD_STYLE_INSTALL + CONSTRUCTOR_BINDING, + OLD_STYLE_INSTALL + INTERFACE_BINDING, + ], + ids= [ + 'OLD_STYLE_INSTALL + CONSTRUCTOR_BINDING', + 'OLD_STYLE_INSTALL + INTERFACE_BINDING', + ]) +@pytest.mark.parametrize('XAnnot,YAnnot,Y2Annot', [ + ('X', 'Y', 'Y2'), + ('fruit::Annotated', 'fruit::Annotated', 'fruit::Annotated'), +]) +def test_clash_with_binding_old_style_install( + binding1_preparation, binding1, binding2_preparation, binding2, XAnnot, YAnnot, Y2Annot): + source = ''' + struct X{}; + + %s + %s + + fruit::Component getComponent() { + return fruit::createComponent() + %s + %s; + } + + ''' % (binding1_preparation, binding2_preparation, binding1, binding2) + expect_compile_error( + 'TypeAlreadyBoundError', + 'Trying to bind C but it is already bound.', + COMMON_DEFINITIONS, + source, + locals(), + ignore_deprecation_warnings=True) + @pytest.mark.parametrize( 'binding1_preparation,binding1,binding2_preparation,binding2', [ CONSTRUCTOR_BINDING + INSTALL, INTERFACE_BINDING + INSTALL, INSTALL + INSTALL2, + ], + ids = [ + 'CONSTRUCTOR_BINDING + INSTALL', + 'INTERFACE_BINDING + INSTALL', + 'INSTALL + INSTALL2', + ]) +@pytest.mark.parametrize('XAnnot,YAnnot,Y2Annot', [ + ('X', 'Y', 'Y2'), + ('fruit::Annotated', 'fruit::Annotated', 'fruit::Annotated'), +]) +def test_clash_with_install( + binding1_preparation, binding1, binding2_preparation, binding2, XAnnot, YAnnot, Y2Annot): + source = ''' + struct X{}; + + %s + %s + + fruit::Component getComponent() { + return fruit::createComponent() + %s + %s; + } + ''' % (binding1_preparation, binding2_preparation, binding1, binding2) + expect_compile_error( + 'DuplicateTypesInComponentError', + 'The installed component provides some types that are already provided by the current component.', + COMMON_DEFINITIONS, + source, + locals()) + +@pytest.mark.parametrize( + 'binding1_preparation,binding1,binding2_preparation,binding2', + [ CONSTRUCTOR_BINDING + OLD_STYLE_INSTALL, INTERFACE_BINDING + OLD_STYLE_INSTALL, OLD_STYLE_INSTALL + OLD_STYLE_INSTALL2, @@ -148,9 +215,6 @@ def test_clash_with_binding(binding1_preparation, binding1, binding2_preparation OLD_STYLE_INSTALL + INSTALL2, ], ids = [ - 'CONSTRUCTOR_BINDING + INSTALL', - 'INTERFACE_BINDING + INSTALL', - 'INSTALL + INSTALL2', 'CONSTRUCTOR_BINDING + OLD_STYLE_INSTALL', 'INTERFACE_BINDING + OLD_STYLE_INSTALL', 'OLD_STYLE_INSTALL + OLD_STYLE_INSTALL2', @@ -161,7 +225,7 @@ def test_clash_with_binding(binding1_preparation, binding1, binding2_preparation ('X', 'Y', 'Y2'), ('fruit::Annotated', 'fruit::Annotated', 'fruit::Annotated'), ]) -def test_clash_with_install( +def test_clash_with_install_old_style_install( binding1_preparation, binding1, binding2_preparation, binding2, XAnnot, YAnnot, Y2Annot): source = ''' struct X{}; @@ -180,7 +244,8 @@ def test_clash_with_install( 'The installed component provides some types that are already provided by the current component.', COMMON_DEFINITIONS, source, - locals()) + locals(), + ignore_deprecation_warnings=True) CONSTRUCTOR_BINDING_ANNOT1=( '', @@ -246,16 +311,9 @@ OLD_STYLE_INSTALL_ANNOT2=( INTERFACE_BINDING_ANNOT1 + INTERFACE_BINDING_ANNOT2, INSTALL_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2, INSTALL_ANNOT1 + INTERFACE_BINDING_ANNOT2, - OLD_STYLE_INSTALL_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2, - OLD_STYLE_INSTALL_ANNOT1 + INTERFACE_BINDING_ANNOT2, CONSTRUCTOR_BINDING_ANNOT1 + INSTALL_ANNOT2, INTERFACE_BINDING_ANNOT1 + INSTALL_ANNOT2, - CONSTRUCTOR_BINDING_ANNOT1 + OLD_STYLE_INSTALL_ANNOT2, - INTERFACE_BINDING_ANNOT1 + OLD_STYLE_INSTALL_ANNOT2, INSTALL_ANNOT1 + INSTALL_ANNOT2, - OLD_STYLE_INSTALL_ANNOT1 + INSTALL_ANNOT2, - INSTALL_ANNOT1 + OLD_STYLE_INSTALL_ANNOT2, - OLD_STYLE_INSTALL_ANNOT1 + OLD_STYLE_INSTALL_ANNOT2, ], ids=[ 'CONSTRUCTOR_BINDING_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2', @@ -264,18 +322,54 @@ OLD_STYLE_INSTALL_ANNOT2=( 'INTERFACE_BINDING_ANNOT1 + INTERFACE_BINDING_ANNOT2', 'INSTALL_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2', 'INSTALL_ANNOT1 + INTERFACE_BINDING_ANNOT2', - 'OLD_STYLE_INSTALL_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2', - 'OLD_STYLE_INSTALL_ANNOT1 + INTERFACE_BINDING_ANNOT2', 'CONSTRUCTOR_BINDING_ANNOT1 + INSTALL_ANNOT2', 'INTERFACE_BINDING_ANNOT1 + INSTALL_ANNOT2', + 'INSTALL_ANNOT1 + INSTALL_ANNOT2', + ]) +def test_no_clash_with_different_annotations(binding1_preparation, binding1, binding2_preparation, binding2): + source = ''' + struct X {}; + + %s + %s + + fruit::Component getComponent() { + return fruit::createComponent() + %s + %s; + } + + int main() { + fruit::Injector injector(getComponent()); + injector.get(); + injector.get(); + } + ''' % (binding1_preparation, binding2_preparation, binding1, binding2) + expect_success( + COMMON_DEFINITIONS, + source) + +@pytest.mark.parametrize( + 'binding1_preparation,binding1,binding2_preparation,binding2', + [ + OLD_STYLE_INSTALL_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2, + OLD_STYLE_INSTALL_ANNOT1 + INTERFACE_BINDING_ANNOT2, + CONSTRUCTOR_BINDING_ANNOT1 + OLD_STYLE_INSTALL_ANNOT2, + INTERFACE_BINDING_ANNOT1 + OLD_STYLE_INSTALL_ANNOT2, + OLD_STYLE_INSTALL_ANNOT1 + INSTALL_ANNOT2, + INSTALL_ANNOT1 + OLD_STYLE_INSTALL_ANNOT2, + OLD_STYLE_INSTALL_ANNOT1 + OLD_STYLE_INSTALL_ANNOT2, + ], + ids=[ + 'OLD_STYLE_INSTALL_ANNOT1 + CONSTRUCTOR_BINDING_ANNOT2', + 'OLD_STYLE_INSTALL_ANNOT1 + INTERFACE_BINDING_ANNOT2', 'CONSTRUCTOR_BINDING_ANNOT1 + OLD_STYLE_INSTALL_ANNOT2', 'INTERFACE_BINDING_ANNOT1 + OLD_STYLE_INSTALL_ANNOT2', - 'INSTALL_ANNOT1 + INSTALL_ANNOT2', 'OLD_STYLE_INSTALL_ANNOT1 + INSTALL_ANNOT2', 'INSTALL_ANNOT1 + OLD_STYLE_INSTALL_ANNOT2', 'OLD_STYLE_INSTALL_ANNOT1 + OLD_STYLE_INSTALL_ANNOT2', ]) -def test_no_clash_with_different_annotations(binding1_preparation, binding1, binding2_preparation, binding2): +def test_no_clash_with_different_annotations_old_style_install(binding1_preparation, binding1, binding2_preparation, binding2): source = ''' struct X {}; @@ -296,7 +390,8 @@ def test_no_clash_with_different_annotations(binding1_preparation, binding1, bin ''' % (binding1_preparation, binding2_preparation, binding1, binding2) expect_success( COMMON_DEFINITIONS, - source) + source, + ignore_deprecation_warnings=True) @pytest.mark.parametrize('XAnnot', [ 'X', diff --git a/tests/test_install.py b/tests/test_install.py index 9baf807..42bec54 100755 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -72,7 +72,32 @@ def test_success_old_style(): Assert(x.n == 5); } ''' - expect_success(COMMON_DEFINITIONS, source) + expect_success(COMMON_DEFINITIONS, source, ignore_deprecation_warnings=True) + +def test_old_style_deprecation_error(): + source = ''' + struct X { + int n; + X(int n) : n(n) {} + }; + + fruit::Component getParentComponent() { + return fruit::createComponent() + .registerProvider([]() { return X(5); }); + } + + fruit::Component getComponent() { + return fruit::createComponent() + .install(getParentComponent()); + } + + int main() { + fruit::Injector injector(getComponent()); + X x = injector.get(); + Assert(x.n == 5); + } + ''' + expect_generic_compile_error('deprecation|deprecated', COMMON_DEFINITIONS, source) def test_with_requirements_success(): source = ''' @@ -144,7 +169,7 @@ def test_with_requirements_success_old_style(): Assert(y.x.n == 5); } ''' - expect_success(COMMON_DEFINITIONS, source) + expect_success(COMMON_DEFINITIONS, source, ignore_deprecation_warnings=True) def test_with_requirements_not_specified_in_child_component_error(): source = ''' @@ -202,7 +227,8 @@ def test_with_requirements_not_specified_in_child_component_error_old_style(): 'NoBindingFoundError', 'No explicit binding nor C::Inject definition was found for T', COMMON_DEFINITIONS, - source) + source, + ignore_deprecation_warnings=True) def test_install_with_args_success(): source = ''' diff --git a/tests/test_install_component_swap_optimization.py b/tests/test_install_component_swap_optimization.py new file mode 100644 index 0000000..12bd643 --- /dev/null +++ b/tests/test_install_component_swap_optimization.py @@ -0,0 +1,65 @@ +#!/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_install_component_swap_optimization(): + source = ''' + fruit::Component getParentComponent() { + static int x = 0; + static float y = 0; + static double z = 0; + static unsigned u = 0; + return fruit::createComponent() + .bindInstance(x) + .bindInstance(y) + .bindInstance(z) + .bindInstance(u); + } + + fruit::Component, std::vector, std::vector, std::vector> getParentComponent2() { + static std::vector x; + static std::vector y; + static std::vector z; + static std::vector u; + return fruit::createComponent() + .bindInstance(x) + .bindInstance(y) + .bindInstance(z) + .bindInstance(u) + .addInstanceMultibinding(x); + } + + fruit::Component getComponent() { + return fruit::createComponent() + .install(getParentComponent()) + .install(getParentComponent2()); + } + + int main() { + fruit::Injector injector(getComponent()); + injector.get(); + + return 0; + } + ''' + expect_success(COMMON_DEFINITIONS, source, ignore_deprecation_warnings=True) + +if __name__== '__main__': + main(__file__) diff --git a/tests/test_required_types.py b/tests/test_required_types.py index 190461c..8ca8a60 100755 --- a/tests/test_required_types.py +++ b/tests/test_required_types.py @@ -104,7 +104,7 @@ def test_required_success_old_style_install(): y->doStuff(); } ''' - expect_success(COMMON_DEFINITIONS, source) + expect_success(COMMON_DEFINITIONS, source, ignore_deprecation_warnings=True) def test_required_annotated_success(): source = ''' -- cgit v1.2.3