OLD | NEW |
---|---|
(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 package org.chromium.device.sensors; | |
6 | |
7 import static org.junit.Assert.assertEquals; | |
8 import static org.junit.Assert.assertNotNull; | |
9 import static org.junit.Assert.assertNull; | |
10 import static org.mockito.ArgumentMatchers.any; | |
11 import static org.mockito.ArgumentMatchers.anyInt; | |
12 import static org.mockito.Mockito.doAnswer; | |
13 import static org.mockito.Mockito.doNothing; | |
14 import static org.mockito.Mockito.doReturn; | |
15 import static org.mockito.Mockito.mock; | |
16 import static org.mockito.Mockito.never; | |
17 import static org.mockito.Mockito.times; | |
18 import static org.mockito.Mockito.verify; | |
19 | |
20 import android.content.Context; | |
21 import android.hardware.Sensor; | |
22 import android.hardware.SensorEvent; | |
23 import android.hardware.SensorEventListener; | |
24 import android.hardware.SensorManager; | |
25 import android.os.Handler; | |
26 import android.util.SparseArray; | |
27 | |
28 import org.chromium.base.test.util.Feature; | |
29 import org.chromium.mojom.device.mojom.ReportingMode; | |
30 import org.chromium.mojom.device.mojom.SensorReadBuffer; | |
31 import org.chromium.mojom.device.mojom.SensorType; | |
32 import org.chromium.testing.local.LocalRobolectricTestRunner; | |
33 | |
34 import org.junit.Before; | |
35 import org.junit.Test; | |
36 import org.junit.runner.RunWith; | |
37 import org.mockito.Mock; | |
38 import org.mockito.MockitoAnnotations; | |
39 import org.mockito.invocation.InvocationOnMock; | |
40 import org.mockito.stubbing.Answer; | |
41 import org.robolectric.annotation.Config; | |
42 | |
43 import java.lang.reflect.Field; | |
44 import java.lang.reflect.Modifier; | |
45 import java.nio.ByteBuffer; | |
46 import java.nio.ByteOrder; | |
47 import java.util.ArrayList; | |
48 import java.util.List; | |
49 | |
50 /** | |
51 * Unit tests for PlatformSensor and PlatformSensorProvider. | |
52 */ | |
53 @RunWith(LocalRobolectricTestRunner.class) | |
54 @Config(manifest = Config.NONE) | |
55 public class PlatformSensorProviderTest { | |
56 @Mock | |
57 private Context mContext; | |
58 @Mock | |
59 private SensorManager mSensorManager; | |
60 @Mock | |
61 private PlatformSensorProvider mPlatformSensorProvider; | |
62 private ByteBuffer mSharedBuffer; | |
63 private final SparseArray<List<Sensor>> mMockSensors = new SparseArray<>(); | |
64 private static final long PLATFORM_SENSOR_ANDROID = 123456789L; | |
65 private static final long PLATFORM_SENSOR_TIMESTAMP = 314159265358979L; | |
66 private static final double MILLISECONDS_IN_NANOSECOND = 0.000001d; | |
67 | |
68 @Before | |
69 public void setUp() { | |
70 MockitoAnnotations.initMocks(this); | |
71 // Remove all mock sensors before the test. | |
72 mMockSensors.clear(); | |
73 doReturn(mSensorManager).when(mContext).getSystemService(Context.SENSOR_ SERVICE); | |
74 doAnswer(new Answer<List<Sensor>>() { | |
75 @Override | |
76 public List<Sensor> answer(final InvocationOnMock invocation) throws Throwable { | |
77 return getMockSensors((int) (Integer) (invocation.getArguments() )[0]); | |
78 } | |
79 }) | |
timvolodine
2016/09/07 14:51:06
is the indentation here correct? (looks a bit weir
Ted C
2016/09/07 18:12:24
I would do:
doAnswer(
new Answer<List<Sen
shalamov
2016/09/07 18:49:18
Thanks, I will format it manually.
shalamov
2016/09/08 13:40:49
Done.
| |
80 .when(mSensorManager) | |
81 .getSensorList(anyInt()); | |
82 doReturn(mSensorManager).when(mPlatformSensorProvider).getSensorManager( ); | |
83 doReturn(new Handler()).when(mPlatformSensorProvider).getHandler(); | |
84 // By default, allow successful registration of SensorEventListeners. | |
85 doReturn(true) | |
86 .when(mSensorManager) | |
87 .registerListener(any(SensorEventListener.class), any(Sensor.cla ss), anyInt(), | |
88 any(Handler.class)); | |
89 doNothing().when(mPlatformSensorProvider).sensorStarted(any(PlatformSens or.class)); | |
90 doNothing().when(mPlatformSensorProvider).sensorStopped(any(PlatformSens or.class)); | |
91 } | |
92 | |
93 /** | |
94 * Test that PlatformSensorProvider cannot create sensors if sensor manager is null. | |
95 */ | |
96 @Test | |
97 @Feature({"PlatformSensorProvider"}) | |
98 public void testNullSensorManager() { | |
99 doReturn(null).when(mContext).getSystemService(Context.SENSOR_SERVICE); | |
100 PlatformSensorProvider provider = PlatformSensorProvider.create(mContext ); | |
101 PlatformSensor sensor = provider.createSensor(SensorType.AMBIENT_LIGHT); | |
102 assertNull(sensor); | |
103 } | |
104 | |
105 /** | |
106 * Test that PlatformSensorProvider cannot create sensors that are not suppo rted. | |
107 */ | |
108 @Test | |
109 @Feature({"PlatformSensorProvider"}) | |
110 public void testSensorNotSupported() { | |
111 PlatformSensorProvider provider = PlatformSensorProvider.create(mContext ); | |
112 PlatformSensor sensor = provider.createSensor(SensorType.AMBIENT_LIGHT); | |
113 assertNull(sensor); | |
114 } | |
115 | |
116 /** | |
117 * Test that PlatformSensorProvider maps device::SensorType to android.hardw are.Sensor.TYPE_*. | |
118 */ | |
119 @Test | |
120 @Feature({"PlatformSensorProvider"}) | |
121 public void testSensorTypeMappings() { | |
122 PlatformSensorProvider provider = PlatformSensorProvider.create(mContext ); | |
123 provider.createSensor(SensorType.AMBIENT_LIGHT); | |
124 verify(mSensorManager).getSensorList(Sensor.TYPE_LIGHT); | |
125 provider.createSensor(SensorType.ACCELEROMETER); | |
126 verify(mSensorManager).getSensorList(Sensor.TYPE_ACCELEROMETER); | |
127 provider.createSensor(SensorType.LINEAR_ACCELERATION); | |
128 verify(mSensorManager).getSensorList(Sensor.TYPE_LINEAR_ACCELERATION); | |
129 provider.createSensor(SensorType.GYROSCOPE); | |
130 verify(mSensorManager).getSensorList(Sensor.TYPE_GYROSCOPE); | |
131 provider.createSensor(SensorType.MAGNETOMETER); | |
132 verify(mSensorManager).getSensorList(Sensor.TYPE_MAGNETIC_FIELD); | |
133 } | |
134 | |
135 /** | |
136 * Test that PlatformSensorProvider can create sensors that are supported. | |
137 */ | |
138 @Test | |
139 @Feature({"PlatformSensorProvider"}) | |
140 public void testSensorSupported() { | |
141 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_LIGHT, | |
142 SensorType.AMBIENT_LIGHT, Sensor.REPORTING_MODE_ON_CHANGE); | |
143 assertNotNull(sensor); | |
144 } | |
145 | |
146 /** | |
147 * Test that PlatformSensor notifies PlatformSensorProvider when it starts ( stops) polling, | |
148 * and SensorEventListener is registered (unregistered) to sensor manager. | |
149 */ | |
150 @Test | |
151 @Feature({"PlatformSensor"}) | |
152 public void testSensorStartStop() { | |
153 addMockSensor(50000, Sensor.TYPE_ACCELEROMETER, Sensor.REPORTING_MODE_CO NTINUOUS); | |
154 PlatformSensor sensor = | |
155 PlatformSensor.create(Sensor.TYPE_ACCELEROMETER, 3, mPlatformSen sorProvider); | |
156 assertNotNull(sensor); | |
157 | |
158 sensor.startSensor(5); | |
159 sensor.stopSensor(); | |
160 | |
161 // Multiple start invocations. | |
162 sensor.startSensor(1); | |
163 sensor.startSensor(2); | |
164 sensor.startSensor(3); | |
165 // Same frequency, should not restart sensor | |
166 sensor.startSensor(3); | |
167 | |
168 // Started polling with 5, 1, 2 and 3 Hz frequency. | |
169 verify(mPlatformSensorProvider, times(4)).getHandler(); | |
170 verify(mPlatformSensorProvider, times(4)).sensorStarted(sensor); | |
171 verify(mSensorManager, times(4)) | |
172 .registerListener(any(SensorEventListener.class), any(Sensor.cla ss), anyInt(), | |
173 any(Handler.class)); | |
174 | |
175 sensor.stopSensor(); | |
176 sensor.stopSensor(); | |
177 verify(mPlatformSensorProvider, times(3)).sensorStopped(sensor); | |
178 verify(mSensorManager, times(4)) | |
179 .unregisterListener(any(SensorEventListener.class), any(Sensor.c lass)); | |
180 } | |
181 | |
182 /** | |
183 * Test that PlatformSensorProvider is notified when PlatformSensor starts a nd in case of | |
184 * failure, tells PlatformSensorProvider that the sensor is stopped, so that polling thread | |
185 * can be stopped. | |
186 */ | |
187 @Test | |
188 @Feature({"PlatformSensor"}) | |
189 public void testSensorStartFails() { | |
190 addMockSensor(50000, Sensor.TYPE_ACCELEROMETER, Sensor.REPORTING_MODE_CO NTINUOUS); | |
191 PlatformSensor sensor = | |
192 PlatformSensor.create(Sensor.TYPE_ACCELEROMETER, 3, mPlatformSen sorProvider); | |
193 assertNotNull(sensor); | |
194 | |
195 doReturn(false) | |
196 .when(mSensorManager) | |
197 .registerListener(any(SensorEventListener.class), any(Sensor.cla ss), anyInt(), | |
198 any(Handler.class)); | |
199 | |
200 sensor.startSensor(5); | |
201 verify(mPlatformSensorProvider, times(1)).sensorStarted(sensor); | |
202 verify(mPlatformSensorProvider, times(1)).sensorStopped(sensor); | |
203 verify(mPlatformSensorProvider, times(1)).getHandler(); | |
204 } | |
205 | |
206 /** | |
207 * Test that PlatformSensor correctly checks supported configuration. | |
208 */ | |
209 @Test | |
210 @Feature({"PlatformSensor"}) | |
211 public void testSensorConfiguration() { | |
212 // 5Hz min delay | |
213 PlatformSensor sensor = createPlatformSensor(200000, Sensor.TYPE_ACCELER OMETER, | |
214 SensorType.ACCELEROMETER, Sensor.REPORTING_MODE_CONTINUOUS); | |
215 assertEquals(true, sensor.checkSensorConfiguration(5)); | |
216 assertEquals(false, sensor.checkSensorConfiguration(6)); | |
217 } | |
218 | |
219 /** | |
220 * Test that PlatformSensor correctly returns its reporting mode. | |
221 */ | |
222 @Test | |
223 @Feature({"PlatformSensor"}) | |
224 public void testSensorOnChangeReportingMode() { | |
225 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_LIGHT, | |
226 SensorType.AMBIENT_LIGHT, Sensor.REPORTING_MODE_ON_CHANGE); | |
227 assertEquals(ReportingMode.ON_CHANGE, sensor.getReportingMode()); | |
228 } | |
229 | |
230 /** | |
231 * Test that PlatformSensor doesn't notify client about sensor reading chang es when | |
232 * sensor reporting mode is ReportingMode.CONTINUOUS. | |
233 */ | |
234 @Test | |
235 @Feature({"PlatformSensor"}) | |
236 public void testSensorNotifierIsNotCalled() | |
237 throws NoSuchFieldException, IllegalAccessException { | |
238 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_ACCELERO METER, | |
239 SensorType.ACCELEROMETER, Sensor.REPORTING_MODE_CONTINUOUS); | |
240 PlatformSensorNotifier mockNotifier = mock(PlatformSensorNotifier.class) ; | |
241 initPlatformSensor(sensor, SensorReadBuffer.READ_BUFFER_SIZE, mockNotifi er); | |
242 SensorEvent event = createFakeEvent(3); | |
243 sensor.onSensorChanged(event); | |
244 verify(mockNotifier, never()).sensorReadingChanged(); | |
245 } | |
246 | |
247 /** | |
248 * Test that shared buffer is correctly populated from SensorEvent. | |
249 */ | |
250 @Test | |
251 @Feature({"PlatformSensor"}) | |
252 public void testSensorBufferFromEvent() throws NoSuchFieldException, Illegal AccessException { | |
253 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_LIGHT, | |
254 SensorType.AMBIENT_LIGHT, Sensor.REPORTING_MODE_ON_CHANGE); | |
255 PlatformSensorNotifier mockNotifier = mock(PlatformSensorNotifier.class) ; | |
256 initPlatformSensor(sensor, SensorReadBuffer.READ_BUFFER_SIZE, mockNotifi er); | |
257 SensorEvent event = createFakeEvent(1); | |
258 sensor.onSensorChanged(event); | |
259 verify(mockNotifier, times(1)).sensorReadingChanged(); | |
260 // Verify that timestamp correctly stored in buffer. | |
261 assertEquals(MILLISECONDS_IN_NANOSECOND * PLATFORM_SENSOR_TIMESTAMP, | |
262 mSharedBuffer.getDouble(), MILLISECONDS_IN_NANOSECOND); | |
263 // Verify illuminance value is correctly stored in buffer and precision is not lost. | |
264 assertEquals(1.0d + MILLISECONDS_IN_NANOSECOND, mSharedBuffer.getDouble( ), | |
265 MILLISECONDS_IN_NANOSECOND); | |
266 } | |
267 | |
268 /** | |
269 * Test that PlatformSensor notifies client when there is an error. | |
270 */ | |
271 @Test | |
272 @Feature({"PlatformSensor"}) | |
273 public void testSensorInvalidReadingSize() throws NoSuchFieldException, Ille galAccessException { | |
274 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_ACCELERO METER, | |
275 SensorType.ACCELEROMETER, Sensor.REPORTING_MODE_CONTINUOUS); | |
276 PlatformSensorNotifier mockNotifier = mock(PlatformSensorNotifier.class) ; | |
277 initPlatformSensor(sensor, SensorReadBuffer.READ_BUFFER_SIZE, mockNotifi er); | |
278 // Accelerometer requires 3 reading values x,y and z, create fake event with 1 reading | |
279 // value. | |
280 SensorEvent event = createFakeEvent(1); | |
281 sensor.onSensorChanged(event); | |
282 verify(mockNotifier, times(1)).sensorError(); | |
283 } | |
284 | |
285 /** | |
286 * Test that PlatformSensor notifies client when there is an error. | |
287 */ | |
288 @Test | |
289 @Feature({"PlatformSensor"}) | |
290 public void testSensorInvalidBufferSize() throws NoSuchFieldException, Illeg alAccessException { | |
291 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_ACCELERO METER, | |
292 SensorType.ACCELEROMETER, Sensor.REPORTING_MODE_CONTINUOUS); | |
293 PlatformSensorNotifier mockNotifier = mock(PlatformSensorNotifier.class) ; | |
294 // Create buffer that doesn't have enough capacity to hold sensor readin g values. | |
295 initPlatformSensor(sensor, 2, mockNotifier); | |
296 SensorEvent event = createFakeEvent(3); | |
297 sensor.onSensorChanged(event); | |
298 verify(mockNotifier, times(1)).sensorError(); | |
299 } | |
300 | |
301 /** | |
302 * Test that multiple PlatformSensor instances correctly register (unregiste r) to | |
303 * sensor manager and notify PlatformSensorProvider when they start (stop) p olling for data. | |
304 */ | |
305 @Test | |
306 @Feature({"PlatformSensor"}) | |
307 public void testMultipleSensorTypeInstances() { | |
308 addMockSensor(200000, Sensor.TYPE_LIGHT, Sensor.REPORTING_MODE_ON_CHANGE ); | |
309 addMockSensor(50000, Sensor.TYPE_ACCELEROMETER, Sensor.REPORTING_MODE_CO NTINUOUS); | |
310 | |
311 PlatformSensor lightSensor = | |
312 PlatformSensor.create(Sensor.TYPE_LIGHT, 1, mPlatformSensorProvi der); | |
313 assertNotNull(lightSensor); | |
314 | |
315 PlatformSensor accelerometerSensor = | |
316 PlatformSensor.create(Sensor.TYPE_ACCELEROMETER, 3, mPlatformSen sorProvider); | |
317 assertNotNull(accelerometerSensor); | |
318 | |
319 lightSensor.startSensor(3); | |
320 accelerometerSensor.startSensor(10); | |
321 lightSensor.stopSensor(); | |
322 accelerometerSensor.stopSensor(); | |
323 | |
324 verify(mPlatformSensorProvider, times(2)).getHandler(); | |
325 verify(mPlatformSensorProvider, times(1)).sensorStarted(lightSensor); | |
326 verify(mPlatformSensorProvider, times(1)).sensorStarted(accelerometerSen sor); | |
327 verify(mPlatformSensorProvider, times(1)).sensorStopped(lightSensor); | |
328 verify(mPlatformSensorProvider, times(1)).sensorStopped(accelerometerSen sor); | |
329 verify(mSensorManager, times(2)) | |
330 .registerListener(any(SensorEventListener.class), any(Sensor.cla ss), anyInt(), | |
331 any(Handler.class)); | |
332 verify(mSensorManager, times(2)) | |
333 .unregisterListener(any(SensorEventListener.class), any(Sensor.c lass)); | |
timvolodine
2016/09/07 14:51:06
Regarding multiple sensors I was actually hoping f
shalamov
2016/09/07 18:49:18
Mockito / JUnit tests are run on 'testing thread',
timvolodine
2016/09/08 12:35:06
Would a simpler approach to just check "mSensorsTh
shalamov
2016/09/08 13:40:49
Done.
| |
334 } | |
335 | |
336 private SensorEvent createFakeEvent(int readingValuesNum) | |
337 throws NoSuchFieldException, IllegalAccessException { | |
338 SensorEvent mockEvent = mock(SensorEvent.class); | |
Ted C
2016/09/07 18:12:24
This seems more complicated than it needs to be.
shalamov
2016/09/07 18:49:18
That's what I tried in the beginning, but it looks
Ted C
2016/09/07 20:08:12
Oh android...can you use reflection to just make t
shalamov
2016/09/08 13:40:49
Done.
| |
339 mockEvent.timestamp = PLATFORM_SENSOR_TIMESTAMP; | |
340 float values[] = new float[readingValuesNum]; | |
341 for (int i = 0; i < readingValuesNum; ++i) { | |
342 values[i] = (float) (i + 1.0f + MILLISECONDS_IN_NANOSECOND); | |
343 } | |
344 | |
345 Field valuesField = SensorEvent.class.getDeclaredField("values"); | |
346 valuesField.setAccessible(true); | |
347 Field modifiersField = Field.class.getDeclaredField("modifiers"); | |
348 modifiersField.setAccessible(true); | |
349 modifiersField.setInt(valuesField, valuesField.getModifiers() & ~Modifie r.FINAL); | |
350 valuesField.set(mockEvent, values); | |
351 return mockEvent; | |
352 } | |
353 | |
354 private void initPlatformSensor( | |
355 PlatformSensor sensor, long readingSize, PlatformSensorNotifier noti fier) { | |
356 mSharedBuffer = ByteBuffer.allocate((int) readingSize); | |
357 mSharedBuffer.order(ByteOrder.nativeOrder()); | |
358 sensor.initPlatformSensorAndroid(notifier, PLATFORM_SENSOR_ANDROID, mSha redBuffer); | |
359 } | |
360 | |
361 private void addMockSensor(long minDelayUsec, int sensorType, int reportingM ode) { | |
362 List<Sensor> mockSensorList = new ArrayList<Sensor>(); | |
363 Sensor mockSensor = mock(Sensor.class); | |
364 doReturn((int) minDelayUsec).when(mockSensor).getMinDelay(); | |
365 doReturn(reportingMode).when(mockSensor).getReportingMode(); | |
366 doReturn(sensorType).when(mockSensor).getType(); | |
367 mockSensorList.add(mockSensor); | |
368 mMockSensors.put(sensorType, mockSensorList); | |
369 } | |
370 | |
371 private List<Sensor> getMockSensors(int sensorType) { | |
372 if (mMockSensors.indexOfKey(sensorType) >= 0) { | |
373 return mMockSensors.get(sensorType); | |
374 } | |
375 return new ArrayList<Sensor>(); | |
376 } | |
377 | |
378 private PlatformSensor createPlatformSensor( | |
379 long minDelayUsec, int androidSensorType, int mojoSensorType, int re portingMode) { | |
380 addMockSensor(minDelayUsec, androidSensorType, reportingMode); | |
381 PlatformSensorProvider provider = PlatformSensorProvider.create(mContext ); | |
382 return provider.createSensor(mojoSensorType); | |
383 } | |
384 } | |
OLD | NEW |