1 // Copyright (c) 2012 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 "base/android/jni_array.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <limits>
11
12 #include "base/android/jni_android.h"
13 #include "base/android/scoped_java_ref.h"
14 #include "base/macros.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace base {
18 namespace android {
19
TEST(JniArray,BasicConversions)20 TEST(JniArray, BasicConversions) {
21 const uint8_t kBytes[] = {0, 1, 2, 3};
22 const size_t kLen = arraysize(kBytes);
23 JNIEnv* env = AttachCurrentThread();
24 ScopedJavaLocalRef<jbyteArray> bytes = ToJavaByteArray(env, kBytes, kLen);
25 ASSERT_TRUE(bytes.obj());
26
27 std::vector<uint8_t> inputVector(kBytes, kBytes + kLen);
28 ScopedJavaLocalRef<jbyteArray> bytesFromVector =
29 ToJavaByteArray(env, inputVector);
30 ASSERT_TRUE(bytesFromVector.obj());
31
32 std::vector<uint8_t> vectorFromBytes(5);
33 std::vector<uint8_t> vectorFromVector(5);
34 JavaByteArrayToByteVector(env, bytes.obj(), &vectorFromBytes);
35 JavaByteArrayToByteVector(env, bytesFromVector.obj(), &vectorFromVector);
36 EXPECT_EQ(4U, vectorFromBytes.size());
37 EXPECT_EQ(4U, vectorFromVector.size());
38 std::vector<uint8_t> expected_vec(kBytes, kBytes + kLen);
39 EXPECT_EQ(expected_vec, vectorFromBytes);
40 EXPECT_EQ(expected_vec, vectorFromVector);
41
42 AppendJavaByteArrayToByteVector(env, bytes.obj(), &vectorFromBytes);
43 EXPECT_EQ(8U, vectorFromBytes.size());
44 expected_vec.insert(expected_vec.end(), kBytes, kBytes + kLen);
45 EXPECT_EQ(expected_vec, vectorFromBytes);
46 }
47
CheckBoolConversion(JNIEnv * env,const bool * bool_array,const size_t len,const ScopedJavaLocalRef<jbooleanArray> & booleans)48 void CheckBoolConversion(JNIEnv* env,
49 const bool* bool_array,
50 const size_t len,
51 const ScopedJavaLocalRef<jbooleanArray>& booleans) {
52 ASSERT_TRUE(booleans.obj());
53
54 jsize java_array_len = env->GetArrayLength(booleans.obj());
55 ASSERT_EQ(static_cast<jsize>(len), java_array_len);
56
57 jboolean value;
58 for (size_t i = 0; i < len; ++i) {
59 env->GetBooleanArrayRegion(booleans.obj(), i, 1, &value);
60 ASSERT_EQ(bool_array[i], value);
61 }
62 }
63
TEST(JniArray,BoolConversions)64 TEST(JniArray, BoolConversions) {
65 const bool kBools[] = {false, true, false};
66 const size_t kLen = arraysize(kBools);
67
68 JNIEnv* env = AttachCurrentThread();
69 CheckBoolConversion(env, kBools, kLen, ToJavaBooleanArray(env, kBools, kLen));
70 }
71
CheckIntConversion(JNIEnv * env,const int * int_array,const size_t len,const ScopedJavaLocalRef<jintArray> & ints)72 void CheckIntConversion(
73 JNIEnv* env,
74 const int* int_array,
75 const size_t len,
76 const ScopedJavaLocalRef<jintArray>& ints) {
77 ASSERT_TRUE(ints.obj());
78
79 jsize java_array_len = env->GetArrayLength(ints.obj());
80 ASSERT_EQ(static_cast<jsize>(len), java_array_len);
81
82 jint value;
83 for (size_t i = 0; i < len; ++i) {
84 env->GetIntArrayRegion(ints.obj(), i, 1, &value);
85 ASSERT_EQ(int_array[i], value);
86 }
87 }
88
TEST(JniArray,IntConversions)89 TEST(JniArray, IntConversions) {
90 const int kInts[] = {0, 1, -1, std::numeric_limits<int32_t>::min(),
91 std::numeric_limits<int32_t>::max()};
92 const size_t kLen = arraysize(kInts);
93
94 JNIEnv* env = AttachCurrentThread();
95 CheckIntConversion(env, kInts, kLen, ToJavaIntArray(env, kInts, kLen));
96
97 const std::vector<int> vec(kInts, kInts + kLen);
98 CheckIntConversion(env, kInts, kLen, ToJavaIntArray(env, vec));
99 }
100
CheckLongConversion(JNIEnv * env,const int64_t * long_array,const size_t len,const ScopedJavaLocalRef<jlongArray> & longs)101 void CheckLongConversion(JNIEnv* env,
102 const int64_t* long_array,
103 const size_t len,
104 const ScopedJavaLocalRef<jlongArray>& longs) {
105 ASSERT_TRUE(longs.obj());
106
107 jsize java_array_len = env->GetArrayLength(longs.obj());
108 ASSERT_EQ(static_cast<jsize>(len), java_array_len);
109
110 jlong value;
111 for (size_t i = 0; i < len; ++i) {
112 env->GetLongArrayRegion(longs.obj(), i, 1, &value);
113 ASSERT_EQ(long_array[i], value);
114 }
115 }
116
TEST(JniArray,LongConversions)117 TEST(JniArray, LongConversions) {
118 const int64_t kLongs[] = {0, 1, -1, std::numeric_limits<int64_t>::min(),
119 std::numeric_limits<int64_t>::max()};
120 const size_t kLen = arraysize(kLongs);
121
122 JNIEnv* env = AttachCurrentThread();
123 CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, kLongs, kLen));
124
125 const std::vector<int64_t> vec(kLongs, kLongs + kLen);
126 CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, vec));
127 }
128
CheckIntArrayConversion(JNIEnv * env,ScopedJavaLocalRef<jintArray> jints,std::vector<int> int_vector,const size_t len)129 void CheckIntArrayConversion(JNIEnv* env,
130 ScopedJavaLocalRef<jintArray> jints,
131 std::vector<int> int_vector,
132 const size_t len) {
133 jint value;
134 for (size_t i = 0; i < len; ++i) {
135 env->GetIntArrayRegion(jints.obj(), i, 1, &value);
136 ASSERT_EQ(int_vector[i], value);
137 }
138 }
139
CheckBoolArrayConversion(JNIEnv * env,ScopedJavaLocalRef<jbooleanArray> jbooleans,std::vector<bool> bool_vector,const size_t len)140 void CheckBoolArrayConversion(JNIEnv* env,
141 ScopedJavaLocalRef<jbooleanArray> jbooleans,
142 std::vector<bool> bool_vector,
143 const size_t len) {
144 jboolean value;
145 for (size_t i = 0; i < len; ++i) {
146 env->GetBooleanArrayRegion(jbooleans.obj(), i, 1, &value);
147 ASSERT_EQ(bool_vector[i], value);
148 }
149 }
150
CheckFloatConversion(JNIEnv * env,const float * float_array,const size_t len,const ScopedJavaLocalRef<jfloatArray> & floats)151 void CheckFloatConversion(
152 JNIEnv* env,
153 const float* float_array,
154 const size_t len,
155 const ScopedJavaLocalRef<jfloatArray>& floats) {
156 ASSERT_TRUE(floats.obj());
157
158 jsize java_array_len = env->GetArrayLength(floats.obj());
159 ASSERT_EQ(static_cast<jsize>(len), java_array_len);
160
161 jfloat value;
162 for (size_t i = 0; i < len; ++i) {
163 env->GetFloatArrayRegion(floats.obj(), i, 1, &value);
164 ASSERT_EQ(float_array[i], value);
165 }
166 }
167
TEST(JniArray,FloatConversions)168 TEST(JniArray, FloatConversions) {
169 const float kFloats[] = { 0.0f, 1.0f, -10.0f};
170 const size_t kLen = arraysize(kFloats);
171
172 JNIEnv* env = AttachCurrentThread();
173 CheckFloatConversion(env, kFloats, kLen,
174 ToJavaFloatArray(env, kFloats, kLen));
175
176 const std::vector<float> vec(kFloats, kFloats + kLen);
177 CheckFloatConversion(env, kFloats, kLen, ToJavaFloatArray(env, vec));
178 }
179
TEST(JniArray,JavaBooleanArrayToBoolVector)180 TEST(JniArray, JavaBooleanArrayToBoolVector) {
181 const bool kBools[] = {false, true, false};
182 const size_t kLen = arraysize(kBools);
183
184 JNIEnv* env = AttachCurrentThread();
185 ScopedJavaLocalRef<jbooleanArray> jbooleans(env, env->NewBooleanArray(kLen));
186 ASSERT_TRUE(jbooleans.obj());
187
188 for (size_t i = 0; i < kLen; ++i) {
189 jboolean j = static_cast<jboolean>(kBools[i]);
190 env->SetBooleanArrayRegion(jbooleans.obj(), i, 1, &j);
191 ASSERT_FALSE(HasException(env));
192 }
193
194 std::vector<bool> bools;
195 JavaBooleanArrayToBoolVector(env, jbooleans.obj(), &bools);
196
197 ASSERT_EQ(static_cast<jsize>(bools.size()),
198 env->GetArrayLength(jbooleans.obj()));
199
200 CheckBoolArrayConversion(env, jbooleans, bools, kLen);
201 }
202
TEST(JniArray,JavaIntArrayToIntVector)203 TEST(JniArray, JavaIntArrayToIntVector) {
204 const int kInts[] = {0, 1, -1};
205 const size_t kLen = arraysize(kInts);
206
207 JNIEnv* env = AttachCurrentThread();
208 ScopedJavaLocalRef<jintArray> jints(env, env->NewIntArray(kLen));
209 ASSERT_TRUE(jints.obj());
210
211 for (size_t i = 0; i < kLen; ++i) {
212 jint j = static_cast<jint>(kInts[i]);
213 env->SetIntArrayRegion(jints.obj(), i, 1, &j);
214 ASSERT_FALSE(HasException(env));
215 }
216
217 std::vector<int> ints;
218 JavaIntArrayToIntVector(env, jints.obj(), &ints);
219
220 ASSERT_EQ(static_cast<jsize>(ints.size()), env->GetArrayLength(jints.obj()));
221
222 CheckIntArrayConversion(env, jints, ints, kLen);
223 }
224
TEST(JniArray,JavaLongArrayToInt64Vector)225 TEST(JniArray, JavaLongArrayToInt64Vector) {
226 const int64_t kInt64s[] = {0LL, 1LL, -1LL};
227 const size_t kLen = arraysize(kInt64s);
228
229 JNIEnv* env = AttachCurrentThread();
230 ScopedJavaLocalRef<jlongArray> jlongs(env, env->NewLongArray(kLen));
231 ASSERT_TRUE(jlongs.obj());
232
233 for (size_t i = 0; i < kLen; ++i) {
234 jlong j = static_cast<jlong>(kInt64s[i]);
235 env->SetLongArrayRegion(jlongs.obj(), i, 1, &j);
236 ASSERT_FALSE(HasException(env));
237 }
238
239 std::vector<int64_t> int64s;
240 JavaLongArrayToInt64Vector(env, jlongs.obj(), &int64s);
241
242 ASSERT_EQ(static_cast<jsize>(int64s.size()),
243 env->GetArrayLength(jlongs.obj()));
244
245 jlong value;
246 for (size_t i = 0; i < kLen; ++i) {
247 env->GetLongArrayRegion(jlongs.obj(), i, 1, &value);
248 ASSERT_EQ(int64s[i], value);
249 ASSERT_EQ(kInt64s[i], int64s[i]);
250 }
251 }
252
TEST(JniArray,JavaLongArrayToLongVector)253 TEST(JniArray, JavaLongArrayToLongVector) {
254 const int64_t kInt64s[] = {0LL, 1LL, -1LL};
255 const size_t kLen = arraysize(kInt64s);
256
257 JNIEnv* env = AttachCurrentThread();
258 ScopedJavaLocalRef<jlongArray> jlongs(env, env->NewLongArray(kLen));
259 ASSERT_TRUE(jlongs.obj());
260
261 for (size_t i = 0; i < kLen; ++i) {
262 jlong j = static_cast<jlong>(kInt64s[i]);
263 env->SetLongArrayRegion(jlongs.obj(), i, 1, &j);
264 ASSERT_FALSE(HasException(env));
265 }
266
267 std::vector<jlong> jlongs_vector;
268 JavaLongArrayToLongVector(env, jlongs.obj(), &jlongs_vector);
269
270 ASSERT_EQ(static_cast<jsize>(jlongs_vector.size()),
271 env->GetArrayLength(jlongs.obj()));
272
273 jlong value;
274 for (size_t i = 0; i < kLen; ++i) {
275 env->GetLongArrayRegion(jlongs.obj(), i, 1, &value);
276 ASSERT_EQ(jlongs_vector[i], value);
277 }
278 }
279
TEST(JniArray,JavaFloatArrayToFloatVector)280 TEST(JniArray, JavaFloatArrayToFloatVector) {
281 const float kFloats[] = {0.0, 0.5, -0.5};
282 const size_t kLen = arraysize(kFloats);
283
284 JNIEnv* env = AttachCurrentThread();
285 ScopedJavaLocalRef<jfloatArray> jfloats(env, env->NewFloatArray(kLen));
286 ASSERT_TRUE(jfloats.obj());
287
288 for (size_t i = 0; i < kLen; ++i) {
289 jfloat j = static_cast<jfloat>(kFloats[i]);
290 env->SetFloatArrayRegion(jfloats.obj(), i, 1, &j);
291 ASSERT_FALSE(HasException(env));
292 }
293
294 std::vector<float> floats;
295 JavaFloatArrayToFloatVector(env, jfloats.obj(), &floats);
296
297 ASSERT_EQ(static_cast<jsize>(floats.size()),
298 env->GetArrayLength(jfloats.obj()));
299
300 jfloat value;
301 for (size_t i = 0; i < kLen; ++i) {
302 env->GetFloatArrayRegion(jfloats.obj(), i, 1, &value);
303 ASSERT_EQ(floats[i], value);
304 }
305 }
306
TEST(JniArray,JavaArrayOfByteArrayToStringVector)307 TEST(JniArray, JavaArrayOfByteArrayToStringVector) {
308 const int kMaxItems = 50;
309 JNIEnv* env = AttachCurrentThread();
310
311 // Create a byte[][] object.
312 ScopedJavaLocalRef<jclass> byte_array_clazz(env, env->FindClass("[B"));
313 ASSERT_TRUE(byte_array_clazz.obj());
314
315 ScopedJavaLocalRef<jobjectArray> array(
316 env, env->NewObjectArray(kMaxItems, byte_array_clazz.obj(), NULL));
317 ASSERT_TRUE(array.obj());
318
319 // Create kMaxItems byte buffers.
320 char text[16];
321 for (int i = 0; i < kMaxItems; ++i) {
322 snprintf(text, sizeof text, "%d", i);
323 ScopedJavaLocalRef<jbyteArray> byte_array =
324 ToJavaByteArray(env, reinterpret_cast<uint8_t*>(text),
325 static_cast<size_t>(strlen(text)));
326 ASSERT_TRUE(byte_array.obj());
327
328 env->SetObjectArrayElement(array.obj(), i, byte_array.obj());
329 ASSERT_FALSE(HasException(env));
330 }
331
332 // Convert to std::vector<std::string>, check the content.
333 std::vector<std::string> vec;
334 JavaArrayOfByteArrayToStringVector(env, array.obj(), &vec);
335
336 EXPECT_EQ(static_cast<size_t>(kMaxItems), vec.size());
337 for (int i = 0; i < kMaxItems; ++i) {
338 snprintf(text, sizeof text, "%d", i);
339 EXPECT_STREQ(text, vec[i].c_str());
340 }
341 }
342
TEST(JniArray,JavaArrayOfIntArrayToIntVector)343 TEST(JniArray, JavaArrayOfIntArrayToIntVector) {
344 const size_t kNumItems = 4;
345 JNIEnv* env = AttachCurrentThread();
346
347 // Create an int[][] object.
348 ScopedJavaLocalRef<jclass> int_array_clazz(env, env->FindClass("[I"));
349 ASSERT_TRUE(int_array_clazz.obj());
350
351 ScopedJavaLocalRef<jobjectArray> array(
352 env, env->NewObjectArray(kNumItems, int_array_clazz.obj(), nullptr));
353 ASSERT_TRUE(array.obj());
354
355 // Populate int[][] object.
356 const int kInts0[] = {0, 1, -1, std::numeric_limits<int32_t>::min(),
357 std::numeric_limits<int32_t>::max()};
358 const size_t kLen0 = arraysize(kInts0);
359 ScopedJavaLocalRef<jintArray> int_array0 = ToJavaIntArray(env, kInts0, kLen0);
360 env->SetObjectArrayElement(array.obj(), 0, int_array0.obj());
361
362 const int kInts1[] = {3, 4, 5};
363 const size_t kLen1 = arraysize(kInts1);
364 ScopedJavaLocalRef<jintArray> int_array1 = ToJavaIntArray(env, kInts1, kLen1);
365 env->SetObjectArrayElement(array.obj(), 1, int_array1.obj());
366
367 const int kInts2[] = {};
368 const size_t kLen2 = 0;
369 ScopedJavaLocalRef<jintArray> int_array2 = ToJavaIntArray(env, kInts2, kLen2);
370 env->SetObjectArrayElement(array.obj(), 2, int_array2.obj());
371
372 const int kInts3[] = {16};
373 const size_t kLen3 = arraysize(kInts3);
374 ScopedJavaLocalRef<jintArray> int_array3 = ToJavaIntArray(env, kInts3, kLen3);
375 env->SetObjectArrayElement(array.obj(), 3, int_array3.obj());
376
377 // Convert to std::vector<std::vector<int>>, check the content.
378 std::vector<std::vector<int>> out;
379 JavaArrayOfIntArrayToIntVector(env, array.obj(), &out);
380
381 EXPECT_EQ(kNumItems, out.size());
382 CheckIntArrayConversion(env, int_array0, out[0], kLen0);
383 CheckIntArrayConversion(env, int_array1, out[1], kLen1);
384 CheckIntArrayConversion(env, int_array2, out[2], kLen2);
385 CheckIntArrayConversion(env, int_array3, out[3], kLen3);
386 }
387
388 } // namespace android
389 } // namespace base
390