| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/test/rectify_callback.h" |
| |
| #include <sstream> |
| #include <utility> |
| |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/functional/callback_forward.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/test/bind.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace base { |
| |
| // Test rectifying functions with no return value. |
| |
| #define CALLBACK_TESTS_VOID(TestNameSuffix, Signature, LambdaToRectify, ...) \ |
| TEST(RectifyCallbackTest, RepeatingCallbackSignatureVoid##TestNameSuffix) { \ |
| auto cb = RectifyCallback<Signature>(BindRepeating(LambdaToRectify)); \ |
| cb.Run(__VA_ARGS__); \ |
| } \ |
| TEST(RectifyCallbackTest, RepeatingCallbackTypeVoid##TestNameSuffix) { \ |
| auto cb = RectifyCallback<RepeatingCallback<Signature>>( \ |
| BindRepeating(LambdaToRectify)); \ |
| cb.Run(__VA_ARGS__); \ |
| } \ |
| TEST(RectifyCallbackTest, RepeatingToOnceVoid##TestNameSuffix) { \ |
| auto cb = RectifyCallback<OnceCallback<Signature>>( \ |
| BindRepeating(LambdaToRectify)); \ |
| std::move(cb).Run(__VA_ARGS__); \ |
| } \ |
| TEST(RectifyCallbackTest, OnceCallbackSignatureVoid##TestNameSuffix) { \ |
| auto cb = RectifyCallback<Signature>(BindOnce(LambdaToRectify)); \ |
| std::move(cb).Run(__VA_ARGS__); \ |
| } \ |
| TEST(RectifyCallbackTest, OnceCallbackTypeVoid##TestNameSuffix) { \ |
| auto cb = \ |
| RectifyCallback<OnceCallback<Signature>>(BindOnce(LambdaToRectify)); \ |
| std::move(cb).Run(__VA_ARGS__); \ |
| } |
| |
| CALLBACK_TESTS_VOID(NoArgsSameSignature, void(), []() {}) |
| |
| CALLBACK_TESTS_VOID( |
| OneArgRemoveOneArg, |
| void(int), |
| []() {}, |
| 1) |
| |
| CALLBACK_TESTS_VOID( |
| TwoArgsRemoveTwoArgs, |
| void(float, int), |
| []() {}, |
| 0.25f, |
| 1) |
| |
| CALLBACK_TESTS_VOID( |
| OneArgSameSignature, |
| void(int), |
| [](int x) { EXPECT_EQ(1, x); }, |
| 1) |
| |
| CALLBACK_TESTS_VOID( |
| TwoArgsRemoveOneArg, |
| void(float, int), |
| [](int x) { EXPECT_EQ(1, x); }, |
| 0.25f, |
| 1) |
| |
| CALLBACK_TESTS_VOID( |
| ThreeArgsRemoveTwoArgs, |
| void(bool, float, int), |
| [](int x) { EXPECT_EQ(1, x); }, |
| true, |
| 0.25f, |
| 1) |
| |
| // Test rectifying functions that do return a value. |
| |
| #define CALLBACK_TESTS_RETURN(TestNameSuffix, Signature, LambdaToRectify, \ |
| ExpectedReturn, ...) \ |
| TEST(RectifyCallbackTest, \ |
| RepeatingCallbackSignatureReturn##TestNameSuffix) { \ |
| auto cb = RectifyCallback<Signature>(BindRepeating(LambdaToRectify)); \ |
| EXPECT_EQ(ExpectedReturn, cb.Run(__VA_ARGS__)); \ |
| } \ |
| TEST(RectifyCallbackTest, RepeatingCallbackTypeReturn##TestNameSuffix) { \ |
| auto cb = RectifyCallback<RepeatingCallback<Signature>>( \ |
| BindRepeating(LambdaToRectify)); \ |
| EXPECT_EQ(ExpectedReturn, cb.Run(__VA_ARGS__)); \ |
| } \ |
| TEST(RectifyCallbackTest, RepeatingToOnceReturn##TestNameSuffix) { \ |
| auto cb = RectifyCallback<OnceCallback<Signature>>( \ |
| BindRepeating(LambdaToRectify)); \ |
| EXPECT_EQ(ExpectedReturn, std::move(cb).Run(__VA_ARGS__)); \ |
| } \ |
| TEST(RectifyCallbackTest, OnceCallbackSignatureReturn##TestNameSuffix) { \ |
| auto cb = RectifyCallback<Signature>(BindOnce(LambdaToRectify)); \ |
| EXPECT_EQ(ExpectedReturn, std::move(cb).Run(__VA_ARGS__)); \ |
| } \ |
| TEST(RectifyCallbackTest, OnceCallbackTypeReturn##TestNameSuffix) { \ |
| auto cb = \ |
| RectifyCallback<OnceCallback<Signature>>(BindOnce(LambdaToRectify)); \ |
| EXPECT_EQ(ExpectedReturn, std::move(cb).Run(__VA_ARGS__)); \ |
| } |
| |
| CALLBACK_TESTS_RETURN( |
| NoArgsSameSignature, |
| int(), |
| []() { return 2; }, |
| 2) |
| |
| CALLBACK_TESTS_RETURN( |
| OneArgRemoveOneArg, |
| int(int), |
| []() { return 2; }, |
| 2, |
| 1) |
| |
| CALLBACK_TESTS_RETURN( |
| TwoArgsRemoveTwoArgs, |
| int(float, int), |
| []() { return 2; }, |
| 2, |
| 0.25f, |
| 1) |
| |
| CALLBACK_TESTS_RETURN( |
| OneArgSameSignature, |
| int(int), |
| [](int x) { return x; }, |
| 2, |
| 2) |
| |
| CALLBACK_TESTS_RETURN( |
| TwoArgsRemoveOneArg, |
| int(float, int), |
| [](int x) { return x; }, |
| 2, |
| 0.25f, |
| 2) |
| |
| CALLBACK_TESTS_RETURN( |
| ThreeArgsRemoveTwoArgs, |
| int(bool, float, int), |
| [](int x) { return x; }, |
| 2, |
| true, |
| 0.25f, |
| 2) |
| |
| // Test proper forwarding of move-only arguments. |
| |
| CALLBACK_TESTS_RETURN( |
| DiscardsMoveOnlyArgs, |
| bool(int, std::unique_ptr<int>), |
| []() { return true; }, |
| true, |
| 2, |
| std::make_unique<int>(3)) |
| |
| CALLBACK_TESTS_RETURN( |
| UsesMoveOnlyArg, |
| int(float, int, std::unique_ptr<int>), |
| [](std::unique_ptr<int> p) { return *p; }, |
| 3, |
| 0.25f, |
| 2, |
| std::make_unique<int>(3)) |
| |
| // Test rectifying DoNothing(). |
| |
| #define CALLBACK_TESTS_DO_NOTHING(TestNameSuffix, Signature, ...) \ |
| TEST(RectifyCallbackTest, SignatureDoNothing##TestNameSuffix) { \ |
| auto cb = RectifyCallback<Signature>(DoNothing()); \ |
| cb.Run(__VA_ARGS__); \ |
| } \ |
| TEST(RectifyCallbackTest, RepeatingCallbackDoNothing##TestNameSuffix) { \ |
| auto cb = RectifyCallback<RepeatingCallback<Signature>>(DoNothing()); \ |
| cb.Run(__VA_ARGS__); \ |
| } \ |
| TEST(RectifyCallbackTest, OnceCallbackDoNothing##TestNameSuffix) { \ |
| auto cb = RectifyCallback<OnceCallback<Signature>>(DoNothing()); \ |
| std::move(cb).Run(__VA_ARGS__); \ |
| } |
| |
| CALLBACK_TESTS_DO_NOTHING(NoArgs, void()) |
| CALLBACK_TESTS_DO_NOTHING(OneArg, void(int), 2) |
| CALLBACK_TESTS_DO_NOTHING(TwoArgs, void(float, int), 0.25, 2) |
| CALLBACK_TESTS_DO_NOTHING(ThreeArgs, void(bool, float, int), false, 0.25, 2) |
| |
| // Test passing callbacks to RectifyCallback() in different ways. |
| |
| TEST(RectifyCallbackTest, RepeatingMove) { |
| auto cb = BindRepeating([](int x) { return x != 0; }); |
| auto cb2 = RectifyCallback<bool(float, int)>(std::move(cb)); |
| EXPECT_EQ(true, cb2.Run(1.0, 1)); |
| EXPECT_EQ(false, cb2.Run(1.0, 0)); |
| } |
| |
| TEST(RectifyCallbackTest, RepeatingCopy) { |
| const auto cb = BindRepeating([](int x) { return x != 0; }); |
| auto cb2 = RectifyCallback<bool(float, int)>(cb); |
| EXPECT_EQ(true, cb2.Run(1.0, 1)); |
| EXPECT_EQ(false, cb2.Run(1.0, 0)); |
| } |
| |
| TEST(RectifyCallbackTest, RepeatingConstReference) { |
| const auto cb = BindRepeating([](int x) { return x != 0; }); |
| const auto& cb_ref = cb; |
| auto cb2 = RectifyCallback<bool(float, int)>(cb_ref); |
| EXPECT_EQ(true, cb2.Run(1.0, 1)); |
| EXPECT_EQ(false, cb2.Run(1.0, 0)); |
| } |
| |
| TEST(RectifyCallbackTest, OnceMove) { |
| auto cb = BindOnce([](int x) { return x != 0; }); |
| auto cb2 = RectifyCallback<bool(float, int)>(std::move(cb)); |
| EXPECT_EQ(true, std::move(cb2).Run(1.0, 1)); |
| } |
| |
| TEST(RectifyCallbackTest, OnceFromRepeating) { |
| auto cb = BindRepeating([](int x) { return x != 0; }); |
| auto cb2 = RectifyCallback<OnceCallback<bool(float, int)>>(std::move(cb)); |
| EXPECT_EQ(true, std::move(cb2).Run(1.0, 1)); |
| } |
| |
| // Test that we can write a function that can rectify its callback argument into |
| // the signature it wants. |
| // |
| // If this is implemented incorrectly, it can result in strange/bad behavior, |
| // even if it manages to compile. |
| |
| namespace { |
| |
| using ExampleRepeatingTargetType = RepeatingCallback<bool(double, int)>; |
| using ExampleOnceTargetType = OnceCallback<bool(double, int)>; |
| |
| // This is the call we'll be rectifying into the expected signature. |
| bool ExampleTargetFunction(int x) { |
| return x != 0; |
| } |
| |
| // Base version of the function that takes a repeating callback. |
| // This is the actual implementation. |
| void ExampleFunctionRepeatingCallback(ExampleRepeatingTargetType callback) { |
| EXPECT_EQ(true, std::move(callback).Run(1.0, 1)); |
| } |
| |
| // Template version of the function that wants a repeating callback; it will |
| // rectify its input and call the base version. |
| // |
| // If the rectify goes awry (e.g. the wrong kind of callback is generated), |
| // this can result in an infinite loop. |
| template <typename T> |
| void ExampleFunctionRepeatingCallback(T&& callback) { |
| ExampleFunctionRepeatingCallback( |
| RectifyCallback<ExampleRepeatingTargetType>(std::forward<T>(callback))); |
| } |
| |
| // Base version of the function that takes a once callback. |
| // This is the actual implementation. |
| void ExampleFunctionOnceCallback(ExampleOnceTargetType callback) { |
| EXPECT_EQ(true, std::move(callback).Run(1.0, 1)); |
| } |
| |
| // Template version of the function that wants a once callback; it will |
| // rectify its input and call the base version. |
| // |
| // If the rectify goes awry (e.g. the wrong kind of callback is generated), |
| // this can result in an infinite loop. |
| template <typename T> |
| void ExampleFunctionOnceCallback(T&& callback) { |
| ExampleFunctionOnceCallback( |
| RectifyCallback<ExampleOnceTargetType>(std::forward<T>(callback))); |
| } |
| |
| } // namespace |
| |
| TEST(RectifyCallbackTest, TemplateOverloadRectifiesOnceCallback) { |
| ExampleFunctionOnceCallback(BindOnce(&ExampleTargetFunction)); |
| ExampleFunctionOnceCallback(BindOnce([]() { return true; })); |
| ExampleFunctionOnceCallback(BindOnce([](double d, int i) { return d && i; })); |
| auto cb = BindOnce(&ExampleTargetFunction); |
| ExampleFunctionOnceCallback(std::move(cb)); |
| } |
| |
| TEST(RectifyCallbackTest, TemplateOverloadRectifiesRepeatingCallback) { |
| ExampleFunctionOnceCallback(BindRepeating(&ExampleTargetFunction)); |
| ExampleFunctionOnceCallback(BindRepeating([]() { return true; })); |
| ExampleFunctionOnceCallback( |
| BindRepeating([](double d, int i) { return d && i; })); |
| auto cb = BindRepeating(&ExampleTargetFunction); |
| ExampleFunctionOnceCallback(cb); |
| bool result = true; |
| ExampleFunctionOnceCallback(BindLambdaForTesting([&]() { return result; })); |
| } |
| |
| TEST(RectifyCallbackTest, TemplateOverloadCoerceRepeatingTarget) { |
| ExampleFunctionRepeatingCallback(BindRepeating(&ExampleTargetFunction)); |
| ExampleFunctionRepeatingCallback(BindRepeating([]() { return true; })); |
| ExampleFunctionRepeatingCallback( |
| BindRepeating([](double d, int i) { return d && i; })); |
| auto cb = BindRepeating(&ExampleTargetFunction); |
| ExampleFunctionRepeatingCallback(cb); |
| bool result = true; |
| ExampleFunctionRepeatingCallback( |
| BindLambdaForTesting([&]() { return result; })); |
| } |
| |
| TEST(RectifyCallbackTest, NullCallbackPassthrough) { |
| { |
| OnceCallback<void()> once; |
| RepeatingCallback<void()> repeating; |
| EXPECT_TRUE(RectifyCallback<void()>(std::move(once)).is_null()); |
| EXPECT_TRUE(RectifyCallback<void()>(repeating).is_null()); |
| EXPECT_TRUE(RectifyCallback<void()>(NullCallback()).is_null()); |
| } |
| |
| { |
| OnceCallback<void()> once; |
| RepeatingCallback<void()> repeating; |
| EXPECT_TRUE(RectifyCallback<void(int)>(std::move(once)).is_null()); |
| EXPECT_TRUE(RectifyCallback<void(int)>(repeating).is_null()); |
| EXPECT_TRUE(RectifyCallback<void(int)>(NullCallback()).is_null()); |
| } |
| } |
| |
| } // namespace base |