diff options
Diffstat (limited to 'chromium/content/browser/device_orientation/provider_unittest.cc')
-rw-r--r-- | chromium/content/browser/device_orientation/provider_unittest.cc | 591 |
1 files changed, 591 insertions, 0 deletions
diff --git a/chromium/content/browser/device_orientation/provider_unittest.cc b/chromium/content/browser/device_orientation/provider_unittest.cc new file mode 100644 index 00000000000..1f310ea3ad4 --- /dev/null +++ b/chromium/content/browser/device_orientation/provider_unittest.cc @@ -0,0 +1,591 @@ +// 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 <map> +#include <queue> + +#include "base/message_loop/message_loop.h" +#include "base/synchronization/lock.h" +#include "content/browser/device_orientation/data_fetcher.h" +#include "content/browser/device_orientation/device_data.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 content { +namespace { + +// Class for testing multiple types of device data. +class TestData : public DeviceData { + public: + TestData() + : value_(0) { + } + + // From DeviceData. + virtual IPC::Message* CreateIPCMessage(int render_view_id) const OVERRIDE { + NOTREACHED(); + return NULL; + } + virtual bool ShouldFireEvent(const DeviceData* old_data) const OVERRIDE { + return true; + } + + void set_value(double value) { value_ = value; } + double value() const { return value_; } + + private: + virtual ~TestData() { } + + double value_; +}; + +// Class for checking expectations on device_data updates from the Provider. +class UpdateChecker : public Provider::Observer { + public: + UpdateChecker(DeviceData::Type device_data_type, + int *expectations_count_ptr) + : Observer(device_data_type), + expectations_count_ptr_(expectations_count_ptr) { + } + virtual ~UpdateChecker() {} + + // From Provider::Observer. + virtual void OnDeviceDataUpdate(const DeviceData* device_data, + DeviceData::Type device_data_type) OVERRIDE = 0; + + void AddExpectation(const DeviceData* device_data) { + scoped_refptr<const DeviceData> expected_device_data(device_data); + expectations_queue_.push(expected_device_data); + ++(*expectations_count_ptr_); + } + + protected: + // Set up by the test fixture, which then blocks while it is accessed + // from OnDeviceDataUpdate which is executed on the test fixture's + // message_loop_. + int* expectations_count_ptr_; + std::queue<scoped_refptr<const DeviceData> > expectations_queue_; +}; + +// Class for checking expectations on orientation updates from the Provider. +class OrientationUpdateChecker : public UpdateChecker { + public: + explicit OrientationUpdateChecker(int* expectations_count_ptr) + : UpdateChecker(DeviceData::kTypeOrientation, expectations_count_ptr) { + } + + virtual ~OrientationUpdateChecker() {} + + // From UpdateChecker. + virtual void OnDeviceDataUpdate(const DeviceData* device_data, + DeviceData::Type device_data_type) OVERRIDE { + ASSERT_FALSE(expectations_queue_.empty()); + ASSERT_EQ(DeviceData::kTypeOrientation, device_data_type); + + scoped_refptr<const Orientation> orientation( + static_cast<const Orientation*>(device_data)); + if (orientation.get() == NULL) + orientation = new Orientation(); + + scoped_refptr<const Orientation> expected(static_cast<const Orientation*>( + (expectations_queue_.front().get()))); + 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()); + EXPECT_EQ(expected->can_provide_absolute(), + orientation->can_provide_absolute()); + 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()); + if (expected->can_provide_absolute()) + EXPECT_EQ(expected->absolute(), orientation->absolute()); + + --(*expectations_count_ptr_); + + if (*expectations_count_ptr_ == 0) { + base::MessageLoop::current()->PostTask(FROM_HERE, + base::MessageLoop::QuitClosure()); + } + } +}; + +// Class for checking expectations on test_data updates from the Provider. +class TestDataUpdateChecker : public UpdateChecker { + public: + explicit TestDataUpdateChecker(int* expectations_count_ptr) + : UpdateChecker(DeviceData::kTypeTest, expectations_count_ptr) { + } + + // From UpdateChecker. + virtual void OnDeviceDataUpdate(const DeviceData* device_data, + DeviceData::Type device_data_type) OVERRIDE { + ASSERT_FALSE(expectations_queue_.empty()); + ASSERT_EQ(DeviceData::kTypeTest, device_data_type); + + scoped_refptr<const TestData> test_data( + static_cast<const TestData*>(device_data)); + if (test_data.get() == NULL) + test_data = new TestData(); + + scoped_refptr<const TestData> expected(static_cast<const TestData*>( + (expectations_queue_.front().get()))); + expectations_queue_.pop(); + + EXPECT_EQ(expected->value(), test_data->value()); + + --(*expectations_count_ptr_); + + if (*expectations_count_ptr_ == 0) { + base::MessageLoop::current()->PostTask(FROM_HERE, + base::MessageLoop::QuitClosure()); + } + } +}; + +// Class for injecting test device data into the Provider. +class MockDeviceDataFactory + : public base::RefCountedThreadSafe<MockDeviceDataFactory> { + public: + MockDeviceDataFactory() + : is_failing_(false) { + } + + static void SetCurInstance(MockDeviceDataFactory* instance) { + if (instance) { + EXPECT_FALSE(instance_); + } + else { + EXPECT_TRUE(instance_); + } + instance_ = instance; + } + + static DataFetcher* CreateDataFetcher() { + EXPECT_TRUE(instance_); + return new MockDataFetcher(instance_); + } + + void SetDeviceData(const DeviceData* device_data, DeviceData::Type type) { + base::AutoLock auto_lock(lock_); + device_data_map_[type] = device_data; + } + + void SetFailing(bool is_failing) { + base::AutoLock auto_lock(lock_); + is_failing_ = is_failing; + } + + private: + friend class base::RefCountedThreadSafe<MockDeviceDataFactory>; + + ~MockDeviceDataFactory() { + } + + // Owned by ProviderImpl. Holds a reference back to MockDeviceDataFactory. + class MockDataFetcher : public DataFetcher { + public: + explicit MockDataFetcher(MockDeviceDataFactory* device_data_factory) + : device_data_factory_(device_data_factory) { } + + // From DataFetcher. Called by the Provider. + virtual const DeviceData* GetDeviceData( + DeviceData::Type device_data_type) OVERRIDE { + base::AutoLock auto_lock(device_data_factory_->lock_); + if (device_data_factory_->is_failing_) + return NULL; + return device_data_factory_->device_data_map_[device_data_type].get(); + } + + private: + scoped_refptr<MockDeviceDataFactory> device_data_factory_; + }; + + static MockDeviceDataFactory* instance_; + std::map<DeviceData::Type, scoped_refptr<const DeviceData> > device_data_map_; + bool is_failing_; + base::Lock lock_; +}; + +MockDeviceDataFactory* MockDeviceDataFactory::instance_; + +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 + // DataFetcherFactory factory. + void Init(ProviderImpl::DataFetcherFactory factory) { + provider_ = new ProviderImpl(factory); + Provider::SetInstanceForTests(provider_.get()); + } + + protected: + // Number of pending expectations. + int pending_expectations_; + + // Provider instance under test. + scoped_refptr<Provider> provider_; + + // Message loop for the test thread. + base::MessageLoop message_loop_; +}; + +TEST_F(DeviceOrientationProviderTest, FailingTest) { + scoped_refptr<MockDeviceDataFactory> device_data_factory( + new MockDeviceDataFactory()); + MockDeviceDataFactory::SetCurInstance(device_data_factory.get()); + Init(MockDeviceDataFactory::CreateDataFetcher); + + scoped_ptr<OrientationUpdateChecker> checker_a( + new OrientationUpdateChecker(&pending_expectations_)); + scoped_ptr<OrientationUpdateChecker> checker_b( + new OrientationUpdateChecker(&pending_expectations_)); + + checker_a->AddExpectation(new Orientation()); + provider_->AddObserver(checker_a.get()); + base::MessageLoop::current()->Run(); + + checker_b->AddExpectation(new Orientation()); + provider_->AddObserver(checker_b.get()); + base::MessageLoop::current()->Run(); + + MockDeviceDataFactory::SetCurInstance(NULL); +} + +TEST_F(DeviceOrientationProviderTest, ProviderIsSingleton) { + scoped_refptr<MockDeviceDataFactory> device_data_factory( + new MockDeviceDataFactory()); + MockDeviceDataFactory::SetCurInstance(device_data_factory.get()); + Init(MockDeviceDataFactory::CreateDataFetcher); + + scoped_refptr<Provider> provider_a(Provider::GetInstance()); + scoped_refptr<Provider> provider_b(Provider::GetInstance()); + + EXPECT_EQ(provider_a.get(), provider_b.get()); + MockDeviceDataFactory::SetCurInstance(NULL); +} + +TEST_F(DeviceOrientationProviderTest, BasicPushTest) { + scoped_refptr<MockDeviceDataFactory> device_data_factory( + new MockDeviceDataFactory()); + MockDeviceDataFactory::SetCurInstance(device_data_factory.get()); + Init(MockDeviceDataFactory::CreateDataFetcher); + scoped_refptr<Orientation> test_orientation(new Orientation()); + test_orientation->set_alpha(1); + test_orientation->set_beta(2); + test_orientation->set_gamma(3); + test_orientation->set_absolute(true); + + scoped_ptr<OrientationUpdateChecker> checker( + new OrientationUpdateChecker(&pending_expectations_)); + checker->AddExpectation(test_orientation.get()); + device_data_factory->SetDeviceData(test_orientation.get(), + DeviceData::kTypeOrientation); + provider_->AddObserver(checker.get()); + base::MessageLoop::current()->Run(); + + provider_->RemoveObserver(checker.get()); + MockDeviceDataFactory::SetCurInstance(NULL); +} + +// Tests multiple observers observing the same type of data. +TEST_F(DeviceOrientationProviderTest, MultipleObserversPushTest) { + scoped_refptr<MockDeviceDataFactory> device_data_factory( + new MockDeviceDataFactory()); + MockDeviceDataFactory::SetCurInstance(device_data_factory.get()); + Init(MockDeviceDataFactory::CreateDataFetcher); + + scoped_refptr<Orientation> test_orientations[] = {new Orientation(), + new Orientation(), new Orientation()}; + test_orientations[0]->set_alpha(1); + test_orientations[0]->set_beta(2); + test_orientations[0]->set_gamma(3); + test_orientations[0]->set_absolute(true); + + test_orientations[1]->set_alpha(4); + test_orientations[1]->set_beta(5); + test_orientations[1]->set_gamma(6); + test_orientations[1]->set_absolute(false); + + test_orientations[2]->set_alpha(7); + test_orientations[2]->set_beta(8); + test_orientations[2]->set_gamma(9); + // can't provide absolute + + scoped_ptr<OrientationUpdateChecker> checker_a( + new OrientationUpdateChecker(&pending_expectations_)); + scoped_ptr<OrientationUpdateChecker> checker_b( + new OrientationUpdateChecker(&pending_expectations_)); + scoped_ptr<OrientationUpdateChecker> checker_c( + new OrientationUpdateChecker(&pending_expectations_)); + + checker_a->AddExpectation(test_orientations[0].get()); + device_data_factory->SetDeviceData(test_orientations[0].get(), + DeviceData::kTypeOrientation); + provider_->AddObserver(checker_a.get()); + base::MessageLoop::current()->Run(); + + checker_a->AddExpectation(test_orientations[1].get()); + checker_b->AddExpectation(test_orientations[0].get()); + checker_b->AddExpectation(test_orientations[1].get()); + device_data_factory->SetDeviceData(test_orientations[1].get(), + DeviceData::kTypeOrientation); + provider_->AddObserver(checker_b.get()); + base::MessageLoop::current()->Run(); + + provider_->RemoveObserver(checker_a.get()); + checker_b->AddExpectation(test_orientations[2].get()); + checker_c->AddExpectation(test_orientations[1].get()); + checker_c->AddExpectation(test_orientations[2].get()); + device_data_factory->SetDeviceData(test_orientations[2].get(), + DeviceData::kTypeOrientation); + provider_->AddObserver(checker_c.get()); + base::MessageLoop::current()->Run(); + + provider_->RemoveObserver(checker_b.get()); + provider_->RemoveObserver(checker_c.get()); + MockDeviceDataFactory::SetCurInstance(NULL); +} + +// Test for when the fetcher cannot provide the first type of data but can +// provide the second type. +TEST_F(DeviceOrientationProviderTest, FailingFirstDataTypeTest) { + + scoped_refptr<MockDeviceDataFactory> device_data_factory( + new MockDeviceDataFactory()); + MockDeviceDataFactory::SetCurInstance(device_data_factory.get()); + Init(MockDeviceDataFactory::CreateDataFetcher); + + scoped_ptr<TestDataUpdateChecker> test_data_checker( + new TestDataUpdateChecker(&pending_expectations_)); + scoped_ptr<OrientationUpdateChecker> orientation_checker( + new OrientationUpdateChecker(&pending_expectations_)); + + scoped_refptr<Orientation> test_orientation(new Orientation()); + test_orientation->set_alpha(1); + test_orientation->set_beta(2); + test_orientation->set_gamma(3); + test_orientation->set_absolute(true); + + test_data_checker->AddExpectation(new TestData()); + provider_->AddObserver(test_data_checker.get()); + base::MessageLoop::current()->Run(); + + orientation_checker->AddExpectation(test_orientation.get()); + device_data_factory->SetDeviceData(test_orientation.get(), + DeviceData::kTypeOrientation); + provider_->AddObserver(orientation_checker.get()); + base::MessageLoop::current()->Run(); + + provider_->RemoveObserver(test_data_checker.get()); + provider_->RemoveObserver(orientation_checker.get()); + MockDeviceDataFactory::SetCurInstance(NULL); +} + +#if defined(OS_LINUX) || defined(OS_WIN) +// Flakily DCHECKs on Linux. See crbug.com/104950. +// FLAKY on Win. See crbug.com/104950. +#define MAYBE_ObserverNotRemoved DISABLED_ObserverNotRemoved +#else +#define MAYBE_ObserverNotRemoved ObserverNotRemoved +#endif +TEST_F(DeviceOrientationProviderTest, MAYBE_ObserverNotRemoved) { + scoped_refptr<MockDeviceDataFactory> device_data_factory( + new MockDeviceDataFactory()); + MockDeviceDataFactory::SetCurInstance(device_data_factory.get()); + Init(MockDeviceDataFactory::CreateDataFetcher); + scoped_refptr<Orientation> test_orientation(new Orientation()); + test_orientation->set_alpha(1); + test_orientation->set_beta(2); + test_orientation->set_gamma(3); + test_orientation->set_absolute(true); + + scoped_refptr<Orientation> test_orientation2(new Orientation()); + test_orientation2->set_alpha(4); + test_orientation2->set_beta(5); + test_orientation2->set_gamma(6); + test_orientation2->set_absolute(false); + + scoped_ptr<OrientationUpdateChecker> checker( + new OrientationUpdateChecker(&pending_expectations_)); + checker->AddExpectation(test_orientation.get()); + device_data_factory->SetDeviceData(test_orientation.get(), + DeviceData::kTypeOrientation); + provider_->AddObserver(checker.get()); + base::MessageLoop::current()->Run(); + + checker->AddExpectation(test_orientation2.get()); + device_data_factory->SetDeviceData(test_orientation2.get(), + DeviceData::kTypeOrientation); + base::MessageLoop::current()->Run(); + + MockDeviceDataFactory::SetCurInstance(NULL); + + // Note that checker is not removed. This should not be a problem. +} + +#if defined(OS_WIN) +// FLAKY on Win. See crbug.com/104950. +#define MAYBE_StartFailing DISABLED_StartFailing +#else +#define MAYBE_StartFailing StartFailing +#endif +TEST_F(DeviceOrientationProviderTest, MAYBE_StartFailing) { + scoped_refptr<MockDeviceDataFactory> device_data_factory( + new MockDeviceDataFactory()); + MockDeviceDataFactory::SetCurInstance(device_data_factory.get()); + Init(MockDeviceDataFactory::CreateDataFetcher); + scoped_refptr<Orientation> test_orientation(new Orientation()); + test_orientation->set_alpha(1); + test_orientation->set_beta(2); + test_orientation->set_gamma(3); + test_orientation->set_absolute(true); + + scoped_ptr<OrientationUpdateChecker> checker_a(new OrientationUpdateChecker( + &pending_expectations_)); + scoped_ptr<OrientationUpdateChecker> checker_b(new OrientationUpdateChecker( + &pending_expectations_)); + + device_data_factory->SetDeviceData(test_orientation.get(), + DeviceData::kTypeOrientation); + checker_a->AddExpectation(test_orientation.get()); + provider_->AddObserver(checker_a.get()); + base::MessageLoop::current()->Run(); + + checker_a->AddExpectation(new Orientation()); + device_data_factory->SetFailing(true); + base::MessageLoop::current()->Run(); + + checker_b->AddExpectation(new Orientation()); + provider_->AddObserver(checker_b.get()); + base::MessageLoop::current()->Run(); + + provider_->RemoveObserver(checker_a.get()); + provider_->RemoveObserver(checker_b.get()); + MockDeviceDataFactory::SetCurInstance(NULL); +} + +TEST_F(DeviceOrientationProviderTest, StartStopStart) { + scoped_refptr<MockDeviceDataFactory> device_data_factory( + new MockDeviceDataFactory()); + MockDeviceDataFactory::SetCurInstance(device_data_factory.get()); + Init(MockDeviceDataFactory::CreateDataFetcher); + + scoped_refptr<Orientation> test_orientation(new Orientation()); + test_orientation->set_alpha(1); + test_orientation->set_beta(2); + test_orientation->set_gamma(3); + test_orientation->set_absolute(true); + + scoped_refptr<Orientation> test_orientation2(new Orientation()); + test_orientation2->set_alpha(4); + test_orientation2->set_beta(5); + test_orientation2->set_gamma(6); + test_orientation2->set_absolute(false); + + scoped_ptr<OrientationUpdateChecker> checker_a(new OrientationUpdateChecker( + &pending_expectations_)); + scoped_ptr<OrientationUpdateChecker> checker_b(new OrientationUpdateChecker( + &pending_expectations_)); + + checker_a->AddExpectation(test_orientation.get()); + device_data_factory->SetDeviceData(test_orientation.get(), + DeviceData::kTypeOrientation); + provider_->AddObserver(checker_a.get()); + base::MessageLoop::current()->Run(); + + provider_->RemoveObserver(checker_a.get()); // This stops the Provider. + + checker_b->AddExpectation(test_orientation2.get()); + device_data_factory->SetDeviceData(test_orientation2.get(), + DeviceData::kTypeOrientation); + provider_->AddObserver(checker_b.get()); + base::MessageLoop::current()->Run(); + + provider_->RemoveObserver(checker_b.get()); + MockDeviceDataFactory::SetCurInstance(NULL); +} + +// Tests that Orientation events only fire if the change is significant. +TEST_F(DeviceOrientationProviderTest, OrientationSignificantlyDifferent) { + scoped_refptr<MockDeviceDataFactory> device_data_factory( + new MockDeviceDataFactory()); + MockDeviceDataFactory::SetCurInstance(device_data_factory.get()); + Init(MockDeviceDataFactory::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; + + scoped_refptr<Orientation> first_orientation(new Orientation()); + first_orientation->set_alpha(kAlpha); + first_orientation->set_beta(kBeta); + first_orientation->set_gamma(kGamma); + first_orientation->set_absolute(true); + + scoped_refptr<Orientation> second_orientation(new Orientation()); + second_orientation->set_alpha(kAlpha + kInsignificantDifference); + second_orientation->set_beta(kBeta + kInsignificantDifference); + second_orientation->set_gamma(kGamma + kInsignificantDifference); + second_orientation->set_absolute(false); + + scoped_refptr<Orientation> third_orientation(new Orientation()); + third_orientation->set_alpha(kAlpha + kSignificantDifference); + third_orientation->set_beta(kBeta + kSignificantDifference); + third_orientation->set_gamma(kGamma + kSignificantDifference); + // can't provide absolute + + scoped_ptr<OrientationUpdateChecker> checker_a(new OrientationUpdateChecker( + &pending_expectations_)); + scoped_ptr<OrientationUpdateChecker> checker_b(new OrientationUpdateChecker( + &pending_expectations_)); + + device_data_factory->SetDeviceData(first_orientation.get(), + DeviceData::kTypeOrientation); + checker_a->AddExpectation(first_orientation.get()); + provider_->AddObserver(checker_a.get()); + base::MessageLoop::current()->Run(); + + // The observers should not see this insignificantly different orientation. + device_data_factory->SetDeviceData(second_orientation.get(), + DeviceData::kTypeOrientation); + checker_b->AddExpectation(first_orientation.get()); + provider_->AddObserver(checker_b.get()); + base::MessageLoop::current()->Run(); + + device_data_factory->SetDeviceData(third_orientation.get(), + DeviceData::kTypeOrientation); + checker_a->AddExpectation(third_orientation.get()); + checker_b->AddExpectation(third_orientation.get()); + base::MessageLoop::current()->Run(); + + provider_->RemoveObserver(checker_a.get()); + provider_->RemoveObserver(checker_b.get()); + MockDeviceDataFactory::SetCurInstance(NULL); +} + +} // namespace + +} // namespace content |