Chromium Code Reviews| 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 |