Commit 5bf31665 authored by Anand K. Mistry's avatar Anand K. Mistry Committed by Commit Bot

Fix RunOnceClosure(OnceClosure) to take a OnceClosure by value

Bug: None
Change-Id: Iddf32bab6d0ab7ca195db02cc24d31e669a49051
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2037184
Commit-Queue: Anand Mistry <amistry@chromium.org>
Reviewed-by: default avatarkylechar <kylechar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#740079}
parent 1e12b4e8
......@@ -10,6 +10,8 @@
#include <utility>
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace base {
......@@ -70,14 +72,28 @@ MATCHER(IsNotNullCallback, "a non-null callback") {
}
// The Run[Once]Closure() action invokes the Run() method on the closure
// provided when the action is constructed.
// provided when the action is constructed. Function arguments passed when the
// action is run will be ignored.
ACTION_P(RunClosure, closure) {
closure.Run();
}
// TODO(kylechar): This action can't take a OnceClosure by value, fix that.
ACTION_P(RunOnceClosure, closure) {
std::move(closure).Run();
// This action can be invoked at most once. Any further invocation will trigger
// a CHECK failure.
inline auto RunOnceClosure(base::OnceClosure cb) {
// Mock actions need to be copyable, but OnceClosure is not. Wrap the closure
// in a base::RefCountedData<> to allow it to be copied. An alternative would
// be to use AdaptCallbackForRepeating(), but that allows the closure to be
// run more than once and silently ignores any invocation after the first.
// Since this is for use by tests, it's better to crash or CHECK-fail and
// surface the incorrect usage, rather than have a silent unexpected success.
using RefCountedOnceClosure = base::RefCountedData<base::OnceClosure>;
scoped_refptr<RefCountedOnceClosure> copyable_cb =
base::MakeRefCounted<RefCountedOnceClosure>(std::move(cb));
return [copyable_cb](auto&&...) {
CHECK(copyable_cb->data);
std::move(copyable_cb->data).Run();
};
}
// The Run[Once]Closure<N>() action invokes the Run() method on the N-th
......
......@@ -124,5 +124,55 @@ TEST(GmockCallbackSupportTest, RunOnceCallback0) {
EXPECT_TRUE(dst);
}
TEST(GmockCallbackSupportTest, RunClosureValue) {
MockFunction<void()> check;
bool dst = false;
EXPECT_CALL(check, Call())
.WillOnce(RunClosure(base::BindRepeating(&SetBool, true, &dst)));
check.Call();
EXPECT_TRUE(dst);
}
TEST(GmockCallbackSupportTest, RunClosureValueWithArgs) {
MockFunction<void(bool, int)> check;
bool dst = false;
EXPECT_CALL(check, Call(true, 42))
.WillOnce(RunClosure(base::BindRepeating(&SetBool, true, &dst)));
check.Call(true, 42);
EXPECT_TRUE(dst);
}
TEST(GmockCallbackSupportTest, RunOnceClosureValue) {
MockFunction<void()> check;
bool dst = false;
EXPECT_CALL(check, Call())
.WillOnce(RunOnceClosure(base::BindOnce(&SetBool, true, &dst)));
check.Call();
EXPECT_TRUE(dst);
}
TEST(GmockCallbackSupportTest, RunOnceClosureValueWithArgs) {
MockFunction<void(bool, int)> check;
bool dst = false;
EXPECT_CALL(check, Call(true, 42))
.WillOnce(RunOnceClosure(base::BindOnce(&SetBool, true, &dst)));
check.Call(true, 42);
EXPECT_TRUE(dst);
}
TEST(GmockCallbackSupportTest, RunOnceClosureValueMultipleCall) {
MockFunction<void()> check;
bool dst = false;
EXPECT_CALL(check, Call())
.WillRepeatedly(RunOnceClosure(base::BindOnce(&SetBool, true, &dst)));
check.Call();
EXPECT_TRUE(dst);
// Invoking the RunOnceClosure action more than once will trigger a
// CHECK-failure.
dst = false;
EXPECT_DEATH_IF_SUPPORTED(check.Call(), "copyable_cb->data");
}
} // namespace test
} // namespace base
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment