Index: base/test/sequenced_task_runner_test_template.cc |
=================================================================== |
--- base/test/sequenced_task_runner_test_template.cc (revision 0) |
+++ base/test/sequenced_task_runner_test_template.cc (revision 0) |
@@ -0,0 +1,263 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/test/sequenced_task_runner_test_template.h" |
+ |
+#include <ostream> |
+ |
+#include "base/location.h" |
+ |
+namespace base { |
+ |
+namespace internal { |
+ |
+TaskEvent::TaskEvent(int i, Type type) |
+ : i(i), type(type) { |
+} |
+ |
+SequencedTaskTracker::SequencedTaskTracker() : next_post_i_(0) { |
+} |
+ |
+void SequencedTaskTracker::PostWrappedNonNestableTask( |
+ const scoped_refptr<SequencedTaskRunner>& task_runner, |
+ const Closure& task) { |
+ AutoLock event_lock(lock_); |
+ const int post_i = next_post_i_++; |
+ Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this, |
+ task, post_i); |
+ task_runner->PostNonNestableTask(FROM_HERE, wrapped_task); |
+ TaskPosted(post_i); |
+} |
+ |
+void SequencedTaskTracker::PostWrappedNestableTask( |
+ const scoped_refptr<SequencedTaskRunner>& task_runner, |
+ const Closure& task) { |
+ AutoLock event_lock(lock_); |
+ const int post_i = next_post_i_++; |
+ Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this, |
+ task, post_i); |
+ task_runner->PostTask(FROM_HERE, wrapped_task); |
+ TaskPosted(post_i); |
+} |
+ |
+void SequencedTaskTracker::PostWrappedDelayedNonNestableTask( |
+ const scoped_refptr<SequencedTaskRunner>& task_runner, |
+ const Closure& task, |
+ TimeDelta delay) { |
+ AutoLock event_lock(lock_); |
+ const int post_i = next_post_i_++; |
+ Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this, |
+ task, post_i); |
+ task_runner->PostNonNestableDelayedTask(FROM_HERE, wrapped_task, delay); |
+ TaskPosted(post_i); |
+} |
+ |
+void SequencedTaskTracker::PostNonNestableTasks( |
+ const scoped_refptr<SequencedTaskRunner>& task_runner, |
+ int task_count) { |
+ for (int i = 0; i < task_count; ++i) { |
+ PostWrappedNonNestableTask(task_runner, Closure()); |
+ } |
+} |
+ |
+void SequencedTaskTracker::RunTask(const Closure& task, int task_i) { |
+ TaskStarted(task_i); |
+ if (!task.is_null()) |
+ task.Run(); |
+ TaskEnded(task_i); |
+} |
+ |
+void SequencedTaskTracker::TaskPosted(int i) { |
+ // Caller must own |lock_|. |
+ events_.push_back(TaskEvent(i, TaskEvent::POST)); |
+} |
+ |
+void SequencedTaskTracker::TaskStarted(int i) { |
+ AutoLock lock(lock_); |
+ events_.push_back(TaskEvent(i, TaskEvent::START)); |
+} |
+ |
+void SequencedTaskTracker::TaskEnded(int i) { |
+ AutoLock lock(lock_); |
+ events_.push_back(TaskEvent(i, TaskEvent::END)); |
+} |
+ |
+const std::vector<TaskEvent>& |
+SequencedTaskTracker::GetTaskEvents() const { |
+ return events_; |
+} |
+ |
+SequencedTaskTracker::~SequencedTaskTracker() { |
+} |
+ |
+void PrintTo(const TaskEvent& event, std::ostream* os) { |
+ *os << "(i=" << event.i << ", type="; |
+ switch (event.type) { |
+ case TaskEvent::POST: *os << "POST"; break; |
+ case TaskEvent::START: *os << "START"; break; |
+ case TaskEvent::END: *os << "END"; break; |
+ } |
+ *os << ")"; |
+} |
+ |
+void SleepForOneSecond() { |
+ base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); |
+} |
+ |
+namespace { |
+ |
+// Returns the task ordinals for the task event type |type| in the order that |
+// they were recorded. |
+std::vector<int> GetEventTypeOrder(const std::vector<TaskEvent>& events, |
+ TaskEvent::Type type) { |
+ std::vector<int> tasks; |
+ std::vector<TaskEvent>::const_iterator event; |
+ for (event = events.begin(); event != events.end(); ++event) { |
+ if (event->type == type) |
+ tasks.push_back(event->i); |
+ } |
+ return tasks; |
+} |
+ |
+// Returns all task events for task |task_i|. |
+std::vector<TaskEvent::Type> GetEventsForTask( |
+ const std::vector<TaskEvent>& events, |
+ int task_i) { |
+ std::vector<TaskEvent::Type> task_event_orders; |
+ std::vector<TaskEvent>::const_iterator event; |
+ for (event = events.begin(); event != events.end(); ++event) { |
+ if (event->i == task_i) |
+ task_event_orders.push_back(event->type); |
+ } |
+ return task_event_orders; |
+} |
+ |
+// Checks that the task events for each task in |events| occur in the order |
+// {POST, START, END}, and that there is only one instance of each event type |
+// per task. |
+::testing::AssertionResult CheckEventOrdersForEachTask( |
+ const std::vector<TaskEvent>& events, |
+ int task_count) { |
+ std::vector<TaskEvent::Type> expected_order; |
+ expected_order.push_back(TaskEvent::POST); |
+ expected_order.push_back(TaskEvent::START); |
+ expected_order.push_back(TaskEvent::END); |
+ |
+ // This is O(n^2), but it runs fast enough currently so is not worth |
+ // optimizing. |
+ for (int i = 0; i < task_count; ++i) { |
+ const std::vector<TaskEvent::Type> task_events = |
+ GetEventsForTask(events, i); |
+ if (task_events != expected_order) { |
+ return ::testing::AssertionFailure() |
+ << "Events for task " << i << " are out of order; expected: " |
+ << ::testing::PrintToString(expected_order) << "; actual: " |
+ << ::testing::PrintToString(task_events); |
+ } |
+ } |
+ return ::testing::AssertionSuccess(); |
+} |
+ |
+// Checks that no two tasks were running at the same time. I.e. the only |
+// events allowed between the START and END of a task are the POSTs of other |
+// tasks. |
+::testing::AssertionResult CheckNoTaskRunsOverlap( |
+ const std::vector<TaskEvent>& events) { |
+ // If > -1, we're currently inside a START, END pair. |
+ int current_task_i = -1; |
+ |
+ std::vector<TaskEvent>::const_iterator event; |
+ for (event = events.begin(); event != events.end(); ++event) { |
+ bool spurious_event_found = false; |
+ |
+ if (current_task_i == -1) { // Not inside a START, END pair. |
+ switch (event->type) { |
+ case TaskEvent::POST: |
+ break; |
+ case TaskEvent::START: |
+ current_task_i = event->i; |
+ break; |
+ case TaskEvent::END: |
+ spurious_event_found = true; |
+ break; |
+ } |
+ |
+ } else { // Inside a START, END pair. |
+ bool interleaved_task_detected = false; |
+ |
+ switch (event->type) { |
+ case TaskEvent::POST: |
+ if (event->i == current_task_i) |
+ spurious_event_found = true; |
+ break; |
+ case TaskEvent::START: |
+ interleaved_task_detected = true; |
+ break; |
+ case TaskEvent::END: |
+ if (event->i != current_task_i) |
+ interleaved_task_detected = true; |
+ else |
+ current_task_i = -1; |
+ break; |
+ } |
+ |
+ if (interleaved_task_detected) { |
+ return ::testing::AssertionFailure() |
+ << "Found event " << ::testing::PrintToString(*event) |
+ << " between START and END events for task " << current_task_i |
+ << "; event dump: " << ::testing::PrintToString(events); |
+ } |
+ } |
+ |
+ if (spurious_event_found) { |
+ const int event_i = event - events.begin(); |
+ return ::testing::AssertionFailure() |
+ << "Spurious event " << ::testing::PrintToString(*event) |
+ << " at position " << event_i << "; event dump: " |
+ << ::testing::PrintToString(events); |
+ } |
+ } |
+ |
+ return ::testing::AssertionSuccess(); |
+} |
+ |
+} // namespace |
+ |
+::testing::AssertionResult CheckNonNestableInvariants( |
+ const std::vector<TaskEvent>& events, |
+ int task_count) { |
+ const std::vector<int> post_order = |
+ GetEventTypeOrder(events, TaskEvent::POST); |
+ const std::vector<int> start_order = |
+ GetEventTypeOrder(events, TaskEvent::START); |
+ const std::vector<int> end_order = |
+ GetEventTypeOrder(events, TaskEvent::END); |
+ |
+ if (start_order != post_order) { |
+ return ::testing::AssertionFailure() |
+ << "Expected START order (which equals actual POST order): \n" |
+ << ::testing::PrintToString(post_order) |
+ << "\n Actual START order:\n" |
+ << ::testing::PrintToString(start_order); |
+ } |
+ |
+ if (end_order != post_order) { |
+ return ::testing::AssertionFailure() |
+ << "Expected END order (which equals actual POST order): \n" |
+ << ::testing::PrintToString(post_order) |
+ << "\n Actual END order:\n" |
+ << ::testing::PrintToString(end_order); |
+ } |
+ |
+ const ::testing::AssertionResult result = |
+ CheckEventOrdersForEachTask(events, task_count); |
+ if (!result) |
+ return result; |
+ |
+ return CheckNoTaskRunsOverlap(events); |
+} |
+ |
+} // namespace internal |
+ |
+} // namespace base |
Property changes on: base/test/sequenced_task_runner_test_template.cc |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |