summaryrefslogtreecommitdiff
path: root/chromium/content/browser/geolocation/geolocation_provider_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/geolocation/geolocation_provider_unittest.cc')
-rw-r--r--chromium/content/browser/geolocation/geolocation_provider_unittest.cc249
1 files changed, 249 insertions, 0 deletions
diff --git a/chromium/content/browser/geolocation/geolocation_provider_unittest.cc b/chromium/content/browser/geolocation/geolocation_provider_unittest.cc
new file mode 100644
index 00000000000..47b397a9a90
--- /dev/null
+++ b/chromium/content/browser/geolocation/geolocation_provider_unittest.cc
@@ -0,0 +1,249 @@
+// 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/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "content/browser/geolocation/geolocation_provider_impl.h"
+#include "content/browser/geolocation/mock_location_arbitrator.h"
+#include "content/public/browser/access_token_store.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::MakeMatcher;
+using testing::Matcher;
+using testing::MatcherInterface;
+using testing::MatchResultListener;
+
+namespace content {
+
+class LocationProviderForTestArbitrator : public GeolocationProviderImpl {
+ public:
+ LocationProviderForTestArbitrator() : mock_arbitrator_(NULL) {}
+ virtual ~LocationProviderForTestArbitrator() {}
+
+ // Only valid for use on the geolocation thread.
+ MockGeolocationArbitrator* mock_arbitrator() const {
+ return mock_arbitrator_;
+ }
+
+ protected:
+ // GeolocationProviderImpl implementation:
+ virtual GeolocationArbitrator* CreateArbitrator() OVERRIDE;
+
+ private:
+ MockGeolocationArbitrator* mock_arbitrator_;
+};
+
+GeolocationArbitrator* LocationProviderForTestArbitrator::CreateArbitrator() {
+ DCHECK(mock_arbitrator_ == NULL);
+ mock_arbitrator_ = new MockGeolocationArbitrator;
+ return mock_arbitrator_;
+}
+
+class GeolocationObserver {
+ public:
+ virtual ~GeolocationObserver() {}
+ virtual void OnLocationUpdate(const Geoposition& position) = 0;
+};
+
+class MockGeolocationObserver : public GeolocationObserver {
+ public:
+ MOCK_METHOD1(OnLocationUpdate, void(const Geoposition& position));
+};
+
+class AsyncMockGeolocationObserver : public MockGeolocationObserver {
+ public:
+ virtual void OnLocationUpdate(const Geoposition& position) OVERRIDE {
+ MockGeolocationObserver::OnLocationUpdate(position);
+ base::MessageLoop::current()->Quit();
+ }
+};
+
+class MockGeolocationCallbackWrapper {
+ public:
+ MOCK_METHOD1(Callback, void(const Geoposition& position));
+};
+
+class GeopositionEqMatcher
+ : public MatcherInterface<const Geoposition&> {
+ public:
+ explicit GeopositionEqMatcher(const Geoposition& expected)
+ : expected_(expected) {}
+
+ virtual bool MatchAndExplain(const Geoposition& actual,
+ MatchResultListener* listener) const OVERRIDE {
+ return actual.latitude == expected_.latitude &&
+ actual.longitude == expected_.longitude &&
+ actual.altitude == expected_.altitude &&
+ actual.accuracy == expected_.accuracy &&
+ actual.altitude_accuracy == expected_.altitude_accuracy &&
+ actual.heading == expected_.heading &&
+ actual.speed == expected_.speed &&
+ actual.timestamp == expected_.timestamp &&
+ actual.error_code == expected_.error_code &&
+ actual.error_message == expected_.error_message;
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const OVERRIDE {
+ *os << "which matches the expected position";
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const OVERRIDE {
+ *os << "which does not match the expected position";
+ }
+
+ private:
+ Geoposition expected_;
+
+ DISALLOW_COPY_AND_ASSIGN(GeopositionEqMatcher);
+};
+
+Matcher<const Geoposition&> GeopositionEq(const Geoposition& expected) {
+ return MakeMatcher(new GeopositionEqMatcher(expected));
+}
+
+class GeolocationProviderTest : public testing::Test {
+ protected:
+ GeolocationProviderTest()
+ : message_loop_(),
+ io_thread_(BrowserThread::IO, &message_loop_),
+ provider_(new LocationProviderForTestArbitrator) {
+ }
+
+ virtual ~GeolocationProviderTest() {}
+
+ LocationProviderForTestArbitrator* provider() { return provider_.get(); }
+
+ // Called on test thread.
+ bool ProvidersStarted();
+ void SendMockLocation(const Geoposition& position);
+
+ private:
+ // Called on provider thread.
+ void GetProvidersStarted(bool* started);
+
+ base::MessageLoop message_loop_;
+ TestBrowserThread io_thread_;
+ scoped_ptr<LocationProviderForTestArbitrator> provider_;
+};
+
+
+bool GeolocationProviderTest::ProvidersStarted() {
+ DCHECK(provider_->IsRunning());
+ DCHECK(base::MessageLoop::current() == &message_loop_);
+ bool started;
+ provider_->message_loop_proxy()->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&GeolocationProviderTest::GetProvidersStarted,
+ base::Unretained(this),
+ &started),
+ base::MessageLoop::QuitClosure());
+ message_loop_.Run();
+ return started;
+}
+
+void GeolocationProviderTest::GetProvidersStarted(bool* started) {
+ DCHECK(base::MessageLoop::current() == provider_->message_loop());
+ *started = provider_->mock_arbitrator()->providers_started();
+}
+
+void GeolocationProviderTest::SendMockLocation(const Geoposition& position) {
+ DCHECK(provider_->IsRunning());
+ DCHECK(base::MessageLoop::current() == &message_loop_);
+ provider_->message_loop()
+ ->PostTask(FROM_HERE,
+ base::Bind(&GeolocationProviderImpl::OnLocationUpdate,
+ base::Unretained(provider_.get()),
+ position));
+}
+
+// Regression test for http://crbug.com/59377
+TEST_F(GeolocationProviderTest, OnPermissionGrantedWithoutObservers) {
+ EXPECT_FALSE(provider()->LocationServicesOptedIn());
+ provider()->UserDidOptIntoLocationServices();
+ EXPECT_TRUE(provider()->LocationServicesOptedIn());
+}
+
+TEST_F(GeolocationProviderTest, StartStop) {
+ EXPECT_FALSE(provider()->IsRunning());
+ GeolocationProviderImpl::LocationUpdateCallback null_callback;
+ provider()->AddLocationUpdateCallback(null_callback, false);
+ EXPECT_TRUE(provider()->IsRunning());
+ EXPECT_TRUE(ProvidersStarted());
+
+ provider()->RemoveLocationUpdateCallback(null_callback);
+ EXPECT_FALSE(ProvidersStarted());
+ EXPECT_TRUE(provider()->IsRunning());
+}
+
+TEST_F(GeolocationProviderTest, StalePositionNotSent) {
+ Geoposition first_position;
+ first_position.latitude = 12;
+ first_position.longitude = 34;
+ first_position.accuracy = 56;
+ first_position.timestamp = base::Time::Now();
+
+ AsyncMockGeolocationObserver first_observer;
+ GeolocationProviderImpl::LocationUpdateCallback first_callback = base::Bind(
+ &MockGeolocationObserver::OnLocationUpdate,
+ base::Unretained(&first_observer));
+ EXPECT_CALL(first_observer, OnLocationUpdate(GeopositionEq(first_position)));
+ provider()->AddLocationUpdateCallback(first_callback, false);
+ SendMockLocation(first_position);
+ base::MessageLoop::current()->Run();
+
+ provider()->RemoveLocationUpdateCallback(first_callback);
+
+ Geoposition second_position;
+ second_position.latitude = 13;
+ second_position.longitude = 34;
+ second_position.accuracy = 56;
+ second_position.timestamp = base::Time::Now();
+
+ AsyncMockGeolocationObserver second_observer;
+
+ // After adding a second observer, check that no unexpected position update
+ // is sent.
+ EXPECT_CALL(second_observer, OnLocationUpdate(testing::_)).Times(0);
+ GeolocationProviderImpl::LocationUpdateCallback second_callback = base::Bind(
+ &MockGeolocationObserver::OnLocationUpdate,
+ base::Unretained(&second_observer));
+ provider()->AddLocationUpdateCallback(second_callback, false);
+ base::MessageLoop::current()->RunUntilIdle();
+
+ // The second observer should receive the new position now.
+ EXPECT_CALL(second_observer,
+ OnLocationUpdate(GeopositionEq(second_position)));
+ SendMockLocation(second_position);
+ base::MessageLoop::current()->Run();
+
+ provider()->RemoveLocationUpdateCallback(second_callback);
+ EXPECT_FALSE(ProvidersStarted());
+}
+
+TEST_F(GeolocationProviderTest, OverrideLocationForTesting) {
+ Geoposition position;
+ position.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
+ provider()->OverrideLocationForTesting(position);
+ // Adding an observer when the location is overridden should synchronously
+ // update the observer with our overridden position.
+ MockGeolocationObserver mock_observer;
+ EXPECT_CALL(mock_observer, OnLocationUpdate(GeopositionEq(position)));
+ GeolocationProviderImpl::LocationUpdateCallback callback = base::Bind(
+ &MockGeolocationObserver::OnLocationUpdate,
+ base::Unretained(&mock_observer));
+ provider()->AddLocationUpdateCallback(callback, false);
+ provider()->RemoveLocationUpdateCallback(callback);
+ // Wait for the providers to be stopped now that all clients are gone.
+ EXPECT_FALSE(ProvidersStarted());
+}
+
+} // namespace content