/* * 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 #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 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 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 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 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 trigger; }; int num_moves = 0; MockFunction 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 trigger; }; MockFunction run; MockFunction 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)); } } // namespace } // namespace webrtc