1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "base/bind_helpers.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string16.h"
11 #include "base/time/time.h"
12 #include "content/browser/geolocation/geolocation_provider_impl.h"
13 #include "content/browser/geolocation/mock_location_arbitrator.h"
14 #include "content/public/browser/access_token_store.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/test/test_browser_thread.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 using testing::MakeMatcher
;
21 using testing::Matcher
;
22 using testing::MatcherInterface
;
23 using testing::MatchResultListener
;
27 class LocationProviderForTestArbitrator
: public GeolocationProviderImpl
{
29 LocationProviderForTestArbitrator() : mock_arbitrator_(NULL
) {}
30 virtual ~LocationProviderForTestArbitrator() {}
32 // Only valid for use on the geolocation thread.
33 MockLocationArbitrator
* mock_arbitrator() const {
34 return mock_arbitrator_
;
38 // GeolocationProviderImpl implementation:
39 virtual LocationArbitrator
* CreateArbitrator() OVERRIDE
;
42 MockLocationArbitrator
* mock_arbitrator_
;
45 LocationArbitrator
* LocationProviderForTestArbitrator::CreateArbitrator() {
46 DCHECK(mock_arbitrator_
== NULL
);
47 mock_arbitrator_
= new MockLocationArbitrator
;
48 return mock_arbitrator_
;
51 class GeolocationObserver
{
53 virtual ~GeolocationObserver() {}
54 virtual void OnLocationUpdate(const Geoposition
& position
) = 0;
57 class MockGeolocationObserver
: public GeolocationObserver
{
59 MOCK_METHOD1(OnLocationUpdate
, void(const Geoposition
& position
));
62 class AsyncMockGeolocationObserver
: public MockGeolocationObserver
{
64 virtual void OnLocationUpdate(const Geoposition
& position
) OVERRIDE
{
65 MockGeolocationObserver::OnLocationUpdate(position
);
66 base::MessageLoop::current()->Quit();
70 class MockGeolocationCallbackWrapper
{
72 MOCK_METHOD1(Callback
, void(const Geoposition
& position
));
75 class GeopositionEqMatcher
76 : public MatcherInterface
<const Geoposition
&> {
78 explicit GeopositionEqMatcher(const Geoposition
& expected
)
79 : expected_(expected
) {}
81 virtual bool MatchAndExplain(const Geoposition
& actual
,
82 MatchResultListener
* listener
) const OVERRIDE
{
83 return actual
.latitude
== expected_
.latitude
&&
84 actual
.longitude
== expected_
.longitude
&&
85 actual
.altitude
== expected_
.altitude
&&
86 actual
.accuracy
== expected_
.accuracy
&&
87 actual
.altitude_accuracy
== expected_
.altitude_accuracy
&&
88 actual
.heading
== expected_
.heading
&&
89 actual
.speed
== expected_
.speed
&&
90 actual
.timestamp
== expected_
.timestamp
&&
91 actual
.error_code
== expected_
.error_code
&&
92 actual
.error_message
== expected_
.error_message
;
95 virtual void DescribeTo(::std::ostream
* os
) const OVERRIDE
{
96 *os
<< "which matches the expected position";
99 virtual void DescribeNegationTo(::std::ostream
* os
) const OVERRIDE
{
100 *os
<< "which does not match the expected position";
104 Geoposition expected_
;
106 DISALLOW_COPY_AND_ASSIGN(GeopositionEqMatcher
);
109 Matcher
<const Geoposition
&> GeopositionEq(const Geoposition
& expected
) {
110 return MakeMatcher(new GeopositionEqMatcher(expected
));
113 class GeolocationProviderTest
: public testing::Test
{
115 GeolocationProviderTest()
117 io_thread_(BrowserThread::IO
, &message_loop_
),
118 provider_(new LocationProviderForTestArbitrator
) {
121 virtual ~GeolocationProviderTest() {}
123 LocationProviderForTestArbitrator
* provider() { return provider_
.get(); }
125 // Called on test thread.
126 bool ProvidersStarted();
127 void SendMockLocation(const Geoposition
& position
);
130 // Called on provider thread.
131 void GetProvidersStarted(bool* started
);
133 base::MessageLoop message_loop_
;
134 TestBrowserThread io_thread_
;
135 scoped_ptr
<LocationProviderForTestArbitrator
> provider_
;
139 bool GeolocationProviderTest::ProvidersStarted() {
140 DCHECK(provider_
->IsRunning());
141 DCHECK(base::MessageLoop::current() == &message_loop_
);
143 provider_
->message_loop_proxy()->PostTaskAndReply(
145 base::Bind(&GeolocationProviderTest::GetProvidersStarted
,
146 base::Unretained(this),
148 base::MessageLoop::QuitClosure());
153 void GeolocationProviderTest::GetProvidersStarted(bool* started
) {
154 DCHECK(base::MessageLoop::current() == provider_
->message_loop());
155 *started
= provider_
->mock_arbitrator()->providers_started();
158 void GeolocationProviderTest::SendMockLocation(const Geoposition
& position
) {
159 DCHECK(provider_
->IsRunning());
160 DCHECK(base::MessageLoop::current() == &message_loop_
);
161 provider_
->message_loop()
162 ->PostTask(FROM_HERE
,
163 base::Bind(&GeolocationProviderImpl::OnLocationUpdate
,
164 base::Unretained(provider_
.get()),
168 // Regression test for http://crbug.com/59377
169 TEST_F(GeolocationProviderTest
, OnPermissionGrantedWithoutObservers
) {
170 EXPECT_FALSE(provider()->LocationServicesOptedIn());
171 provider()->UserDidOptIntoLocationServices();
172 EXPECT_TRUE(provider()->LocationServicesOptedIn());
175 TEST_F(GeolocationProviderTest
, StartStop
) {
176 EXPECT_FALSE(provider()->IsRunning());
177 GeolocationProviderImpl::LocationUpdateCallback null_callback
;
178 provider()->AddLocationUpdateCallback(null_callback
, false);
179 EXPECT_TRUE(provider()->IsRunning());
180 EXPECT_TRUE(ProvidersStarted());
182 provider()->RemoveLocationUpdateCallback(null_callback
);
183 EXPECT_FALSE(ProvidersStarted());
184 EXPECT_TRUE(provider()->IsRunning());
187 TEST_F(GeolocationProviderTest
, StalePositionNotSent
) {
188 Geoposition first_position
;
189 first_position
.latitude
= 12;
190 first_position
.longitude
= 34;
191 first_position
.accuracy
= 56;
192 first_position
.timestamp
= base::Time::Now();
194 AsyncMockGeolocationObserver first_observer
;
195 GeolocationProviderImpl::LocationUpdateCallback first_callback
= base::Bind(
196 &MockGeolocationObserver::OnLocationUpdate
,
197 base::Unretained(&first_observer
));
198 EXPECT_CALL(first_observer
, OnLocationUpdate(GeopositionEq(first_position
)));
199 provider()->AddLocationUpdateCallback(first_callback
, false);
200 SendMockLocation(first_position
);
201 base::MessageLoop::current()->Run();
203 provider()->RemoveLocationUpdateCallback(first_callback
);
205 Geoposition second_position
;
206 second_position
.latitude
= 13;
207 second_position
.longitude
= 34;
208 second_position
.accuracy
= 56;
209 second_position
.timestamp
= base::Time::Now();
211 AsyncMockGeolocationObserver second_observer
;
213 // After adding a second observer, check that no unexpected position update
215 EXPECT_CALL(second_observer
, OnLocationUpdate(testing::_
)).Times(0);
216 GeolocationProviderImpl::LocationUpdateCallback second_callback
= base::Bind(
217 &MockGeolocationObserver::OnLocationUpdate
,
218 base::Unretained(&second_observer
));
219 provider()->AddLocationUpdateCallback(second_callback
, false);
220 base::MessageLoop::current()->RunUntilIdle();
222 // The second observer should receive the new position now.
223 EXPECT_CALL(second_observer
,
224 OnLocationUpdate(GeopositionEq(second_position
)));
225 SendMockLocation(second_position
);
226 base::MessageLoop::current()->Run();
228 provider()->RemoveLocationUpdateCallback(second_callback
);
229 EXPECT_FALSE(ProvidersStarted());
232 TEST_F(GeolocationProviderTest
, OverrideLocationForTesting
) {
233 Geoposition position
;
234 position
.error_code
= Geoposition::ERROR_CODE_POSITION_UNAVAILABLE
;
235 provider()->OverrideLocationForTesting(position
);
236 // Adding an observer when the location is overridden should synchronously
237 // update the observer with our overridden position.
238 MockGeolocationObserver mock_observer
;
239 EXPECT_CALL(mock_observer
, OnLocationUpdate(GeopositionEq(position
)));
240 GeolocationProviderImpl::LocationUpdateCallback callback
= base::Bind(
241 &MockGeolocationObserver::OnLocationUpdate
,
242 base::Unretained(&mock_observer
));
243 provider()->AddLocationUpdateCallback(callback
, false);
244 provider()->RemoveLocationUpdateCallback(callback
);
245 // Wait for the providers to be stopped now that all clients are gone.
246 EXPECT_FALSE(ProvidersStarted());
249 } // namespace content