OLD | NEW |
| (Empty) |
1 // Copyright 2017 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.shape_detection; | |
6 | |
7 import static org.junit.Assert.assertEquals; | |
8 import static org.junit.Assert.assertTrue; | |
9 | |
10 import android.graphics.Bitmap; | |
11 import android.graphics.PointF; | |
12 import android.media.FaceDetector; | |
13 import android.media.FaceDetector.Face; | |
14 | |
15 import org.junit.Before; | |
16 import org.junit.Test; | |
17 import org.junit.runner.RunWith; | |
18 import org.mockito.ArgumentCaptor; | |
19 import org.mockito.Mockito; | |
20 import org.mockito.MockitoAnnotations; | |
21 import org.mockito.invocation.InvocationOnMock; | |
22 import org.mockito.stubbing.Answer; | |
23 import org.robolectric.ParameterizedRobolectricTestRunner; | |
24 import org.robolectric.ParameterizedRobolectricTestRunner.Parameters; | |
25 import org.robolectric.annotation.Config; | |
26 import org.robolectric.shadows.ShadowLog; | |
27 | |
28 import org.chromium.base.ThreadUtils; | |
29 import org.chromium.base.test.util.Feature; | |
30 import org.chromium.mojo.system.SharedBufferHandle; | |
31 import org.chromium.mojo.system.SharedBufferHandle.MapFlags; | |
32 import org.chromium.shape_detection.mojom.FaceDetection; | |
33 import org.chromium.shape_detection.mojom.FaceDetectionResult; | |
34 import org.chromium.shape_detection.mojom.FaceDetectorOptions; | |
35 | |
36 import java.nio.ByteBuffer; | |
37 import java.util.Arrays; | |
38 import java.util.Collection; | |
39 | |
40 /** | |
41 * Test suite for Java Face Detection. | |
42 */ | |
43 @RunWith(ParameterizedRobolectricTestRunner.class) | |
44 @Config(sdk = 21, manifest = Config.NONE) | |
45 public class FaceDetectionImplTest { | |
46 private static final int VALID_WIDTH = 1; | |
47 private static final int VALID_HEIGHT = 1; | |
48 private static final int INVALID_WIDTH = 0; | |
49 private static final long NUM_BYTES = VALID_WIDTH * VALID_HEIGHT * 4; | |
50 | |
51 @Parameters | |
52 public static Collection<Object[]> data() { | |
53 return Arrays.asList(new Object[][] {{true}, {false}}); | |
54 } | |
55 | |
56 // Class under test. | |
57 private final FaceDetectionImpl mFaceDetectionImpl; | |
58 | |
59 public FaceDetectionImplTest(boolean fastMode) { | |
60 FaceDetectorOptions options = new FaceDetectorOptions(); | |
61 options.fastMode = fastMode; | |
62 options.maxDetectedFaces = 1; | |
63 mFaceDetectionImpl = new FaceDetectionImpl(options); | |
64 } | |
65 | |
66 @Before | |
67 public void setUp() { | |
68 ShadowLog.stream = System.out; | |
69 MockitoAnnotations.initMocks(this); | |
70 } | |
71 | |
72 /** | |
73 * Verify construction works. | |
74 */ | |
75 @Test | |
76 @Feature({"ShapeDetection"}) | |
77 public void testConstruction() { | |
78 assertTrue("Should be on UI thread", ThreadUtils.runningOnUiThread()); | |
79 } | |
80 | |
81 /** | |
82 * Verify detection fails if the SharedBufferHandle is invalid. | |
83 */ | |
84 @Test | |
85 @Feature({"ShapeDetection"}) | |
86 public void testDetectionFailsWithInvalidHandle() { | |
87 assertTrue("Should be on UI thread", ThreadUtils.runningOnUiThread()); | |
88 | |
89 SharedBufferHandle sharedBuffer = Mockito.mock(SharedBufferHandle.class)
; | |
90 Mockito.when(sharedBuffer.isValid()).thenReturn(false); | |
91 | |
92 FaceDetection.DetectResponse callback = Mockito.mock(FaceDetection.Detec
tResponse.class); | |
93 ArgumentCaptor<FaceDetectionResult[]> argument = | |
94 ArgumentCaptor.forClass(FaceDetectionResult[].class); | |
95 | |
96 mFaceDetectionImpl.detect(sharedBuffer, VALID_WIDTH, VALID_HEIGHT, callb
ack); | |
97 | |
98 Mockito.verify(sharedBuffer, Mockito.times(1)).isValid(); | |
99 Mockito.verify(callback, Mockito.times(1)).call(argument.capture()); | |
100 assertEquals("result", 0, argument.getValue().length); | |
101 } | |
102 | |
103 /** | |
104 * Verify detection fails if the sent dimensions are ugly. | |
105 */ | |
106 @Test | |
107 @Feature({"ShapeDetection"}) | |
108 public void testDetectionFailsWithInvalidDimensions() { | |
109 assertTrue("Should be on UI thread", ThreadUtils.runningOnUiThread()); | |
110 | |
111 SharedBufferHandle sharedBuffer = Mockito.mock(SharedBufferHandle.class)
; | |
112 Mockito.when(sharedBuffer.isValid()).thenReturn(true); | |
113 | |
114 FaceDetection.DetectResponse callback = Mockito.mock(FaceDetection.Detec
tResponse.class); | |
115 ArgumentCaptor<FaceDetectionResult[]> argument = | |
116 ArgumentCaptor.forClass(FaceDetectionResult[].class); | |
117 | |
118 mFaceDetectionImpl.detect(sharedBuffer, INVALID_WIDTH, VALID_HEIGHT, cal
lback); | |
119 | |
120 Mockito.verify(sharedBuffer, Mockito.times(1)).isValid(); | |
121 Mockito.verify(callback, Mockito.times(1)).call(argument.capture()); | |
122 assertEquals("result", 0, argument.getValue().length); | |
123 } | |
124 | |
125 /** | |
126 * Verify detection fails if SharedBufferHandle fails to map(). | |
127 */ | |
128 @Test | |
129 @Feature({"ShapeDetection"}) | |
130 public void testDetectionFailsWithWronglyMappedBuffer() { | |
131 assertTrue("Should be on UI thread", ThreadUtils.runningOnUiThread()); | |
132 | |
133 SharedBufferHandle sharedBuffer = Mockito.mock(SharedBufferHandle.class)
; | |
134 Mockito.when(sharedBuffer.isValid()).thenReturn(true); | |
135 Mockito.when(sharedBuffer.map( | |
136 Mockito.eq(0L), Mockito.eq(NUM_BYTES), Mockito.any(
MapFlags.class))) | |
137 .thenReturn(ByteBuffer.allocate(0)); | |
138 | |
139 FaceDetection.DetectResponse callback = Mockito.mock(FaceDetection.Detec
tResponse.class); | |
140 ArgumentCaptor<FaceDetectionResult[]> argument = | |
141 ArgumentCaptor.forClass(FaceDetectionResult[].class); | |
142 | |
143 mFaceDetectionImpl.detect(sharedBuffer, VALID_WIDTH, VALID_HEIGHT, callb
ack); | |
144 | |
145 Mockito.verify(sharedBuffer, Mockito.times(1)).isValid(); | |
146 Mockito.verify(sharedBuffer, Mockito.times(1)) | |
147 .map(Mockito.eq(0L), Mockito.eq(NUM_BYTES), Mockito.any(MapFlags
.class)); | |
148 Mockito.verify(callback, Mockito.times(1)).call(argument.capture()); | |
149 assertEquals("result", 0, argument.getValue().length); | |
150 } | |
151 | |
152 /** | |
153 * Verify detection works. | |
154 */ | |
155 @Test | |
156 @Feature({"ShapeDetection"}) | |
157 public void testDetection() { | |
158 assertTrue("Should be on UI thread", ThreadUtils.runningOnUiThread()); | |
159 | |
160 SharedBufferHandle sharedBuffer = Mockito.mock(SharedBufferHandle.class)
; | |
161 Mockito.when(sharedBuffer.isValid()).thenReturn(true); | |
162 Mockito.when(sharedBuffer.map( | |
163 Mockito.eq(0L), Mockito.eq(NUM_BYTES), Mockito.any(
MapFlags.class))) | |
164 .thenReturn(ByteBuffer.allocate((int) NUM_BYTES)); | |
165 | |
166 FaceDetection.DetectResponse callback = Mockito.mock(FaceDetection.Detec
tResponse.class); | |
167 ArgumentCaptor<FaceDetectionResult[]> argument = | |
168 ArgumentCaptor.forClass(FaceDetectionResult[].class); | |
169 | |
170 // We have to add a |faceDetector| mock that inside returns a |face| moc
k. To spice things | |
171 // up, some methods, findFaces() and getMidPoint(), modify parameters so
we need doAnswer(). | |
172 final float eyesDistance = 1.0f; | |
173 final float faceCenterX = 2.0f; | |
174 final float faceCenterY = 3.0f; | |
175 | |
176 Face face = Mockito.mock(Face.class); | |
177 Mockito.when(face.eyesDistance()).thenReturn(eyesDistance); | |
178 Mockito.doAnswer(new Answer<Void>() { | |
179 @Override | |
180 public Void answer(InvocationOnMock invocation) { | |
181 Object[] args = invocation.getArguments(); | |
182 PointF midPoint = (PointF) args[0]; | |
183 midPoint.set(faceCenterX, faceCenterY); | |
184 return null; | |
185 } | |
186 }) | |
187 .when(face) | |
188 .getMidPoint(Mockito.any(PointF.class)); | |
189 | |
190 FaceDetector faceDetector = Mockito.mock(FaceDetector.class); | |
191 FaceDetectionImpl.setFaceDetector(faceDetector); | |
192 Mockito.doAnswer(new Answer<Integer>() { | |
193 @Override | |
194 public Integer answer(InvocationOnMock invocation) throws Throwa
ble { | |
195 Object[] args = invocation.getArguments(); | |
196 Face[] faceArray = (Face[]) args[1]; | |
197 faceArray[0] = face; | |
198 return 1; | |
199 } | |
200 }) | |
201 .when(faceDetector) | |
202 .findFaces(Mockito.any(Bitmap.class), Mockito.any()); | |
203 | |
204 mFaceDetectionImpl.detect(sharedBuffer, VALID_WIDTH, VALID_HEIGHT, callb
ack); | |
205 | |
206 Mockito.verify(sharedBuffer, Mockito.times(1)).isValid(); | |
207 Mockito.verify(sharedBuffer, Mockito.times(1)) | |
208 .map(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(MapFlags.
class)); | |
209 | |
210 Mockito.verify(faceDetector, Mockito.times(1)) | |
211 .findFaces(Mockito.any(Bitmap.class), Mockito.any()); | |
212 | |
213 // Detection happens asynchronously: give some timeout. | |
214 Mockito.verify(callback, Mockito.timeout(3000 /* milliseconds */).times(
1)) | |
215 .call(argument.capture()); | |
216 assertEquals("result", 1, argument.getValue().length); | |
217 assertEquals("width", 2 * eyesDistance, argument.getValue()[0].boundingB
ox.width, 0.1); | |
218 assertEquals("height", 2 * eyesDistance, argument.getValue()[0].bounding
Box.height, 0.1); | |
219 assertEquals("x", faceCenterX - eyesDistance, argument.getValue()[0].bou
ndingBox.x, 0.1); | |
220 assertEquals("y", faceCenterY - eyesDistance, argument.getValue()[0].bou
ndingBox.y, 0.1); | |
221 } | |
222 } | |
OLD | NEW |