blob: cb6e0de7f64415518b4e701316d0813d8fea11fc [file] [log] [blame]
// Copyright (c) 2009 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.
// This file provides some utility classes that help with testing APIs which use
// callbacks.
//
// -- InvokeRunnable --
// The InvokeRunnable is an action that can be used a gMock mock object to
// invoke the Run() method on mock argument. Example:
//
// class MockFoo : public Foo {
// public:
// MOCK_METHOD0(DoSomething, void(Task* done_cb));
// };
//
// EXPECT_CALL(foo, DoSomething(_)).WillOnce(WithArg<0>(InvokeRunnable()));
//
// Then you pass "foo" to something that will eventually call DoSomething().
// The mock action will ensure that passed in done_cb is invoked.
//
//
// -- TaskMocker --
// The TaskMocker class lets you create mock callbacks. Callbacks are
// difficult to mock because ownership of the callback object is often passed
// to the funciton being invoked. TaskMocker solves this by providing a
// GetTask() function that creates a new, single-use task that delegates to
// the originating TaskMocker object. Expectations are placed on the
// originating TaskMocker object. Each callback retrieved by GetTask() is
// tracked to ensure that it is properly deleted. The TaskMocker expects to
// outlive all the callbacks retrieved by GetTask().
//
// Example:
//
// TaskMocker done_cb;
// EXPECT_CALL(done_cb, Run()).Times(3);
//
// func1(done_cb.GetTask());
// func2(done_cb.GetTask());
// func3(done_cb.GetTask());
//
// // All 3 callbacks from GetTask() should be deleted before done_cb goes out
// // of scope.
//
// This class is not threadsafe.
//
// TODO(ajwong): Is it even worth bothering with gmock here?
// TODO(ajwong): Move MockFilterCallback here and merge the implementation
// differences.
#ifndef MEDIA_BASE_MOCK_TASK_H_
#define MEDIA_BASE_MOCK_TASK_H_
#include "base/task.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace media {
ACTION(InvokeRunnable) {
arg0->Run();
delete arg0;
}
class TaskMocker {
public:
TaskMocker()
: outstanding_tasks_(0) {
}
~TaskMocker() {
CHECK(outstanding_tasks_ == 0)
<< "If outstanding_tasks_ is not zero, tasks have been leaked.";
}
Task* CreateTask() {
return new CountingTask(this);
}
MOCK_METHOD0(Run, void());
private:
friend class CountingTask;
class CountingTask : public Task {
public:
CountingTask(TaskMocker* origin)
: origin_(origin) {
origin_->outstanding_tasks_++;
}
virtual void Run() {
origin_->Run();
}
virtual ~CountingTask() {
origin_->outstanding_tasks_--;
}
private:
TaskMocker* origin_;
DISALLOW_COPY_AND_ASSIGN(CountingTask);
};
int outstanding_tasks_;
DISALLOW_COPY_AND_ASSIGN(TaskMocker);
};
} // namespace media
#endif //MEDIA_BASE_MOCK_TASK_H_