Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1254)

Side by Side Diff: device/generic_sensor/platform_sensor_and_provider_unittest_win.cc

Issue 2447973003: [sensors] [win] Implement ambient light sensor for Windows platform (Closed)
Patch Set: Fixes for review comments from Mikhail. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 <SensorsApi.h>
6 #include <Sensors.h> // NOLINT
7
8 #include "base/bind.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/win/iunknown_impl.h"
12
13 #include "device/generic_sensor/platform_sensor_provider_win.h"
14 #include "device/generic_sensor/public/interfaces/sensor_provider.mojom.h"
15
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 using ::testing::_;
20 using ::testing::Invoke;
21 using ::testing::IsNull;
22 using ::testing::NiceMock;
23 using ::testing::NotNull;
24 using ::testing::Return;
25
26 namespace device {
27 using mojom::SensorType;
28
29 template <class Interface>
30 class MockCOMInterface : public Interface, public base::win::IUnknownImpl {
31 public:
32 // IUnknown interface
33 ULONG STDMETHODCALLTYPE AddRef() override { return IUnknownImpl::AddRef(); }
34 ULONG STDMETHODCALLTYPE Release() override { return IUnknownImpl::Release(); }
35
36 STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override {
37 if (riid == __uuidof(Interface)) {
38 *ppv = static_cast<Interface*>(this);
39 AddRef();
40 return S_OK;
41 }
42 return IUnknownImpl::QueryInterface(riid, ppv);
43 }
44
45 protected:
46 ~MockCOMInterface() override = default;
47 };
48
49 // Mock class for ISensorManager COM interface.
50 class MockISensorManager : public MockCOMInterface<ISensorManager> {
51 public:
52 // ISensorManager interface
53 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
54 GetSensorsByCategory,
55 HRESULT(REFSENSOR_CATEGORY_ID category,
56 ISensorCollection** sensors_found));
57 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
58 GetSensorsByType,
59 HRESULT(REFSENSOR_TYPE_ID sensor_id,
60 ISensorCollection** sensors_found));
61 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
62 GetSensorByID,
63 HRESULT(REFSENSOR_ID sensor_id, ISensor** sensor));
64 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
65 SetEventSink,
66 HRESULT(ISensorManagerEvents* event_sink));
67 MOCK_METHOD3_WITH_CALLTYPE(STDMETHODCALLTYPE,
68 RequestPermissions,
69 HRESULT(HWND parent,
70 ISensorCollection* sensors,
71 BOOL is_modal));
72
73 protected:
74 ~MockISensorManager() override = default;
75 };
76
77 // Mock class for ISensorCollection COM interface.
78 class MockISensorCollection : public MockCOMInterface<ISensorCollection> {
79 public:
80 // ISensorCollection interface
81 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
82 GetAt,
83 HRESULT(ULONG index, ISensor** sensor));
84 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
85 GetCount,
86 HRESULT(ULONG* count));
87 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, Add, HRESULT(ISensor* sensor));
88 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
89 Remove,
90 HRESULT(ISensor* sensor));
91 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
92 RemoveByID,
93 HRESULT(REFSENSOR_ID sensor_id));
94 MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, Clear, HRESULT());
95
96 protected:
97 ~MockISensorCollection() override = default;
98 };
99
100 // Mock class for ISensor COM interface.
101 class MockISensor : public MockCOMInterface<ISensor> {
102 public:
103 // ISensor interface
104 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, GetID, HRESULT(SENSOR_ID* id));
105 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
106 GetCategory,
107 HRESULT(SENSOR_CATEGORY_ID* category));
108 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
109 GetType,
110 HRESULT(SENSOR_TYPE_ID* type));
111 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
112 GetFriendlyName,
113 HRESULT(BSTR* name));
114 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
115 GetProperty,
116 HRESULT(REFPROPERTYKEY key,
117 PROPVARIANT* property));
118 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
119 GetProperties,
120 HRESULT(IPortableDeviceKeyCollection* keys,
121 IPortableDeviceValues** properties));
122 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
123 GetSupportedDataFields,
124 HRESULT(IPortableDeviceKeyCollection** data));
125 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
126 SetProperties,
127 HRESULT(IPortableDeviceValues* properties,
128 IPortableDeviceValues** results));
129 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
130 SupportsDataField,
131 HRESULT(REFPROPERTYKEY key,
132 VARIANT_BOOL* is_supported));
133 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
134 GetState,
135 HRESULT(SensorState* state));
136 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
137 GetData,
138 HRESULT(ISensorDataReport** data_report));
139 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
140 SupportsEvent,
141 HRESULT(REFGUID event_guid,
142 VARIANT_BOOL* is_supported));
143 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
144 GetEventInterest,
145 HRESULT(GUID** values, ULONG* count));
146 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
147 SetEventInterest,
148 HRESULT(GUID* values, ULONG count));
149 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
150 SetEventSink,
151 HRESULT(ISensorEvents* pEvents));
152
153 protected:
154 ~MockISensor() override = default;
155 };
156
157 // Mock class for ISensorDataReport COM interface.
158 class MockISensorDataReport : public MockCOMInterface<ISensorDataReport> {
159 public:
160 // ISensorDataReport interface
161 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
162 GetTimestamp,
163 HRESULT(SYSTEMTIME* timestamp));
164 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
165 GetSensorValue,
166 HRESULT(REFPROPERTYKEY key, PROPVARIANT* value));
167 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
168 GetSensorValues,
169 HRESULT(IPortableDeviceKeyCollection* keys,
170 IPortableDeviceValues** values));
171
172 protected:
173 ~MockISensorDataReport() override = default;
174 };
175
176 // Class that provides test harness support for generic sensor adaptation for
177 // Windows platform. Testing is mainly done by mocking main COM interfaces that
178 // are used to communicate with Sensors API.
179 // MockISensorManager - mocks ISensorManager and responsible for fetching
180 // list of supported sensors.
181 // MockISensorCollection - mocks collection of ISensor objects.
182 // MockISensor - mocks ISensor intrface.
183 // MockISensorDataReport - mocks IDataReport interface that is used to deliver
184 // data in OnDataUpdated event.
185 class PlatformSensorAndProviderTestWin : public ::testing::Test {
186 public:
187 void SetUp() override {
188 message_loop_.reset(new base::MessageLoopForIO);
189 m_sensor_ = new NiceMock<MockISensor>();
190 m_sensor_collection_ = new NiceMock<MockISensorCollection>();
191 m_sensor_manager_ = new NiceMock<MockISensorManager>();
192 base::win::ScopedComPtr<ISensorManager> manager;
193 m_sensor_manager_->QueryInterface(__uuidof(ISensorManager),
194 manager.ReceiveVoid());
195
196 // Overrides default ISensorManager with mocked interface.
197 PlatformSensorProviderWin::GetInstance()->SetSensorManagerForTesing(
198 manager);
199 }
200
201 void TearDown() override {
202 base::win::ScopedComPtr<ISensorManager> null_manager;
203 PlatformSensorProviderWin::GetInstance()->SetSensorManagerForTesing(
204 null_manager);
205 }
206
207 protected:
208 void SensorCreated(scoped_refptr<PlatformSensor> sensor) {
209 m_platform_sensor_ = sensor;
210 run_loop_->Quit();
211 }
212
213 // Sensor creation is asynchronous, therefore inner loop is used to wait for
214 // PlatformSensorProvider::CreateSensorCallback completion.
215 scoped_refptr<PlatformSensor> CreateSensor(mojom::SensorType type) {
216 run_loop_ = std::make_unique<base::RunLoop>();
217 PlatformSensorProviderWin::GetInstance()->CreateSensor(
218 type, base::Bind(&PlatformSensorAndProviderTestWin::SensorCreated,
219 base::Unretained(this)));
220 run_loop_->Run();
221 scoped_refptr<PlatformSensor> sensor;
222 sensor.swap(m_platform_sensor_);
223 run_loop_ = nullptr;
224 return sensor;
225 }
226
227 // Sets sensor with REFSENSOR_TYPE_ID |sensor| to be supported by mocked
228 // ISensorMager and it will be present in ISensorCollection.
229 void SetSupportedSensor(REFSENSOR_TYPE_ID sensor) {
230 EXPECT_CALL(*m_sensor_manager_, GetSensorsByType(sensor, _)).Times(1);
231 EXPECT_CALL(*m_sensor_collection_, GetCount(_)).Times(1);
232 EXPECT_CALL(*m_sensor_collection_, GetAt(0, _)).Times(1);
233
234 // Returns mock ISensorCollection.
235 ON_CALL(*m_sensor_manager_, GetSensorsByType(sensor, _))
236 .WillByDefault(Invoke(
237 [this](REFSENSOR_TYPE_ID type, ISensorCollection** collection) {
238 m_sensor_collection_->QueryInterface(
239 __uuidof(ISensorCollection),
240 reinterpret_cast<void**>(collection));
241 return S_OK;
242 }));
243
244 // Returns number of ISensor objects in ISensorCollection, at the moment
245 // only one ISensor interface instance is suported.
246 ON_CALL(*m_sensor_collection_, GetCount(_))
247 .WillByDefault(Invoke([](ULONG* count) {
248 *count = 1;
249 return S_OK;
250 }));
251
252 // Returns ISensor interface instance at index 0.
253 ON_CALL(*m_sensor_collection_, GetAt(0, _))
254 .WillByDefault(Invoke([this](ULONG index, ISensor** sensor) {
255 m_sensor_->QueryInterface(__uuidof(ISensor),
256 reinterpret_cast<void**>(sensor));
257 return S_OK;
258 }));
259
260 // Handles |SetEventSink| call that is used to subscribe to sensor events
261 // through ISensorEvents interface. ISensorEvents is stored and attached to
262 // |sensor_events_| that is used later to generate fake error, state and
263 // data change events.
264 ON_CALL(*m_sensor_, SetEventSink(NotNull()))
265 .WillByDefault(Invoke([this](ISensorEvents* events) {
266 events->AddRef();
267 sensor_events_.Attach(events);
268 return S_OK;
269 }));
270
271 // When |SetEventSink| is called with nullptr, it means that client is no
272 // longer interested in sensor events and ISensorEvents can be released.
273 ON_CALL(*m_sensor_, SetEventSink(IsNull()))
274 .WillByDefault(Invoke([this](ISensorEvents* events) {
275 sensor_events_.Release();
276 return S_OK;
277 }));
278 }
279
280 // Sets minimal reporting frequency for the mock sensor.
281 void SetSupportedReportingFrequency(double frequency) {
282 ON_CALL(*m_sensor_, GetProperty(SENSOR_PROPERTY_MIN_REPORT_INTERVAL, _))
283 .WillByDefault(
284 Invoke([frequency](REFPROPERTYKEY key, PROPVARIANT* pProperty) {
285 pProperty->vt = VT_UI4;
286 pProperty->ulVal =
287 (1 / frequency) * base::Time::kMillisecondsPerSecond;
288 return S_OK;
289 }));
290 }
291
292 // Generates OnLeave event, e.g. when sensor is disconnected.
293 void GenerateLeaveEvent() {
294 if (!sensor_events_)
295 return;
296 sensor_events_->OnLeave(SENSOR_ID());
297 }
298
299 // Generates OnStateChangedLeave event.
300 void GenerateStateChangeEvent(SensorState state) {
301 if (!sensor_events_)
302 return;
303 sensor_events_->OnStateChanged(m_sensor_.get(), state);
304 }
305
306 // Generates OnDataUpdated event and creates ISensorDataReport with fake
307 // |value| for property with |key|.
308 void GenerateDataUpdatedEvent(REFPROPERTYKEY key, double value) {
309 if (!sensor_events_)
310 return;
311
312 auto mock_report = new NiceMock<MockISensorDataReport>();
313
314 EXPECT_CALL(*mock_report, GetTimestamp(_)).Times(1);
315 EXPECT_CALL(*mock_report, GetSensorValue(_, _)).Times(1);
316
317 ON_CALL(*mock_report, GetTimestamp(_))
318 .WillByDefault(Invoke([](SYSTEMTIME* timestamp) {
319 GetSystemTime(timestamp);
320 return S_OK;
321 }));
322
323 ON_CALL(*mock_report, GetSensorValue(key, _))
324 .WillByDefault(Invoke([value](REFPROPERTYKEY, PROPVARIANT* variant) {
325 variant->vt = VT_R8;
326 variant->dblVal = value;
327 return S_OK;
328 }));
329
330 base::win::ScopedComPtr<ISensorDataReport> data_report;
331 mock_report->QueryInterface(__uuidof(ISensorDataReport),
332 data_report.ReceiveVoid());
333
334 sensor_events_->OnDataUpdated(m_sensor_.get(), data_report.get());
335 }
336
337 scoped_refptr<MockISensorManager> m_sensor_manager_;
338 scoped_refptr<MockISensorCollection> m_sensor_collection_;
339 scoped_refptr<MockISensor> m_sensor_;
340 base::win::ScopedComPtr<ISensorEvents> sensor_events_;
341 std::unique_ptr<base::MessageLoop> message_loop_;
342 scoped_refptr<PlatformSensor> m_platform_sensor_;
343 // Inner run loop used to wait for async sensor creation callback.
344 std::unique_ptr<base::RunLoop> run_loop_;
345 };
346
347 // Mock for PlatformSensor's client interface that is used to deliver
348 // error and data changes notifications.
349 class MockPlatformSensorClient : public PlatformSensor::Client {
350 public:
351 MockPlatformSensorClient() = default;
352 explicit MockPlatformSensorClient(scoped_refptr<PlatformSensor> sensor)
353 : sensor_(sensor) {
354 if (sensor_)
355 sensor_->AddClient(this);
356
357 ON_CALL(*this, IsNotificationSuspended()).WillByDefault(Return(false));
358 }
359
360 ~MockPlatformSensorClient() override {
361 if (sensor_)
362 sensor_->RemoveClient(this);
363 }
364
365 // PlatformSensor::Client interface.
366 MOCK_METHOD0(OnSensorReadingChanged, void());
367 MOCK_METHOD0(OnSensorError, void());
368 MOCK_METHOD0(IsNotificationSuspended, bool());
369
370 private:
371 scoped_refptr<PlatformSensor> sensor_;
372 };
373
374 // Tests that PlatformSensorManager returns null sensor when sensor
375 // is not implemented.
376 TEST_F(PlatformSensorAndProviderTestWin, SensorIsNotImplemented) {
377 EXPECT_CALL(*m_sensor_manager_,
378 GetSensorsByType(SENSOR_TYPE_ACCELEROMETER_3D, _))
379 .Times(0);
380 EXPECT_FALSE(CreateSensor(SensorType::ACCELEROMETER));
381 }
382
383 // Tests that PlatformSensorManager returns null sensor when sensor
384 // is implemented, but not supported by the hardware.
385 TEST_F(PlatformSensorAndProviderTestWin, SensorIsNotSupported) {
386 EXPECT_CALL(*m_sensor_manager_,
387 GetSensorsByType(SENSOR_TYPE_AMBIENT_LIGHT, _))
388 .Times(1);
389 ON_CALL(*m_sensor_manager_, GetSensorsByType(SENSOR_TYPE_AMBIENT_LIGHT, _))
390 .WillByDefault(Invoke([](REFSENSOR_TYPE_ID, ISensorCollection** result) {
Reilly Grant (use Gerrit) 2016/10/27 00:59:19 Here and also elsewhere such as above in SetSuppor
shalamov 2016/10/27 13:51:07 Done.
391 *result = nullptr;
392 return E_FAIL;
393 }));
394 EXPECT_FALSE(CreateSensor(SensorType::AMBIENT_LIGHT));
395 }
396
397 // Tests that PlatformSensorManager returns correct sensor when sensor
398 // is supported by the hardware.
399 TEST_F(PlatformSensorAndProviderTestWin, SensorIsSupported) {
400 SetSupportedSensor(SENSOR_TYPE_AMBIENT_LIGHT);
401 auto sensor = CreateSensor(SensorType::AMBIENT_LIGHT);
402 EXPECT_TRUE(sensor);
403 EXPECT_EQ(SensorType::AMBIENT_LIGHT, sensor->GetType());
404 }
405
406 // Tests that PlatformSensor::StartListening fails when provided reporting
407 // frequency is above hardware capabilities.
408 TEST_F(PlatformSensorAndProviderTestWin, StartFails) {
409 SetSupportedReportingFrequency(1);
410 SetSupportedSensor(SENSOR_TYPE_AMBIENT_LIGHT);
411
412 auto sensor = CreateSensor(SensorType::AMBIENT_LIGHT);
413 EXPECT_TRUE(sensor);
414
415 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
416 PlatformSensorConfiguration configuration(10);
417 EXPECT_FALSE(sensor->StartListening(client.get(), configuration));
418 }
419
420 // Tests that PlatformSensor::StartListening succeeds and notification about
421 // modified sensor reading is sent to the PlatformSensor::Client interface.
422 TEST_F(PlatformSensorAndProviderTestWin, SensorStarted) {
423 SetSupportedReportingFrequency(10);
424 SetSupportedSensor(SENSOR_TYPE_AMBIENT_LIGHT);
425
426 EXPECT_CALL(*m_sensor_, SetEventSink(NotNull())).Times(1);
427 EXPECT_CALL(*m_sensor_, SetEventSink(IsNull())).Times(1);
428 EXPECT_CALL(*m_sensor_, SetProperties(NotNull(), _)).Times(1);
429
430 ON_CALL(*m_sensor_, SetProperties(_, _))
431 .WillByDefault(Invoke(
432 [](IPortableDeviceValues* props, IPortableDeviceValues** result) {
433 ULONG value = 0;
434 HRESULT hr = props->GetUnsignedIntegerValue(
435 SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, &value);
436 EXPECT_THAT(SUCCEEDED(hr), true);
Reilly Grant (use Gerrit) 2016/10/27 00:59:19 Comparisons to true can be fishy. Use EXPECT_TRUE(
shalamov 2016/10/27 13:51:07 Done.
437 // 10Hz is 100msec
438 EXPECT_THAT(value, 100);
439 return hr;
440 }));
441
442 auto sensor = CreateSensor(SensorType::AMBIENT_LIGHT);
443 EXPECT_TRUE(sensor);
444
445 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
446 PlatformSensorConfiguration configuration(10);
447 EXPECT_TRUE(sensor->StartListening(client.get(), configuration));
448
449 EXPECT_CALL(*client, OnSensorReadingChanged()).Times(1);
450 GenerateDataUpdatedEvent(SENSOR_DATA_TYPE_LIGHT_LEVEL_LUX, 3.14);
451 base::RunLoop().RunUntilIdle();
452 EXPECT_TRUE(sensor->StopListening(client.get(), configuration));
453 }
454
455 // Tests that OnSensorError is called when sensor is disconnected.
456 TEST_F(PlatformSensorAndProviderTestWin, SensorRemoved) {
457 SetSupportedSensor(SENSOR_TYPE_AMBIENT_LIGHT);
458 auto sensor = CreateSensor(SensorType::AMBIENT_LIGHT);
459 EXPECT_TRUE(sensor);
460
461 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
462 PlatformSensorConfiguration configuration(10);
463 EXPECT_TRUE(sensor->StartListening(client.get(), configuration));
464 EXPECT_CALL(*client, OnSensorError()).Times(1);
465
466 GenerateLeaveEvent();
467 base::RunLoop().RunUntilIdle();
468 }
469
470 // Tests that OnSensorError is called when sensor is in an error state.
471 TEST_F(PlatformSensorAndProviderTestWin, SensorStateChangedToError) {
472 SetSupportedSensor(SENSOR_TYPE_AMBIENT_LIGHT);
473 auto sensor = CreateSensor(SensorType::AMBIENT_LIGHT);
474 EXPECT_TRUE(sensor);
475
476 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
477 PlatformSensorConfiguration configuration(10);
478 EXPECT_TRUE(sensor->StartListening(client.get(), configuration));
479 EXPECT_CALL(*client, OnSensorError()).Times(1);
480
481 GenerateStateChangeEvent(SENSOR_STATE_ERROR);
482 base::RunLoop().RunUntilIdle();
483 }
484
485 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698