1 // Copyright 2019 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.
4
5 #include "services/device/geolocation/win/location_provider_winrt.h"
6
7 #include "base/run_loop.h"
8 #include "base/test/task_environment.h"
9 #include "base/win/core_winrt_util.h"
10 #include "services/device/geolocation/win/fake_geocoordinate_winrt.h"
11 #include "services/device/geolocation/win/fake_geolocator_winrt.h"
12 #include "services/device/public/cpp/geolocation/geoposition.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace device {
16 namespace {
17 using ABI::Windows::Devices::Geolocation::IGeolocator;
18 using ABI::Windows::Devices::Geolocation::PositionStatus;
19
20 class MockLocationObserver {
21 public:
MockLocationObserver(base::OnceClosure update_called)22 MockLocationObserver(base::OnceClosure update_called)
23 : update_called_(std::move(update_called)) {}
24 ~MockLocationObserver() = default;
25
InvalidateLastPosition()26 void InvalidateLastPosition() {
27 last_position_.error_code = mojom::Geoposition::ErrorCode::NONE;
28 EXPECT_FALSE(ValidateGeoposition(last_position_));
29 }
30
OnLocationUpdate(const LocationProvider * provider,const mojom::Geoposition & position)31 void OnLocationUpdate(const LocationProvider* provider,
32 const mojom::Geoposition& position) {
33 last_position_ = position;
34 on_location_update_called_ = true;
35 std::move(update_called_).Run();
36 }
37
last_position()38 mojom::Geoposition last_position() { return last_position_; }
39
on_location_update_called()40 bool on_location_update_called() { return on_location_update_called_; }
41
42 private:
43 base::OnceClosure update_called_;
44 mojom::Geoposition last_position_;
45 bool on_location_update_called_ = false;
46 };
47
48 } // namespace
49
50 class TestingLocationProviderWinrt : public LocationProviderWinrt {
51 public:
TestingLocationProviderWinrt(std::unique_ptr<FakeGeocoordinateData> position_data,PositionStatus position_status)52 TestingLocationProviderWinrt(
53 std::unique_ptr<FakeGeocoordinateData> position_data,
54 PositionStatus position_status)
55 : position_data_(std::move(position_data)),
56 position_status_(position_status) {}
57
HasPermissionBeenGrantedForTest()58 bool HasPermissionBeenGrantedForTest() { return permission_granted_; }
59
IsHighAccuracyEnabled()60 bool IsHighAccuracyEnabled() { return enable_high_accuracy_; }
61
GetStatusChangedToken()62 base::Optional<EventRegistrationToken> GetStatusChangedToken() {
63 return status_changed_token_;
64 }
65
GetPositionChangedToken()66 base::Optional<EventRegistrationToken> GetPositionChangedToken() {
67 return position_changed_token_;
68 }
69
GetGeolocator(IGeolocator ** geo_locator)70 HRESULT GetGeolocator(IGeolocator** geo_locator) override {
71 *geo_locator = Microsoft::WRL::Make<FakeGeolocatorWinrt>(
72 std::move(position_data_), position_status_)
73 .Detach();
74 return S_OK;
75 }
76
77 private:
78 std::unique_ptr<FakeGeocoordinateData> position_data_;
79 const PositionStatus position_status_;
80 };
81
82 class LocationProviderWinrtTest : public testing::Test {
83 public:
SetUpTestSuite()84 static void SetUpTestSuite() {
85 base::win::RoInitialize(RO_INIT_TYPE::RO_INIT_MULTITHREADED);
86 }
87
88 protected:
LocationProviderWinrtTest()89 LocationProviderWinrtTest()
90 : observer_(
91 std::make_unique<MockLocationObserver>(run_loop_.QuitClosure())),
92 callback_(base::BindRepeating(&MockLocationObserver::OnLocationUpdate,
93 base::Unretained(observer_.get()))) {}
94
InitializeProvider(PositionStatus position_status=PositionStatus::PositionStatus_Ready)95 void InitializeProvider(
96 PositionStatus position_status = PositionStatus::PositionStatus_Ready) {
97 auto test_data = FakeGeocoordinateData();
98 test_data.longitude = 0;
99 test_data.latitude = 0;
100 test_data.accuracy = 0;
101 InitializeProvider(test_data, position_status);
102 }
103
InitializeProvider(FakeGeocoordinateData position_data,PositionStatus position_status=PositionStatus::PositionStatus_Ready)104 void InitializeProvider(
105 FakeGeocoordinateData position_data,
106 PositionStatus position_status = PositionStatus::PositionStatus_Ready) {
107 provider_ = std::make_unique<TestingLocationProviderWinrt>(
108 std::make_unique<FakeGeocoordinateData>(position_data),
109 position_status);
110 provider_->SetUpdateCallback(callback_);
111 }
112
113 base::test::TaskEnvironment task_environment_;
114 base::RunLoop run_loop_;
115 const std::unique_ptr<MockLocationObserver> observer_;
116 const LocationProvider::LocationProviderUpdateCallback callback_;
117 std::unique_ptr<TestingLocationProviderWinrt> provider_;
118 };
119
TEST_F(LocationProviderWinrtTest,CreateDestroy)120 TEST_F(LocationProviderWinrtTest, CreateDestroy) {
121 InitializeProvider();
122 EXPECT_TRUE(provider_);
123 provider_.reset();
124 }
125
TEST_F(LocationProviderWinrtTest,OnPermissionGranted)126 TEST_F(LocationProviderWinrtTest, OnPermissionGranted) {
127 InitializeProvider();
128 EXPECT_FALSE(provider_->HasPermissionBeenGrantedForTest());
129 provider_->OnPermissionGranted();
130 EXPECT_TRUE(provider_->HasPermissionBeenGrantedForTest());
131 }
132
TEST_F(LocationProviderWinrtTest,SetAccuracyOptions)133 TEST_F(LocationProviderWinrtTest, SetAccuracyOptions) {
134 InitializeProvider();
135 provider_->StartProvider(/*enable_high_accuracy=*/false);
136 EXPECT_EQ(false, provider_->IsHighAccuracyEnabled());
137 provider_->StartProvider(/*enable_high_accuracy=*/true);
138 EXPECT_EQ(true, provider_->IsHighAccuracyEnabled());
139 }
140
141 // Tests when OnPermissionGranted() called location update is provided.
TEST_F(LocationProviderWinrtTest,HasPermissions)142 TEST_F(LocationProviderWinrtTest, HasPermissions) {
143 auto test_data = FakeGeocoordinateData();
144 test_data.longitude = 1;
145 test_data.latitude = 2;
146 test_data.accuracy = 3;
147 test_data.speed = 4;
148
149 InitializeProvider(test_data);
150 provider_->OnPermissionGranted();
151 provider_->StartProvider(/*enable_high_accuracy=*/false);
152
153 EXPECT_FALSE(observer_->on_location_update_called());
154 EXPECT_FALSE(ValidateGeoposition(observer_->last_position()));
155
156 EXPECT_TRUE(provider_->GetStatusChangedToken().has_value());
157 EXPECT_TRUE(provider_->GetPositionChangedToken().has_value());
158
159 run_loop_.Run();
160
161 EXPECT_TRUE(observer_->on_location_update_called());
162 auto position = observer_->last_position();
163 EXPECT_TRUE(ValidateGeoposition(position));
164 EXPECT_EQ(position.latitude, test_data.latitude);
165 EXPECT_EQ(position.longitude, test_data.longitude);
166 EXPECT_EQ(position.accuracy, test_data.accuracy);
167 EXPECT_EQ(position.altitude, device::mojom::kBadAltitude);
168 EXPECT_EQ(position.altitude_accuracy, device::mojom::kBadAccuracy);
169 EXPECT_EQ(position.speed, test_data.speed.value());
170 EXPECT_EQ(position.heading, device::mojom::kBadHeading);
171 }
172
173 // Tests when OnPermissionGranted() called location update is provided with all
174 // possible values populated.
TEST_F(LocationProviderWinrtTest,HasPermissionsAllValues)175 TEST_F(LocationProviderWinrtTest, HasPermissionsAllValues) {
176 auto test_data = FakeGeocoordinateData();
177 test_data.longitude = 1;
178 test_data.latitude = 2;
179 test_data.accuracy = 3;
180 test_data.altitude = 4;
181 test_data.altitude_accuracy = 5;
182 test_data.heading = 6;
183 test_data.speed = 7;
184
185 InitializeProvider(test_data);
186 provider_->OnPermissionGranted();
187 provider_->StartProvider(/*enable_high_accuracy=*/false);
188
189 EXPECT_FALSE(observer_->on_location_update_called());
190 EXPECT_FALSE(ValidateGeoposition(observer_->last_position()));
191
192 EXPECT_TRUE(provider_->GetStatusChangedToken().has_value());
193 EXPECT_TRUE(provider_->GetPositionChangedToken().has_value());
194
195 run_loop_.Run();
196
197 EXPECT_TRUE(observer_->on_location_update_called());
198 auto position = observer_->last_position();
199 EXPECT_TRUE(ValidateGeoposition(position));
200 EXPECT_EQ(position.latitude, test_data.latitude);
201 EXPECT_EQ(position.longitude, test_data.longitude);
202 EXPECT_EQ(position.accuracy, test_data.accuracy);
203 EXPECT_EQ(position.altitude, test_data.altitude.value());
204 EXPECT_EQ(position.altitude_accuracy, test_data.altitude_accuracy.value());
205 EXPECT_EQ(position.speed, test_data.speed.value());
206 EXPECT_EQ(position.heading, test_data.heading.value());
207 }
208
209 // Tests when provider is stopped and started quickly access errors
210 // do not occur and location update is not called.
TEST_F(LocationProviderWinrtTest,StartStopProviderRunTasks)211 TEST_F(LocationProviderWinrtTest, StartStopProviderRunTasks) {
212 InitializeProvider();
213 provider_->OnPermissionGranted();
214 provider_->StartProvider(/*enable_high_accuracy=*/false);
215 provider_->StopProvider();
216
217 EXPECT_FALSE(observer_->on_location_update_called());
218 EXPECT_FALSE(ValidateGeoposition(observer_->last_position()));
219
220 run_loop_.RunUntilIdle();
221
222 EXPECT_FALSE(observer_->on_location_update_called());
223 EXPECT_FALSE(provider_->GetStatusChangedToken().has_value());
224 EXPECT_FALSE(provider_->GetPositionChangedToken().has_value());
225 }
226
227 // Tests when OnPermissionGranted() has not been called location update
228 // is not provided.
TEST_F(LocationProviderWinrtTest,NoPermissions)229 TEST_F(LocationProviderWinrtTest, NoPermissions) {
230 InitializeProvider();
231 provider_->StartProvider(/*enable_high_accuracy=*/false);
232
233 EXPECT_FALSE(observer_->on_location_update_called());
234 EXPECT_FALSE(ValidateGeoposition(observer_->last_position()));
235
236 run_loop_.RunUntilIdle();
237
238 EXPECT_FALSE(observer_->on_location_update_called());
239 EXPECT_FALSE(provider_->GetStatusChangedToken().has_value());
240 EXPECT_FALSE(provider_->GetPositionChangedToken().has_value());
241 }
242
243 // Tests when a PositionStatus_Disabled is returned from the OS indicating
244 // access to location on the OS is disabled, a permission denied is returned.
TEST_F(LocationProviderWinrtTest,PositionStatusDisabledOsPermissions)245 TEST_F(LocationProviderWinrtTest, PositionStatusDisabledOsPermissions) {
246 InitializeProvider(PositionStatus::PositionStatus_Disabled);
247 provider_->OnPermissionGranted();
248 provider_->StartProvider(/*enable_high_accuracy=*/false);
249
250 EXPECT_FALSE(observer_->on_location_update_called());
251 EXPECT_FALSE(ValidateGeoposition(observer_->last_position()));
252
253 EXPECT_TRUE(provider_->GetStatusChangedToken().has_value());
254 EXPECT_TRUE(provider_->GetPositionChangedToken().has_value());
255
256 run_loop_.Run();
257
258 EXPECT_TRUE(observer_->on_location_update_called());
259 auto position = observer_->last_position();
260 EXPECT_FALSE(ValidateGeoposition(position));
261 EXPECT_EQ(position.error_code,
262 mojom::Geoposition::ErrorCode::PERMISSION_DENIED);
263 }
264 } // namespace device
265