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() { | |
scheib
2017/05/17 00:55:39
Just testing that the member variable mFaceDetect
mcasas
2017/05/17 16:54:03
Yes, also because |options| in l.60 is parameteriz
| |
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 handle = Mockito.mock(SharedBufferHandle.class); | |
scheib
2017/05/17 00:55:39
renaming handle -> sharedBuffer would be clearer.
mcasas
2017/05/17 16:54:03
Done.
| |
90 Mockito.when(handle.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(handle, VALID_WIDTH, VALID_HEIGHT, callback); | |
97 | |
98 Mockito.verify(handle, 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 handle = Mockito.mock(SharedBufferHandle.class); | |
112 Mockito.when(handle.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(handle, INVALID_WIDTH, VALID_HEIGHT, callback) ; | |
119 | |
120 Mockito.verify(handle, 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 handle = Mockito.mock(SharedBufferHandle.class); | |
134 Mockito.when(handle.isValid()).thenReturn(true); | |
135 Mockito.when(handle.map(Mockito.eq(0L), Mockito.eq(NUM_BYTES), Mockito.a ny(MapFlags.class))) | |
136 .thenReturn(ByteBuffer.allocate(0)); | |
137 | |
138 FaceDetection.DetectResponse callback = Mockito.mock(FaceDetection.Detec tResponse.class); | |
139 ArgumentCaptor<FaceDetectionResult[]> argument = | |
140 ArgumentCaptor.forClass(FaceDetectionResult[].class); | |
141 | |
142 mFaceDetectionImpl.detect(handle, VALID_WIDTH, VALID_HEIGHT, callback); | |
143 | |
144 Mockito.verify(handle, Mockito.times(1)).isValid(); | |
145 Mockito.verify(handle, Mockito.times(1)) | |
146 .map(Mockito.eq(0L), Mockito.eq(NUM_BYTES), Mockito.any(MapFlags .class)); | |
147 Mockito.verify(callback, Mockito.times(1)).call(argument.capture()); | |
148 assertEquals("result", 0, argument.getValue().length); | |
149 } | |
150 | |
151 /** | |
152 * Verify detection works. | |
153 */ | |
154 @Test | |
155 @Feature({"ShapeDetection"}) | |
156 public void testDetection() { | |
157 assertTrue("Should be on UI thread", ThreadUtils.runningOnUiThread()); | |
158 | |
159 SharedBufferHandle handle = Mockito.mock(SharedBufferHandle.class); | |
160 Mockito.when(handle.isValid()).thenReturn(true); | |
161 Mockito.when(handle.map(Mockito.eq(0L), Mockito.eq(NUM_BYTES), Mockito.a ny(MapFlags.class))) | |
162 .thenReturn(ByteBuffer.allocate((int) NUM_BYTES)); | |
163 | |
164 FaceDetection.DetectResponse callback = Mockito.mock(FaceDetection.Detec tResponse.class); | |
165 ArgumentCaptor<FaceDetectionResult[]> argument = | |
166 ArgumentCaptor.forClass(FaceDetectionResult[].class); | |
167 | |
168 // We have to add a |faceDetector| mock that inside returns a |face| moc k. To spice things | |
169 // up, some methods, findFaces() and getMidPoint(), modify parameters so we need doAnswer(). | |
170 final float eyesDistance = 1.0f; | |
171 final float faceCenterX = 2.0f; | |
172 final float faceCenterY = 3.0f; | |
173 | |
174 Face face = Mockito.mock(Face.class); | |
175 Mockito.when(face.eyesDistance()).thenReturn(eyesDistance); | |
176 Mockito.doAnswer(new Answer<Void>() { | |
177 @Override | |
178 public Void answer(InvocationOnMock invocation) { | |
179 Object[] args = invocation.getArguments(); | |
180 PointF midPoint = (PointF) args[0]; | |
181 midPoint.set(faceCenterX, faceCenterY); | |
182 return null; | |
183 } | |
184 }) | |
185 .when(face) | |
186 .getMidPoint(Mockito.any(PointF.class)); | |
187 | |
188 FaceDetector faceDetector = Mockito.mock(FaceDetector.class); | |
189 mFaceDetectionImpl.setFaceDetector(faceDetector); | |
190 Mockito.doAnswer(new Answer<Integer>() { | |
191 @Override | |
192 public Integer answer(InvocationOnMock invocation) throws Throwa ble { | |
193 Object[] args = invocation.getArguments(); | |
194 Face[] faceArray = (Face[]) args[1]; | |
195 faceArray[0] = face; | |
196 return 1; | |
197 } | |
198 }) | |
199 .when(faceDetector) | |
200 .findFaces(Mockito.any(Bitmap.class), Mockito.any()); | |
201 | |
202 mFaceDetectionImpl.detect(handle, VALID_WIDTH, VALID_HEIGHT, callback); | |
203 | |
204 Mockito.verify(handle, Mockito.times(1)).isValid(); | |
205 Mockito.verify(handle, Mockito.times(1)) | |
206 .map(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(MapFlags. class)); | |
207 | |
208 Mockito.verify(faceDetector, Mockito.times(1)) | |
209 .findFaces(Mockito.any(Bitmap.class), Mockito.any()); | |
210 | |
211 // Detection happens asynchronously: give some timeout. | |
212 Mockito.verify(callback, Mockito.timeout(1000 /* milliseconds */).times( 1)) | |
213 .call(argument.capture()); | |
214 assertEquals("result", 1, argument.getValue().length); | |
215 assertEquals("width", 2 * eyesDistance, argument.getValue()[0].boundingB ox.width, 0.1); | |
216 assertEquals("height", 2 * eyesDistance, argument.getValue()[0].bounding Box.height, 0.1); | |
217 assertEquals("x", faceCenterX - eyesDistance, argument.getValue()[0].bou ndingBox.x, 0.1); | |
218 assertEquals("y", faceCenterY - eyesDistance, argument.getValue()[0].bou ndingBox.y, 0.1); | |
219 } | |
220 } | |
OLD | NEW |