1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "media/cast/test/fake_single_thread_task_runner.h"
6
7#include "base/logging.h"
8#include "base/time/tick_clock.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11namespace media {
12namespace cast {
13namespace test {
14
15FakeSingleThreadTaskRunner::FakeSingleThreadTaskRunner(
16    base::SimpleTestTickClock* clock)
17    : clock_(clock),
18      fail_on_next_task_(false) {}
19
20FakeSingleThreadTaskRunner::~FakeSingleThreadTaskRunner() {}
21
22bool FakeSingleThreadTaskRunner::PostDelayedTask(
23    const tracked_objects::Location& from_here,
24    const base::Closure& task,
25    base::TimeDelta delay) {
26  if (fail_on_next_task_) {
27    LOG(FATAL) << "Infinite task-add loop detected.";
28  }
29  CHECK(delay >= base::TimeDelta());
30  EXPECT_GE(delay, base::TimeDelta());
31  PostedTask posed_task(from_here,
32                        task,
33                        clock_->NowTicks(),
34                        delay,
35                        base::TestPendingTask::NESTABLE);
36
37  tasks_.insert(std::make_pair(posed_task.GetTimeToRun(), posed_task));
38  return false;
39}
40
41bool FakeSingleThreadTaskRunner::RunsTasksOnCurrentThread() const {
42  return true;
43}
44
45void FakeSingleThreadTaskRunner::RunTasks() {
46  while (true) {
47    // Run all tasks equal or older than current time.
48    std::multimap<base::TimeTicks, PostedTask>::iterator it = tasks_.begin();
49    if (it == tasks_.end())
50      return;  // No more tasks.
51
52    PostedTask task = it->second;
53    if (clock_->NowTicks() < task.GetTimeToRun())
54      return;
55
56    tasks_.erase(it);
57    task.task.Run();
58  }
59}
60
61void FakeSingleThreadTaskRunner::Sleep(base::TimeDelta t) {
62  base::TimeTicks run_until = clock_->NowTicks() + t;
63  while (1) {
64    // If we run more than 100000 iterations, we've probably
65    // hit some sort of case where a new task is posted every
66    // time that we invoke a task, and we can't make progress
67    // anymore. If that happens, set fail_on_next_task_ to true
68    // and throw an error when the next task is posted.
69    for (int i = 0; i < 100000; i++) {
70      // Run all tasks equal or older than current time.
71      std::multimap<base::TimeTicks, PostedTask>::iterator it = tasks_.begin();
72      if (it == tasks_.end()) {
73        clock_->Advance(run_until - clock_->NowTicks());
74        return;
75      }
76
77      PostedTask task = it->second;
78      if (run_until < task.GetTimeToRun()) {
79        clock_->Advance(run_until - clock_->NowTicks());
80        return;
81      }
82
83      clock_->Advance(task.GetTimeToRun() - clock_->NowTicks());
84      tasks_.erase(it);
85      task.task.Run();
86    }
87    // Instead of failing immediately, we fail when the next task is
88    // added so that the backtrace will include the task that was added.
89    fail_on_next_task_ = true;
90  }
91}
92
93bool FakeSingleThreadTaskRunner::PostNonNestableDelayedTask(
94    const tracked_objects::Location& from_here,
95    const base::Closure& task,
96    base::TimeDelta delay) {
97  NOTIMPLEMENTED();
98  return false;
99}
100
101}  // namespace test
102}  // namespace cast
103}  // namespace media
104