blob: d991d5ad360327727a2fede877e432232ce864cc [file] [log] [blame]
// Copyright (c) 2011 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 <queue>
#include "base/message_loop.h"
#include "base/synchronization/lock.h"
#include "base/task.h"
#include "content/browser/device_orientation/data_fetcher.h"
#include "content/browser/device_orientation/orientation.h"
#include "content/browser/device_orientation/provider.h"
#include "content/browser/device_orientation/provider_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace device_orientation {
namespace {
// Class for checking expectations on orientation updates from the Provider.
class UpdateChecker : public Provider::Observer {
public:
explicit UpdateChecker(int* expectations_count_ptr)
: expectations_count_ptr_(expectations_count_ptr) {
}
virtual ~UpdateChecker() {}
// From Provider::Observer.
virtual void OnOrientationUpdate(const Orientation& orientation) {
ASSERT_FALSE(expectations_queue_.empty());
Orientation expected = expectations_queue_.front();
expectations_queue_.pop();
EXPECT_EQ(expected.can_provide_alpha_, orientation.can_provide_alpha_);
EXPECT_EQ(expected.can_provide_beta_, orientation.can_provide_beta_);
EXPECT_EQ(expected.can_provide_gamma_, orientation.can_provide_gamma_);
if (expected.can_provide_alpha_)
EXPECT_EQ(expected.alpha_, orientation.alpha_);
if (expected.can_provide_beta_)
EXPECT_EQ(expected.beta_, orientation.beta_);
if (expected.can_provide_gamma_)
EXPECT_EQ(expected.gamma_, orientation.gamma_);
--(*expectations_count_ptr_);
if (*expectations_count_ptr_ == 0) {
MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
}
}
void AddExpectation(const Orientation& orientation) {
expectations_queue_.push(orientation);
++(*expectations_count_ptr_);
}
private:
// Set up by the test fixture, which then blocks while it is accessed
// from OnOrientationUpdate which is executed on the test fixture's
// message_loop_.
int* expectations_count_ptr_;
std::queue<Orientation> expectations_queue_;
};
// Class for injecting test orientation data into the Provider.
class MockOrientationFactory : public base::RefCounted<MockOrientationFactory> {
public:
MockOrientationFactory() {
EXPECT_FALSE(instance_);
instance_ = this;
}
~MockOrientationFactory() {
instance_ = NULL;
}
static DataFetcher* CreateDataFetcher() {
EXPECT_TRUE(instance_);
return new MockDataFetcher(instance_);
}
void SetOrientation(const Orientation& orientation) {
base::AutoLock auto_lock(lock_);
orientation_ = orientation;
}
private:
// Owned by ProviderImpl. Holds a reference back to MockOrientationFactory.
class MockDataFetcher : public DataFetcher {
public:
explicit MockDataFetcher(MockOrientationFactory* orientation_factory)
: orientation_factory_(orientation_factory) { }
// From DataFetcher. Called by the Provider.
virtual bool GetOrientation(Orientation* orientation) {
base::AutoLock auto_lock(orientation_factory_->lock_);
*orientation = orientation_factory_->orientation_;
return true;
}
private:
scoped_refptr<MockOrientationFactory> orientation_factory_;
};
static MockOrientationFactory* instance_;
Orientation orientation_;
base::Lock lock_;
};
MockOrientationFactory* MockOrientationFactory::instance_;
// Mock DataFetcher that always fails to provide any orientation data.
class FailingDataFetcher : public DataFetcher {
public:
// Factory method; passed to and called by the ProviderImpl.
static DataFetcher* Create() {
return new FailingDataFetcher();
}
// From DataFetcher.
virtual bool GetOrientation(Orientation* orientation) {
return false;
}
private:
FailingDataFetcher() {}
};
class DeviceOrientationProviderTest : public testing::Test {
public:
DeviceOrientationProviderTest()
: pending_expectations_(0) {
}
virtual void TearDown() {
provider_ = NULL;
// Make sure it is really gone.
EXPECT_FALSE(Provider::GetInstanceForTests());
// Clean up in any case, so as to not break subsequent test.
Provider::SetInstanceForTests(NULL);
}
// Initialize the test fixture with a ProviderImpl that uses the
// DataFetcherFactories in the null-terminated factories array.
void Init(ProviderImpl::DataFetcherFactory* factories) {
provider_ = new ProviderImpl(factories);
Provider::SetInstanceForTests(provider_);
}
// Initialize the test fixture with a ProviderImpl that uses the
// DataFetcherFactory factory.
void Init(ProviderImpl::DataFetcherFactory factory) {
ProviderImpl::DataFetcherFactory factories[] = { factory, NULL };
Init(factories);
}
protected:
// Number of pending expectations.
int pending_expectations_;
// Provider instance under test.
scoped_refptr<Provider> provider_;
// Message loop for the test thread.
MessageLoop message_loop_;
};
TEST_F(DeviceOrientationProviderTest, FailingTest) {
Init(FailingDataFetcher::Create);
scoped_ptr<UpdateChecker> checker_a(
new UpdateChecker(&pending_expectations_));
scoped_ptr<UpdateChecker> checker_b(
new UpdateChecker(&pending_expectations_));
checker_a->AddExpectation(Orientation::Empty());
provider_->AddObserver(checker_a.get());
MessageLoop::current()->Run();
checker_b->AddExpectation(Orientation::Empty());
provider_->AddObserver(checker_b.get());
MessageLoop::current()->Run();
}
TEST_F(DeviceOrientationProviderTest, ProviderIsSingleton) {
Init(FailingDataFetcher::Create);
scoped_refptr<Provider> provider_a(Provider::GetInstance());
scoped_refptr<Provider> provider_b(Provider::GetInstance());
EXPECT_EQ(provider_a.get(), provider_b.get());
}
TEST_F(DeviceOrientationProviderTest, BasicPushTest) {
scoped_refptr<MockOrientationFactory> orientation_factory(
new MockOrientationFactory());
Init(MockOrientationFactory::CreateDataFetcher);
const Orientation kTestOrientation(true, 1, true, 2, true, 3);
scoped_ptr<UpdateChecker> checker(new UpdateChecker(&pending_expectations_));
checker->AddExpectation(kTestOrientation);
orientation_factory->SetOrientation(kTestOrientation);
provider_->AddObserver(checker.get());
MessageLoop::current()->Run();
provider_->RemoveObserver(checker.get());
}
TEST_F(DeviceOrientationProviderTest, MultipleObserversPushTest) {
scoped_refptr<MockOrientationFactory> orientation_factory(
new MockOrientationFactory());
Init(MockOrientationFactory::CreateDataFetcher);
const Orientation kTestOrientations[] = {
Orientation(true, 1, true, 2, true, 3),
Orientation(true, 4, true, 5, true, 6),
Orientation(true, 7, true, 8, true, 9)};
scoped_ptr<UpdateChecker> checker_a(
new UpdateChecker(&pending_expectations_));
scoped_ptr<UpdateChecker> checker_b(
new UpdateChecker(&pending_expectations_));
scoped_ptr<UpdateChecker> checker_c(
new UpdateChecker(&pending_expectations_));
checker_a->AddExpectation(kTestOrientations[0]);
orientation_factory->SetOrientation(kTestOrientations[0]);
provider_->AddObserver(checker_a.get());
MessageLoop::current()->Run();
checker_a->AddExpectation(kTestOrientations[1]);
checker_b->AddExpectation(kTestOrientations[0]);
checker_b->AddExpectation(kTestOrientations[1]);
orientation_factory->SetOrientation(kTestOrientations[1]);
provider_->AddObserver(checker_b.get());
MessageLoop::current()->Run();
provider_->RemoveObserver(checker_a.get());
checker_b->AddExpectation(kTestOrientations[2]);
checker_c->AddExpectation(kTestOrientations[1]);
checker_c->AddExpectation(kTestOrientations[2]);
orientation_factory->SetOrientation(kTestOrientations[2]);
provider_->AddObserver(checker_c.get());
MessageLoop::current()->Run();
provider_->RemoveObserver(checker_b.get());
provider_->RemoveObserver(checker_c.get());
}
TEST_F(DeviceOrientationProviderTest, ObserverNotRemoved) {
scoped_refptr<MockOrientationFactory> orientation_factory(
new MockOrientationFactory());
Init(MockOrientationFactory::CreateDataFetcher);
const Orientation kTestOrientation(true, 1, true, 2, true, 3);
const Orientation kTestOrientation2(true, 4, true, 5, true, 6);
scoped_ptr<UpdateChecker> checker(new UpdateChecker(&pending_expectations_));
checker->AddExpectation(kTestOrientation);
orientation_factory->SetOrientation(kTestOrientation);
provider_->AddObserver(checker.get());
MessageLoop::current()->Run();
checker->AddExpectation(kTestOrientation2);
orientation_factory->SetOrientation(kTestOrientation2);
MessageLoop::current()->Run();
// Note that checker is not removed. This should not be a problem.
}
TEST_F(DeviceOrientationProviderTest, StartFailing) {
scoped_refptr<MockOrientationFactory> orientation_factory(
new MockOrientationFactory());
Init(MockOrientationFactory::CreateDataFetcher);
const Orientation kTestOrientation(true, 1, true, 2, true, 3);
scoped_ptr<UpdateChecker> checker_a(new UpdateChecker(
&pending_expectations_));
scoped_ptr<UpdateChecker> checker_b(new UpdateChecker(
&pending_expectations_));
orientation_factory->SetOrientation(kTestOrientation);
checker_a->AddExpectation(kTestOrientation);
provider_->AddObserver(checker_a.get());
MessageLoop::current()->Run();
checker_a->AddExpectation(Orientation::Empty());
orientation_factory->SetOrientation(Orientation::Empty());
MessageLoop::current()->Run();
checker_b->AddExpectation(Orientation::Empty());
provider_->AddObserver(checker_b.get());
MessageLoop::current()->Run();
provider_->RemoveObserver(checker_a.get());
provider_->RemoveObserver(checker_b.get());
}
TEST_F(DeviceOrientationProviderTest, StartStopStart) {
scoped_refptr<MockOrientationFactory> orientation_factory(
new MockOrientationFactory());
Init(MockOrientationFactory::CreateDataFetcher);
const Orientation kTestOrientation(true, 1, true, 2, true, 3);
const Orientation kTestOrientation2(true, 4, true, 5, true, 6);
scoped_ptr<UpdateChecker> checker_a(new UpdateChecker(
&pending_expectations_));
scoped_ptr<UpdateChecker> checker_b(new UpdateChecker(
&pending_expectations_));
checker_a->AddExpectation(kTestOrientation);
orientation_factory->SetOrientation(kTestOrientation);
provider_->AddObserver(checker_a.get());
MessageLoop::current()->Run();
provider_->RemoveObserver(checker_a.get()); // This stops the Provider.
checker_b->AddExpectation(kTestOrientation2);
orientation_factory->SetOrientation(kTestOrientation2);
provider_->AddObserver(checker_b.get());
MessageLoop::current()->Run();
provider_->RemoveObserver(checker_b.get());
}
TEST_F(DeviceOrientationProviderTest, SignificantlyDifferent) {
scoped_refptr<MockOrientationFactory> orientation_factory(
new MockOrientationFactory());
Init(MockOrientationFactory::CreateDataFetcher);
// Values that should be well below or above the implementation's
// significane threshold.
const double kInsignificantDifference = 1e-6;
const double kSignificantDifference = 30;
const double kAlpha = 4, kBeta = 5, kGamma = 6;
const Orientation first_orientation(true, kAlpha, true, kBeta, true, kGamma);
const Orientation second_orientation(true, kAlpha + kInsignificantDifference,
true, kBeta + kInsignificantDifference,
true, kGamma + kInsignificantDifference);
const Orientation third_orientation(true, kAlpha + kSignificantDifference,
true, kBeta + kSignificantDifference,
true, kGamma + kSignificantDifference);
scoped_ptr<UpdateChecker> checker_a(new UpdateChecker(
&pending_expectations_));
scoped_ptr<UpdateChecker> checker_b(new UpdateChecker(
&pending_expectations_));
orientation_factory->SetOrientation(first_orientation);
checker_a->AddExpectation(first_orientation);
provider_->AddObserver(checker_a.get());
MessageLoop::current()->Run();
// The observers should not see this insignificantly different orientation.
orientation_factory->SetOrientation(second_orientation);
checker_b->AddExpectation(first_orientation);
provider_->AddObserver(checker_b.get());
MessageLoop::current()->Run();
orientation_factory->SetOrientation(third_orientation);
checker_a->AddExpectation(third_orientation);
checker_b->AddExpectation(third_orientation);
MessageLoop::current()->Run();
provider_->RemoveObserver(checker_a.get());
provider_->RemoveObserver(checker_b.get());
}
} // namespace
} // namespace device_orientation