Index: chrome/browser/device_orientation/provider_unittest.cc |
diff --git a/chrome/browser/device_orientation/provider_unittest.cc b/chrome/browser/device_orientation/provider_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cadc1748fa17d2bcc6f3dd7163f300470b2bcd46 |
--- /dev/null |
+++ b/chrome/browser/device_orientation/provider_unittest.cc |
@@ -0,0 +1,369 @@ |
+// Copyright (c) 2010 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/lock.h" |
+#include "base/message_loop.h" |
+#include "base/task.h" |
+#include "chrome/browser/device_orientation/data_fetcher.h" |
+#include "chrome/browser/device_orientation/orientation.h" |
+#include "chrome/browser/device_orientation/provider.h" |
+#include "chrome/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) { |
+ } |
+ |
+ // 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) { |
+ 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) { |
+ AutoLock auto_lock(orientation_factory_->lock_); |
+ *orientation = orientation_factory_->orientation_; |
+ return true; |
+ } |
+ |
+ private: |
+ scoped_refptr<MockOrientationFactory> orientation_factory_; |
+ }; |
+ |
+ static MockOrientationFactory* instance_; |
+ Orientation orientation_; |
+ 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() { |
+ } |
+ |
+ // 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(&message_loop_, 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); |
+ } |
+ |
+ void ScheduleAddObserver(Provider::Observer* observer) { |
+ Task* task = NewRunnableMethod(provider_.get(), &Provider::AddObserver, |
+ observer); |
+ message_loop_.PostTask(FROM_HERE, task); |
+ } |
+ |
+ void RemoveObserver(Provider::Observer* observer) { |
+ Task* task = NewRunnableMethod(provider_.get(), &Provider::RemoveObserver, |
+ observer); |
+ message_loop_.PostTask(FROM_HERE, task); |
+ message_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask()); |
+ message_loop_.Run(); |
+ } |
+ |
+ MessageLoop* message_loop() { |
+ return &message_loop_; |
+ } |
+ |
+ private: |
+ // Provider instance under test. |
+ scoped_refptr<Provider> provider_; |
+ |
+ // Message loop for adding or removing observers of the provider, and |
+ // receiving orientation updates. In non-test situations, this would |
+ // be the message loop of the IO thread. |
+ MessageLoop message_loop_; |
+}; |
+ |
+TEST_F(DeviceOrientationProviderTest, FailingTest) { |
+ Init(FailingDataFetcher::Create); |
+ int expectations_count = 0; |
+ |
+ scoped_ptr<UpdateChecker> checker_a(new UpdateChecker(&expectations_count)); |
+ scoped_ptr<UpdateChecker> checker_b(new UpdateChecker(&expectations_count)); |
+ |
+ checker_a->AddExpectation(Orientation::Empty()); |
+ ScheduleAddObserver(checker_a.get()); |
+ message_loop()->Run(); |
+ |
+ checker_b->AddExpectation(Orientation::Empty()); |
+ ScheduleAddObserver(checker_b.get()); |
+ message_loop()->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); |
+ int expectations_count = 0; |
+ const Orientation kTestOrientation(true, 1, true, 2, true, 3); |
+ |
+ scoped_ptr<UpdateChecker> checker(new UpdateChecker(&expectations_count)); |
+ checker->AddExpectation(kTestOrientation); |
+ orientation_factory->SetOrientation(kTestOrientation); |
+ ScheduleAddObserver(checker.get()); |
+ message_loop()->Run(); |
+ |
+ RemoveObserver(checker.get()); |
+} |
+ |
+TEST_F(DeviceOrientationProviderTest, MultipleObserversPushTest) { |
+ scoped_refptr<MockOrientationFactory> orientation_factory( |
+ new MockOrientationFactory()); |
+ Init(MockOrientationFactory::CreateDataFetcher); |
+ int expectations_count = 0; |
+ 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(&expectations_count)); |
+ scoped_ptr<UpdateChecker> checker_b(new UpdateChecker(&expectations_count)); |
+ scoped_ptr<UpdateChecker> checker_c(new UpdateChecker(&expectations_count)); |
+ |
+ checker_a->AddExpectation(kTestOrientations[0]); |
+ orientation_factory->SetOrientation(kTestOrientations[0]); |
+ ScheduleAddObserver(checker_a.get()); |
+ message_loop()->Run(); |
+ |
+ checker_a->AddExpectation(kTestOrientations[1]); |
+ checker_b->AddExpectation(kTestOrientations[0]); |
+ checker_b->AddExpectation(kTestOrientations[1]); |
+ orientation_factory->SetOrientation(kTestOrientations[1]); |
+ ScheduleAddObserver(checker_b.get()); |
+ message_loop()->Run(); |
+ |
+ RemoveObserver(checker_a.get()); |
+ checker_b->AddExpectation(kTestOrientations[2]); |
+ checker_c->AddExpectation(kTestOrientations[1]); |
+ checker_c->AddExpectation(kTestOrientations[2]); |
+ orientation_factory->SetOrientation(kTestOrientations[2]); |
+ ScheduleAddObserver(checker_c.get()); |
+ message_loop()->Run(); |
+ |
+ RemoveObserver(checker_b.get()); |
+ RemoveObserver(checker_c.get()); |
+} |
+ |
+TEST_F(DeviceOrientationProviderTest, ObserverNotRemoved) { |
+ scoped_refptr<MockOrientationFactory> orientation_factory( |
+ new MockOrientationFactory()); |
+ Init(MockOrientationFactory::CreateDataFetcher); |
+ int expectations_count = 0; |
+ const Orientation kTestOrientation(true, 1, true, 2, true, 3); |
+ |
+ scoped_ptr<UpdateChecker> checker(new UpdateChecker(&expectations_count)); |
+ checker->AddExpectation(kTestOrientation); |
+ orientation_factory->SetOrientation(kTestOrientation); |
+ ScheduleAddObserver(checker.get()); |
+ message_loop()->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); |
+ int expectations_count = 0; |
+ const Orientation kTestOrientation(true, 1, true, 2, true, 3); |
+ |
+ scoped_ptr<UpdateChecker> checker_a(new UpdateChecker(&expectations_count)); |
+ scoped_ptr<UpdateChecker> checker_b(new UpdateChecker(&expectations_count)); |
+ |
+ orientation_factory->SetOrientation(kTestOrientation); |
+ checker_a->AddExpectation(kTestOrientation); |
+ ScheduleAddObserver(checker_a.get()); |
+ message_loop()->Run(); |
+ |
+ checker_a->AddExpectation(Orientation::Empty()); |
+ orientation_factory->SetOrientation(Orientation::Empty()); |
+ message_loop()->Run(); |
+ |
+ checker_b->AddExpectation(Orientation::Empty()); |
+ ScheduleAddObserver(checker_b.get()); |
+ message_loop()->Run(); |
+ |
+ RemoveObserver(checker_a.get()); |
+ RemoveObserver(checker_b.get()); |
+} |
+ |
+TEST_F(DeviceOrientationProviderTest, StartStopStart) { |
+ scoped_refptr<MockOrientationFactory> orientation_factory( |
+ new MockOrientationFactory()); |
+ Init(MockOrientationFactory::CreateDataFetcher); |
+ int expectations_count = 0; |
+ 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(&expectations_count)); |
+ scoped_ptr<UpdateChecker> checker_b(new UpdateChecker(&expectations_count)); |
+ |
+ checker_a->AddExpectation(kTestOrientation); |
+ orientation_factory->SetOrientation(kTestOrientation); |
+ ScheduleAddObserver(checker_a.get()); |
+ message_loop()->Run(); |
+ |
+ RemoveObserver(checker_a.get()); // This stops the Provider. |
+ |
+ checker_b->AddExpectation(kTestOrientation2); |
+ orientation_factory->SetOrientation(kTestOrientation2); |
+ ScheduleAddObserver(checker_b.get()); |
+ message_loop()->Run(); |
+ RemoveObserver(checker_b.get()); |
+} |
+ |
+TEST_F(DeviceOrientationProviderTest, SignificantlyDifferent) { |
+ scoped_refptr<MockOrientationFactory> orientation_factory( |
+ new MockOrientationFactory()); |
+ Init(MockOrientationFactory::CreateDataFetcher); |
+ int expectations_count = 0; |
+ |
+ // 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(&expectations_count)); |
+ scoped_ptr<UpdateChecker> checker_b(new UpdateChecker(&expectations_count)); |
+ |
+ |
+ orientation_factory->SetOrientation(first_orientation); |
+ checker_a->AddExpectation(first_orientation); |
+ ScheduleAddObserver(checker_a.get()); |
+ message_loop()->Run(); |
+ |
+ // The observers should not see this insignificantly different orientation. |
+ orientation_factory->SetOrientation(second_orientation); |
+ checker_b->AddExpectation(first_orientation); |
+ ScheduleAddObserver(checker_b.get()); |
+ message_loop()->Run(); |
+ |
+ orientation_factory->SetOrientation(third_orientation); |
+ checker_a->AddExpectation(third_orientation); |
+ checker_b->AddExpectation(third_orientation); |
+ message_loop()->Run(); |
+ |
+ RemoveObserver(checker_a.get()); |
+ RemoveObserver(checker_b.get()); |
+} |
+ |
+} // namespace |
+ |
+} // namespace device_orientation |