diff --git a/examples/annotated_injection/car.cpp b/examples/annotated_injection/car.cpp index 32f47fa4..53d4ce1b 100644 --- a/examples/annotated_injection/car.cpp +++ b/examples/annotated_injection/car.cpp @@ -42,6 +42,6 @@ class CarImpl : public Car { fruit::Component getCarComponent() { return fruit::createComponent() .bind() - .install(getMainBrakeComponent()) - .install(getEmergencyBrakeComponent()); + .install(getMainBrakeComponent) + .install(getEmergencyBrakeComponent); } diff --git a/examples/scaling_doubles/scaler.cpp b/examples/scaling_doubles/scaler.cpp index 9b6889aa..da277945 100644 --- a/examples/scaling_doubles/scaler.cpp +++ b/examples/scaling_doubles/scaler.cpp @@ -40,5 +40,5 @@ class ScalerImpl : public Scaler { Component getScalerComponent() { return createComponent() .bind() - .install(getMultiplierComponent()); + .install(getMultiplierComponent); } diff --git a/examples/server/main.cpp b/examples/server/main.cpp index c6e637cf..633ab2e6 100644 --- a/examples/server/main.cpp +++ b/examples/server/main.cpp @@ -25,7 +25,7 @@ int main() { Injector injector(getServerComponent()); Server* server(injector); - server->run(getRequestDispatcherComponent()); + server->run(getRequestDispatcherComponent); return 0; } diff --git a/examples/server/request_dispatcher.cpp b/examples/server/request_dispatcher.cpp index ed0ee17c..2901a3ba 100644 --- a/examples/server/request_dispatcher.cpp +++ b/examples/server/request_dispatcher.cpp @@ -61,6 +61,6 @@ class RequestDispatcherImpl : public RequestDispatcher { Component, RequestDispatcher> getRequestDispatcherComponent() { return createComponent() .bind() - .install(getFooHandlerComponent()) - .install(getBarHandlerComponent()); + .install(getFooHandlerComponent) + .install(getBarHandlerComponent); } diff --git a/examples/server/server.cpp b/examples/server/server.cpp index 962ebbc6..33f012f8 100644 --- a/examples/server/server.cpp +++ b/examples/server/server.cpp @@ -37,13 +37,13 @@ class ServerImpl : public Server { } } - void run(Component, RequestDispatcher> requestDispatcherComponent) override { + void run(Component, RequestDispatcher>(*requestDispatcherComponent)()) override { ServerContext serverContext; serverContext.startupTime = getTime(); const NormalizedComponent, RequestDispatcher> requestDispatcherNormalizedComponent( createComponent() - .install(std::move(requestDispatcherComponent)) + .install(requestDispatcherComponent) .bindInstance(serverContext)); cerr << "Server started." << endl; diff --git a/examples/server/server.h b/examples/server/server.h index 91fc7dec..4a0273e0 100644 --- a/examples/server/server.h +++ b/examples/server/server.h @@ -26,7 +26,8 @@ class Server { public: - virtual void run(fruit::Component, RequestDispatcher> requestDispatcherComponent) = 0; + virtual void run( + fruit::Component, RequestDispatcher>(*)()) = 0; }; fruit::Component getServerComponent(); diff --git a/examples/simple_injection/checked_incrementer.cpp b/examples/simple_injection/checked_incrementer.cpp index 7ffd612f..7f27a356 100644 --- a/examples/simple_injection/checked_incrementer.cpp +++ b/examples/simple_injection/checked_incrementer.cpp @@ -21,6 +21,6 @@ fruit::Component getCheckedIncrementerComponent() { return fruit::createComponent() - .install(getIncrementerImplComponent()) - .install(getCheckedAdderComponent()); + .install(getIncrementerImplComponent) + .install(getCheckedAdderComponent); } diff --git a/examples/simple_injection/simple_incrementer.cpp b/examples/simple_injection/simple_incrementer.cpp index 3d3f835f..9a0b869a 100644 --- a/examples/simple_injection/simple_incrementer.cpp +++ b/examples/simple_injection/simple_incrementer.cpp @@ -21,6 +21,6 @@ fruit::Component getSimpleIncrementerComponent() { return fruit::createComponent() - .install(getIncrementerImplComponent()) - .install(getSimpleAdderComponent()); + .install(getIncrementerImplComponent) + .install(getSimpleAdderComponent); } diff --git a/include/fruit/component.h b/include/fruit/component.h index d82c9c84..ee93c4bf 100644 --- a/include/fruit/component.h +++ b/include/fruit/component.h @@ -40,7 +40,7 @@ template class Component { public: Component(Component&&) = default; - Component(const Component&) = default; + FRUIT_DEPRECATED_DECLARATION(Component(const Component&)); Component& operator=(Component&&) = delete; Component& operator=(const Component&) = delete; @@ -61,7 +61,7 @@ class Component { * It's provided only for convenience. */ template - Component(Component component); + FRUIT_DEPRECATED_DECLARATION(Component(Component component)); private: // Do not use. Use fruit::createComponent() instead. @@ -92,8 +92,8 @@ class Component { * * fruit::Component getFooComponent() { * return fruit::createComponent() - * .install(getComponent1()) - * .install(getComponent2()) + * .install(getComponent1) + * .install(getComponent2) * .bind(); * } * @@ -122,8 +122,8 @@ PartialComponent<> createComponent(); * * fruit::Component getFooComponent() { * return fruit::createComponent() - * .install(getComponent1()) - * .install(getComponent2()) + * .install(getComponent1) + * .install(getComponent2) * .bind(); * } * @@ -459,8 +459,8 @@ class PartialComponent { * Example usage: * * createComponent() - * .install(getComponent1()) - * .install(getComponent2()) + * .install(getComponent1) + * .install(getComponent2) * * As in the example, the template parameters will be inferred by the compiler, it's not necessary to specify them explicitly. * @@ -468,7 +468,52 @@ class PartialComponent { * with fruit::Annotated<> if desired. */ template - PartialComponent>, Bindings...> install(Component component) &&; + FRUIT_DEPRECATED_DECLARATION( + PartialComponent>, Bindings...> + install(Component component) && + ); + + /** + * Adds the bindings (and multibindings) in the Component obtained by calling fun(args...) to the current component. + * + * For example, these components: + * Component getComponent1(); + * Component getComponent2(int n, std::string s); + * + * can be installed as: + * + * createComponent() + * // equivalent to install(getComponent1()) + * .install(getComponent1) + * // equivalent to install(getComponent2(5, std::string("Hello")) + * .install(getComponent2, 5, std::string("Hello")) + * + * If any `args` are provided, they must be: + * - Copy-constructible + * - Move-constructible + * - Assignable + * - Move-assignable + * - Equality comparable (i.e., operator== must be defined for two values of that type) + * - Hashable (i.e., std::hash must be defined for values of that type) + * + * Note that this only applies to `args`. E.g. in the example above `int` and `std::string` must satisfy this + * requirement (and they do), but `Foo` and `Bar` don't need to. + * + * A lambda with no captures can also be used as the first argument, for example: + * + * createComponent() + * .install([]() {return getComponent1();}) + * .install([](int n, std::string s) {return getComponent2(n, s);}, 5, std::string("Hello")) + * + * These two install() calls are equivalent to the previous ones. + * + * As in the example, the template parameters for this method will be inferred by the compiler, it's not necessary to + * specify them explicitly. + */ + template + PartialComponent, Bindings...> install( + OtherComponent(*)(Args...), + Args... args) &&; private: template diff --git a/include/fruit/impl/component.defn.h b/include/fruit/impl/component.defn.h index 2f2972ab..c79279b5 100644 --- a/include/fruit/impl/component.defn.h +++ b/include/fruit/impl/component.defn.h @@ -64,9 +64,14 @@ inline Component::Component(PartialComponent component) Op()(storage); } +template +inline FRUIT_DEPRECATED_DEFINITION(Component::Component(const Component& other)) + : storage(other.storage) { +} + template template -inline Component::Component(Component component) +inline FRUIT_DEPRECATED_DEFINITION(Component::Component(Component component)) : Component(fruit::createComponent().install(component)) { } @@ -221,7 +226,7 @@ PartialComponent::registerFactory(Lambda) && { template template inline PartialComponent>, Bindings...> -PartialComponent::install(Component component) && { +FRUIT_DEPRECATED_DEFINITION(PartialComponent::install(Component component)) && { using Op = OpFor>>; (void)typename fruit::impl::meta::CheckIfError::type(); @@ -229,6 +234,45 @@ PartialComponent::install(Component component) return {std::move(storage)}; } +template +FRUIT_ALWAYS_INLINE +inline int checkAcceptableComponentInstallArg() { + // This lambda checks that the required operations on T exist. + // Note that the lambda is never actually executed. + auto checkRequirements = [](const T& constRef, T value) { + T x1(constRef); + T x2(std::move(value)); + x1 = constRef; + x2 = std::move(value); + bool b = (constRef == constRef); + std::size_t h = std::hash()(constRef); + (void)x1; + (void)x2; + (void)b; + (void)h; + }; + (void)checkRequirements; + return 0; +} + +template +template +inline PartialComponent, Bindings...> +PartialComponent::install( + OtherComponent(*f)(Args...), + Args... args) && { + using IntCollector = int[]; + (void)(IntCollector{0, checkAcceptableComponentInstallArg()...}); + + using Op = OpFor>; + (void)typename fruit::impl::meta::CheckIfError::type(); + + OtherComponent component = f(std::move(args)...); + + storage.install(std::move(component.storage)); + return {std::move(storage)}; +} + } // namespace fruit #endif // FRUIT_COMPONENT_DEFN_H diff --git a/tests/test_bind_instance.py b/tests/test_bind_instance.py index b2abaeb3..c61f0658 100755 --- a/tests/test_bind_instance.py +++ b/tests/test_bind_instance.py @@ -107,24 +107,6 @@ def test_success_two_explicit_type_arguments(XAnnot, XRefAnnot): ''' expect_success(COMMON_DEFINITIONS, source, locals()) -@pytest.mark.parametrize('XAnnot', [ - 'X', - 'fruit::Annotated', -]) -def test_mismatched_type_arguments(XAnnot): - source = ''' - struct X {}; - - fruit::Component<> getComponent(int& n) { - return fruit::createComponent() - .bindInstance(n); - } - ''' - expect_success( - COMMON_DEFINITIONS, - source, - locals()) - @pytest.mark.parametrize('BaseAnnot,BasePtrAnnot', [ ('Base', 'Base*'), ('fruit::Annotated', 'fruit::Annotated'), diff --git a/tests/test_bind_interface.py b/tests/test_bind_interface.py index 16ebec11..3037b949 100755 --- a/tests/test_bind_interface.py +++ b/tests/test_bind_interface.py @@ -108,21 +108,6 @@ def test_bound_chain_ok(): ''' expect_success(COMMON_DEFINITIONS, source) -def test_bind_non_normalized_types_error(): - source = ''' - struct X {}; - - struct Y : public std::shared_ptr {}; - - fruit::Component<> getComponent() { - return fruit::createComponent() - .bind, Y>(); - } - ''' - expect_success( - COMMON_DEFINITIONS, - source) - def test_bind_factory_no_args(): source = ''' struct X { @@ -145,7 +130,7 @@ def test_bind_factory_no_args(): fruit::Component> getComponent() { return fruit::createComponent() - .install(getYComponent()) + .install(getYComponent) .bind(); } @@ -180,7 +165,7 @@ def test_bind_factory_no_args_invalid_unique_ptr(): fruit::Component> getComponent() { return fruit::createComponent() - .install(getYComponent()) + .install(getYComponent) .bind(); } @@ -216,7 +201,7 @@ def test_bind_factory_1_arg(): fruit::Component> getComponent() { return fruit::createComponent() - .install(getYComponent()) + .install(getYComponent) .bind(); } @@ -252,7 +237,7 @@ def test_bind_factory_2_arg(): fruit::Component> getComponent() { return fruit::createComponent() - .install(getYComponent()) + .install(getYComponent) .bind(); } diff --git a/tests/test_binding_clash.py b/tests/test_binding_clash.py index 44fbf266..1edd373d 100755 --- a/tests/test_binding_clash.py +++ b/tests/test_binding_clash.py @@ -46,7 +46,7 @@ .registerConstructor(); } ''', - '.install(getParentComponent())') + '.install(getParentComponent)') INSTALL2=( ''' fruit::Component getParentComponent2() { @@ -54,7 +54,7 @@ .registerConstructor(); } ''', - '.install(getParentComponent2())') + '.install(getParentComponent2)') OLD_STYLE_INSTALL=( ''' fruit::Component getParentComponent() { @@ -230,7 +230,7 @@ def test_clash_with_install_old_style_install( .registerConstructor(); } ''', - '.install(getParentComponent1())') + '.install(getParentComponent1)') INSTALL_ANNOT2=( ''' fruit::Component getParentComponent2() { @@ -238,7 +238,7 @@ def test_clash_with_install_old_style_install( .registerConstructor(); } ''', - '.install(getParentComponent2())') + '.install(getParentComponent2)') OLD_STYLE_INSTALL_ANNOT1=( ''' fruit::Component getParentComponent1() { @@ -401,7 +401,7 @@ def test_bind_instance_and_bind_instance_runtime(XAnnot, XAnnotRegex): fruit::Component getComponentForInstance() { // Note: don't do this in real code, leaks memory. return fruit::createComponent() - .install(getComponentForInstanceHelper()) + .install(getComponentForInstanceHelper) .bindInstance(*(new X())); } @@ -431,7 +431,7 @@ def test_bind_instance_and_binding_runtime(XAnnot, XAnnotRegex): fruit::Component getComponentForInstance(X& x) { return fruit::createComponent() - .install(getComponentForInstanceHelper(&x)) + .install(getComponentForInstanceHelper, &x) .registerConstructor(); } @@ -461,8 +461,13 @@ def test_during_component_merge_consistent_ok(XAnnot): return fruit::createComponent(); } + fruit::Component<> getRootComponent() { + return fruit::createComponent() + .install(getComponent); + } + int main() { - fruit::NormalizedComponent<> normalizedComponent(getComponent()); + fruit::NormalizedComponent<> normalizedComponent(getRootComponent()); fruit::Injector injector(normalizedComponent, getComponent()); Assert(X::num_objects_constructed == 0); diff --git a/tests/test_binding_compression.py b/tests/test_binding_compression.py index 4d2cbc22..e17975c0 100755 --- a/tests/test_binding_compression.py +++ b/tests/test_binding_compression.py @@ -124,7 +124,7 @@ def test_compression_undone(): fruit::Component getI2Component() { return fruit::createComponent() - .install(getI1Component()) + .install(getI1Component) .bind(); } diff --git a/tests/test_component.py b/tests/test_component.py index 56082c14..8669e3ac 100755 --- a/tests/test_component.py +++ b/tests/test_component.py @@ -54,7 +54,8 @@ def test_component_conversion(XAnnot, XPtrAnnot): expect_success( COMMON_DEFINITIONS, source, - locals()) + locals(), + ignore_deprecation_warnings=True) @pytest.mark.parametrize('XAnnot,XPtrAnnot', [ ('X', 'X*'), @@ -136,7 +137,7 @@ def test_copy_deprecated(XAnnot): injector.get(); } ''' - expect_success(COMMON_DEFINITIONS, source, locals()) + expect_generic_compile_error('deprecation|deprecated', COMMON_DEFINITIONS, source, locals()) @pytest.mark.parametrize('XAnnot', [ 'X', @@ -261,17 +262,6 @@ def test_type_required_and_provided_with_different_annotations_ok(): COMMON_DEFINITIONS, source) -def test_two_required_lists_error(): - source = ''' - struct X {}; - struct Y {}; - - InstantiateType(fruit::Component, fruit::Required>) - ''' - expect_success( - COMMON_DEFINITIONS, - source) - def test_multiple_required_types_ok(): source = ''' struct X {}; @@ -283,7 +273,7 @@ def test_multiple_required_types_ok(): fruit::Component getComponent() { return fruit::createComponent() - .install(getEmptyComponent()) + .install(getEmptyComponent) .registerConstructor() .registerConstructor(); } diff --git a/tests/test_injector_unsafe_get.py b/tests/test_injector_unsafe_get.py index ee5ae086..cb47501a 100755 --- a/tests/test_injector_unsafe_get.py +++ b/tests/test_injector_unsafe_get.py @@ -47,8 +47,13 @@ def test_success(XAnnot, YAnnot, ZAnnot): return fruit::createComponent(); } + fruit::Component<> getRootComponent() { + return fruit::createComponent() + .install(getComponent); + } + int main() { - fruit::Injector<> injector(getComponent()); + fruit::Injector<> injector(getRootComponent()); X* x = injector.unsafeGet(); Y* y = injector.unsafeGet(); Z* z = injector.unsafeGet(); diff --git a/tests/test_install.py b/tests/test_install.py index 47ec0c57..0ab906bc 100755 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -38,7 +38,7 @@ def test_success(): fruit::Component getComponent() { return fruit::createComponent() - .install(getParentComponent()); + .install(getParentComponent); } int main() { @@ -74,6 +74,31 @@ def test_success_old_style(): ''' 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 = ''' struct X { @@ -93,13 +118,13 @@ def test_with_requirements_success(): fruit::Component, Y> getYComponent() { return fruit::createComponent() - .install(getParentYComponent()); + .install(getParentYComponent); } fruit::Component getComponent() { return fruit::createComponent() .registerProvider([]() { return X(5); }) - .install(getYComponent()); + .install(getYComponent); } int main() { @@ -166,7 +191,7 @@ def test_with_requirements_not_specified_in_child_component_error(): // We intentionally don't have fruit::Required here, we want to test that this results in an error. fruit::Component getYComponent() { return fruit::createComponent() - .install(getParentYComponent()); + .install(getParentYComponent); } ''' expect_compile_error( @@ -240,7 +265,7 @@ def test_install_with_args_success(): fruit::Component getComponent() { return fruit::createComponent() - .install(getParentComponent(5, std::string("Hello"), Arg{})); + .install(getParentComponent, 5, std::string("Hello"), Arg{}); } int main() { @@ -251,6 +276,179 @@ def test_install_with_args_success(): ''' expect_success(COMMON_DEFINITIONS, source) +def test_install_with_args_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 { + size_t operator()(const Arg&); + }; + } + + fruit::Component getParentComponent(int, std::string, Arg); + + fruit::Component getComponent() { + return fruit::createComponent() + .install(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_install_with_args_error_not_move_assignable(): + source = ''' + 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 { + size_t operator()(const Arg&); + }; + } + + fruit::Component getParentComponent(int, std::string, Arg); + + fruit::Component getComponent() { + return fruit::createComponent() + .install(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_install_with_args_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 { + size_t operator()(const Arg&); + }; + } + + fruit::Component getParentComponent(int, std::string, Arg); + + fruit::Component getComponent() { + return fruit::createComponent() + .install(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_install_with_args_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 { + size_t operator()(const Arg&); + }; + } + + fruit::Component getParentComponent(int, std::string, Arg); + + fruit::Component getComponent() { + return fruit::createComponent() + .install(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_install_with_args_error_not_hashable(): + source = ''' + 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 getParentComponent(int, std::string, Arg); + + fruit::Component getComponent() { + return fruit::createComponent() + .install(getParentComponent, 5, std::string("Hello"), Arg{}); + } + ''' + expect_generic_compile_error( + 'error: use of deleted function .std::hash::hash\(\).' + + '|error: call to implicitly-deleted default constructor of .std::hash.' + + '|error: invalid use of incomplete type .struct std::hash.' + + '|error: implicit instantiation of undefined template .std::(__1::)?hash.' + + '|error C2338: The C\+\+ Standard doesn.t provide a hash for this type.', + COMMON_DEFINITIONS, + source) + @pytest.mark.parametrize('XAnnot', [ 'X', 'fruit::Annotated', @@ -268,18 +466,18 @@ def test_install_component_functions_different_args_not_deduped(XAnnot): fruit::Component<> getComponent2() { return fruit::createComponent() - .install(getComponent(1)); + .install(getComponent, 1); } fruit::Component<> getComponent3() { return fruit::createComponent() - .install(getComponent(2)); + .install(getComponent, 2); } fruit::Component<> getComponent4() { return fruit::createComponent() - .install(getComponent2()) - .install(getComponent3()); + .install(getComponent2) + .install(getComponent3); } int main() { @@ -298,5 +496,50 @@ def test_install_component_functions_different_args_not_deduped(XAnnot): source, locals()) +def test_install_component_functions_different_arguments_loop_not_reported(): + source = ''' + struct X {}; + struct Y {}; + struct Z {}; + + // X -> Y(1) -> Z -> Y(2) + + fruit::Component getXComponent(); + fruit::Component getYComponent(int); + fruit::Component getZComponent(); + + fruit::Component getXComponent() { + return fruit::createComponent() + .registerConstructor() + .install(getYComponent, 1); + } + + fruit::Component getYComponent(int n) { + if (n == 1) { + return fruit::createComponent() + .registerConstructor() + .install(getZComponent); + } else { + return fruit::createComponent() + .registerConstructor(); + } + } + + fruit::Component getZComponent() { + return fruit::createComponent() + .registerConstructor() + .install(getYComponent, 2); + } + + int main() { + fruit::Injector injector(getXComponent()); + injector.get(); + } + ''' + expect_success( + COMMON_DEFINITIONS, + source, + locals()) + if __name__== '__main__': main(__file__) diff --git a/tests/test_misc.py b/tests/test_misc.py index 9c7f467c..7dacb0b7 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -113,14 +113,12 @@ def test_misc(): fruit::Component> getMyComponent() { return fruit::createComponent() // Must fail at runtime. - // .install(getXProvider2()) + // .install(getXProvider2) .bind() - .install(getParentComponent()); + .install(getParentComponent); } int main() { - fruit::Component m = getMyComponent(); - fruit::Injector< Interface3, // XFactory, diff --git a/tests/test_multibindings_misc.py b/tests/test_multibindings_misc.py index 112b7ba1..d6b6d5cf 100755 --- a/tests/test_multibindings_misc.py +++ b/tests/test_multibindings_misc.py @@ -159,6 +159,5 @@ def test_multiple_various_kinds(): COMMON_DEFINITIONS, source) - if __name__== '__main__': main(__file__) diff --git a/tests/test_normalized_component.py b/tests/test_normalized_component.py index c385a0de..0f0b9e2d 100755 --- a/tests/test_normalized_component.py +++ b/tests/test_normalized_component.py @@ -199,17 +199,6 @@ def test_error_type_required_and_provided(XAnnot): source, locals()) -def test_two_required_lists_error(): - source = ''' - struct X {}; - struct Y {}; - - InstantiateType(fruit::NormalizedComponent, fruit::Required>) - ''' - expect_success( - COMMON_DEFINITIONS, - source) - def test_multiple_required_types_ok(): source = ''' struct X {}; @@ -221,7 +210,7 @@ def test_multiple_required_types_ok(): fruit::Component getXYComponent() { return fruit::createComponent() - .install(getEmptyComponent()) + .install(getEmptyComponent) .registerConstructor() .registerConstructor(); } diff --git a/tests/test_register_instance.py b/tests/test_register_instance.py index e7fa4b0f..83438119 100755 --- a/tests/test_register_instance.py +++ b/tests/test_register_instance.py @@ -35,7 +35,7 @@ def test_success(intAnnot, intPtrAnnot): fruit::Component getComponentForInstance(int& n) { return fruit::createComponent() - .install(getComponentForInstanceHelper(&n)) + .install(getComponentForInstanceHelper, &n) .bindInstance(n); } @@ -68,7 +68,7 @@ def test_abstract_class_ok(XAnnot): fruit::Component getComponentForInstance(X& x) { return fruit::createComponent() - .install(getComponentForInstanceHelper(&x)) + .install(getComponentForInstanceHelper, &x) .bindInstance(x); } ''' diff --git a/tests/test_required_types.py b/tests/test_required_types.py index ec1be6fa..8ca8a603 100755 --- a/tests/test_required_types.py +++ b/tests/test_required_types.py @@ -54,8 +54,8 @@ def test_required_success(): } fruit::Component getComponent() { return fruit::createComponent() - .install(getYComponent()) - .install(getXFactoryComponent()); + .install(getYComponent) + .install(getXFactoryComponent); } int main() { fruit::Injector injector(getComponent()); @@ -137,8 +137,8 @@ def test_required_annotated_success(): } fruit::Component getComponent() { return fruit::createComponent() - .install(getYComponent()) - .install(getXFactoryComponent()); + .install(getYComponent) + .install(getXFactoryComponent); } int main() { fruit::Injector injector(getComponent()); @@ -167,8 +167,8 @@ def test_required_forward_declared_success(): fruit::Component getXFactoryComponent(); fruit::Component getComponent() { return fruit::createComponent() - .install(getYComponent()) - .install(getXFactoryComponent()); + .install(getYComponent) + .install(getXFactoryComponent); } int main() { fruit::Injector injector(getComponent()); @@ -214,8 +214,8 @@ def test_required_annotated_forward_declared_success(): fruit::Component getXFactoryComponent(); fruit::Component getComponent() { return fruit::createComponent() - .install(getYComponent()) - .install(getXFactoryComponent()); + .install(getYComponent) + .install(getXFactoryComponent); } int main() { fruit::Injector injector(getComponent());