blob: 261b9e891b0f5533a6dd9433cfe2deb9ed18e060 [file] [log] [blame]
/*
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/task_utils/to_queued_task.h"
#include <memory>
#include "absl/memory/memory.h"
#include "api/task_queue/queued_task.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
using ::testing::InSequence;
using ::testing::MockFunction;
void RunTask(std::unique_ptr<QueuedTask> task) {
// Simulate how task queue suppose to run tasks.
QueuedTask* raw = task.release();
if (raw->Run())
delete raw;
}
TEST(ToQueuedTaskTest, AcceptsLambda) {
bool run = false;
std::unique_ptr<QueuedTask> task = ToQueuedTask([&run] { run = true; });
EXPECT_FALSE(run);
RunTask(std::move(task));
EXPECT_TRUE(run);
}
TEST(ToQueuedTaskTest, AcceptsCopyableClosure) {
struct CopyableClosure {
CopyableClosure(int* num_copies, int* num_moves, int* num_runs)
: num_copies(num_copies), num_moves(num_moves), num_runs(num_runs) {}
CopyableClosure(const CopyableClosure& other)
: num_copies(other.num_copies),
num_moves(other.num_moves),
num_runs(other.num_runs) {
++*num_copies;
}
CopyableClosure(CopyableClosure&& other)
: num_copies(other.num_copies),
num_moves(other.num_moves),
num_runs(other.num_runs) {
++*num_moves;
}
void operator()() { ++*num_runs; }
int* num_copies;
int* num_moves;
int* num_runs;
};
int num_copies = 0;
int num_moves = 0;
int num_runs = 0;
std::unique_ptr<QueuedTask> task;
{
CopyableClosure closure(&num_copies, &num_moves, &num_runs);
task = ToQueuedTask(closure);
// Destroy closure to check with msan task has own copy.
}
EXPECT_EQ(num_copies, 1);
EXPECT_EQ(num_runs, 0);
RunTask(std::move(task));
EXPECT_EQ(num_copies, 1);
EXPECT_EQ(num_moves, 0);
EXPECT_EQ(num_runs, 1);
}
TEST(ToQueuedTaskTest, AcceptsMoveOnlyClosure) {
struct MoveOnlyClosure {
MoveOnlyClosure(int* num_moves, std::function<void()> trigger)
: num_moves(num_moves), trigger(std::move(trigger)) {}
MoveOnlyClosure(const MoveOnlyClosure&) = delete;
MoveOnlyClosure(MoveOnlyClosure&& other)
: num_moves(other.num_moves), trigger(std::move(other.trigger)) {
++*num_moves;
}
void operator()() { trigger(); }
int* num_moves;
std::function<void()> trigger;
};
int num_moves = 0;
MockFunction<void()> run;
auto task = ToQueuedTask(MoveOnlyClosure(&num_moves, run.AsStdFunction()));
EXPECT_EQ(num_moves, 1);
EXPECT_CALL(run, Call);
RunTask(std::move(task));
EXPECT_EQ(num_moves, 1);
}
TEST(ToQueuedTaskTest, AcceptsMoveOnlyCleanup) {
struct MoveOnlyClosure {
MoveOnlyClosure(const MoveOnlyClosure&) = delete;
MoveOnlyClosure(MoveOnlyClosure&&) = default;
void operator()() { trigger(); }
std::function<void()> trigger;
};
MockFunction<void()> run;
MockFunction<void()> cleanup;
auto task = ToQueuedTask(MoveOnlyClosure{run.AsStdFunction()},
MoveOnlyClosure{cleanup.AsStdFunction()});
// Expect run closure to complete before cleanup closure.
InSequence in_sequence;
EXPECT_CALL(run, Call);
EXPECT_CALL(cleanup, Call);
RunTask(std::move(task));
}
TEST(ToQueuedTaskTest, PendingTaskSafetyFlag) {
rtc::scoped_refptr<PendingTaskSafetyFlag> flag =
PendingTaskSafetyFlag::Create();
int count = 0;
// Create two identical tasks that increment the |count|.
auto task1 = ToQueuedTask(flag, [&count]() { ++count; });
auto task2 = ToQueuedTask(flag, [&count]() { ++count; });
EXPECT_EQ(0, count);
RunTask(std::move(task1));
EXPECT_EQ(1, count);
flag->SetNotAlive();
// Now task2 should actually not run.
RunTask(std::move(task2));
EXPECT_EQ(1, count);
}
} // namespace
} // namespace webrtc