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
CheckIntConversion(JNIEnv * env,const int * int_array,const size_t len,const ScopedJavaLocalRef<jintArray> & ints)48 void CheckIntConversion(
49 JNIEnv* env,
50 const int* int_array,
51 const size_t len,
52 const ScopedJavaLocalRef<jintArray>& ints) {
53 ASSERT_TRUE(ints.obj());
54
55 jsize java_array_len = env->GetArrayLength(ints.obj());
56 ASSERT_EQ(static_cast<jsize>(len), java_array_len);
57
58 jint value;
59 for (size_t i = 0; i < len; ++i) {
60 env->GetIntArrayRegion(ints.obj(), i, 1, &value);
61 ASSERT_EQ(int_array[i], value);
62 }
63 }
64
TEST(JniArray,IntConversions)65 TEST(JniArray, IntConversions) {
66 const int kInts[] = {0, 1, -1, std::numeric_limits<int32_t>::min(),
67 std::numeric_limits<int32_t>::max()};
68 const size_t kLen = arraysize(kInts);
69
70 JNIEnv* env = AttachCurrentThread();
71 CheckIntConversion(env, kInts, kLen, ToJavaIntArray(env, kInts, kLen));
72
73 const std::vector<int> vec(kInts, kInts + kLen);
74 CheckIntConversion(env, kInts, kLen, ToJavaIntArray(env, vec));
75 }
76
CheckLongConversion(JNIEnv * env,const int64_t * long_array,const size_t len,const ScopedJavaLocalRef<jlongArray> & longs)77 void CheckLongConversion(JNIEnv* env,
78 const int64_t* long_array,
79 const size_t len,
80 const ScopedJavaLocalRef<jlongArray>& longs) {
81 ASSERT_TRUE(longs.obj());
82
83 jsize java_array_len = env->GetArrayLength(longs.obj());
84 ASSERT_EQ(static_cast<jsize>(len), java_array_len);
85
86 jlong value;
87 for (size_t i = 0; i < len; ++i) {
88 env->GetLongArrayRegion(longs.obj(), i, 1, &value);
89 ASSERT_EQ(long_array[i], value);
90 }
91 }
92
TEST(JniArray,LongConversions)93 TEST(JniArray, LongConversions) {
94 const int64_t kLongs[] = {0, 1, -1, std::numeric_limits<int64_t>::min(),
95 std::numeric_limits<int64_t>::max()};
96 const size_t kLen = arraysize(kLongs);
97
98 JNIEnv* env = AttachCurrentThread();
99 CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, kLongs, kLen));
100
101 const std::vector<int64_t> vec(kLongs, kLongs + kLen);
102 CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, vec));
103 }
104
CheckIntArrayConversion(JNIEnv * env,ScopedJavaLocalRef<jintArray> jints,std::vector<int> int_vector,const size_t len)105 void CheckIntArrayConversion(JNIEnv* env,
106 ScopedJavaLocalRef<jintArray> jints,
107 std::vector<int> int_vector,
108 const size_t len) {
109 jint value;
110 for (size_t i = 0; i < len; ++i) {
111 env->GetIntArrayRegion(jints.obj(), i, 1, &value);
112 ASSERT_EQ(int_vector[i], value);
113 }
114 }
115
CheckFloatConversion(JNIEnv * env,const float * float_array,const size_t len,const ScopedJavaLocalRef<jfloatArray> & floats)116 void CheckFloatConversion(
117 JNIEnv* env,
118 const float* float_array,
119 const size_t len,
120 const ScopedJavaLocalRef<jfloatArray>& floats) {
121 ASSERT_TRUE(floats.obj());
122
123 jsize java_array_len = env->GetArrayLength(floats.obj());
124 ASSERT_EQ(static_cast<jsize>(len), java_array_len);
125
126 jfloat value;
127 for (size_t i = 0; i < len; ++i) {
128 env->GetFloatArrayRegion(floats.obj(), i, 1, &value);
129 ASSERT_EQ(float_array[i], value);
130 }
131 }
132
TEST(JniArray,FloatConversions)133 TEST(JniArray, FloatConversions) {
134 const float kFloats[] = { 0.0f, 1.0f, -10.0f};
135 const size_t kLen = arraysize(kFloats);
136
137 JNIEnv* env = AttachCurrentThread();
138 CheckFloatConversion(env, kFloats, kLen,
139 ToJavaFloatArray(env, kFloats, kLen));
140
141 const std::vector<float> vec(kFloats, kFloats + kLen);
142 CheckFloatConversion(env, kFloats, kLen, ToJavaFloatArray(env, vec));
143 }
144
TEST(JniArray,JavaIntArrayToIntVector)145 TEST(JniArray, JavaIntArrayToIntVector) {
146 const int kInts[] = {0, 1, -1};
147 const size_t kLen = arraysize(kInts);
148
149 JNIEnv* env = AttachCurrentThread();
150 ScopedJavaLocalRef<jintArray> jints(env, env->NewIntArray(kLen));
151 ASSERT_TRUE(jints.obj());
152
153 for (size_t i = 0; i < kLen; ++i) {
154 jint j = static_cast<jint>(kInts[i]);
155 env->SetIntArrayRegion(jints.obj(), i, 1, &j);
156 ASSERT_FALSE(HasException(env));
157 }
158
159 std::vector<int> ints;
160 JavaIntArrayToIntVector(env, jints.obj(), &ints);
161
162 ASSERT_EQ(static_cast<jsize>(ints.size()), env->GetArrayLength(jints.obj()));
163
164 CheckIntArrayConversion(env, jints, ints, kLen);
165 }
166
TEST(JniArray,JavaLongArrayToInt64Vector)167 TEST(JniArray, JavaLongArrayToInt64Vector) {
168 const int64_t kInt64s[] = {0LL, 1LL, -1LL};
169 const size_t kLen = arraysize(kInt64s);
170
171 JNIEnv* env = AttachCurrentThread();
172 ScopedJavaLocalRef<jlongArray> jlongs(env, env->NewLongArray(kLen));
173 ASSERT_TRUE(jlongs.obj());
174
175 for (size_t i = 0; i < kLen; ++i) {
176 jlong j = static_cast<jlong>(kInt64s[i]);
177 env->SetLongArrayRegion(jlongs.obj(), i, 1, &j);
178 ASSERT_FALSE(HasException(env));
179 }
180
181 std::vector<int64_t> int64s;
182 JavaLongArrayToInt64Vector(env, jlongs.obj(), &int64s);
183
184 ASSERT_EQ(static_cast<jsize>(int64s.size()),
185 env->GetArrayLength(jlongs.obj()));
186
187 jlong value;
188 for (size_t i = 0; i < kLen; ++i) {
189 env->GetLongArrayRegion(jlongs.obj(), i, 1, &value);
190 ASSERT_EQ(int64s[i], value);
191 ASSERT_EQ(kInt64s[i], int64s[i]);
192 }
193 }
194
TEST(JniArray,JavaLongArrayToLongVector)195 TEST(JniArray, JavaLongArrayToLongVector) {
196 const int64_t kInt64s[] = {0LL, 1LL, -1LL};
197 const size_t kLen = arraysize(kInt64s);
198
199 JNIEnv* env = AttachCurrentThread();
200 ScopedJavaLocalRef<jlongArray> jlongs(env, env->NewLongArray(kLen));
201 ASSERT_TRUE(jlongs.obj());
202
203 for (size_t i = 0; i < kLen; ++i) {
204 jlong j = static_cast<jlong>(kInt64s[i]);
205 env->SetLongArrayRegion(jlongs.obj(), i, 1, &j);
206 ASSERT_FALSE(HasException(env));
207 }
208
209 std::vector<jlong> jlongs_vector;
210 JavaLongArrayToLongVector(env, jlongs.obj(), &jlongs_vector);
211
212 ASSERT_EQ(static_cast<jsize>(jlongs_vector.size()),
213 env->GetArrayLength(jlongs.obj()));
214
215 jlong value;
216 for (size_t i = 0; i < kLen; ++i) {
217 env->GetLongArrayRegion(jlongs.obj(), i, 1, &value);
218 ASSERT_EQ(jlongs_vector[i], value);
219 }
220 }
221
TEST(JniArray,JavaFloatArrayToFloatVector)222 TEST(JniArray, JavaFloatArrayToFloatVector) {
223 const float kFloats[] = {0.0, 0.5, -0.5};
224 const size_t kLen = arraysize(kFloats);
225
226 JNIEnv* env = AttachCurrentThread();
227 ScopedJavaLocalRef<jfloatArray> jfloats(env, env->NewFloatArray(kLen));
228 ASSERT_TRUE(jfloats.obj());
229
230 for (size_t i = 0; i < kLen; ++i) {
231 jfloat j = static_cast<jfloat>(kFloats[i]);
232 env->SetFloatArrayRegion(jfloats.obj(), i, 1, &j);
233 ASSERT_FALSE(HasException(env));
234 }
235
236 std::vector<float> floats;
237 JavaFloatArrayToFloatVector(env, jfloats.obj(), &floats);
238
239 ASSERT_EQ(static_cast<jsize>(floats.size()),
240 env->GetArrayLength(jfloats.obj()));
241
242 jfloat value;
243 for (size_t i = 0; i < kLen; ++i) {
244 env->GetFloatArrayRegion(jfloats.obj(), i, 1, &value);
245 ASSERT_EQ(floats[i], value);
246 }
247 }
248
TEST(JniArray,JavaArrayOfByteArrayToStringVector)249 TEST(JniArray, JavaArrayOfByteArrayToStringVector) {
250 const int kMaxItems = 50;
251 JNIEnv* env = AttachCurrentThread();
252
253 // Create a byte[][] object.
254 ScopedJavaLocalRef<jclass> byte_array_clazz(env, env->FindClass("[B"));
255 ASSERT_TRUE(byte_array_clazz.obj());
256
257 ScopedJavaLocalRef<jobjectArray> array(
258 env, env->NewObjectArray(kMaxItems, byte_array_clazz.obj(), NULL));
259 ASSERT_TRUE(array.obj());
260
261 // Create kMaxItems byte buffers.
262 char text[16];
263 for (int i = 0; i < kMaxItems; ++i) {
264 snprintf(text, sizeof text, "%d", i);
265 ScopedJavaLocalRef<jbyteArray> byte_array =
266 ToJavaByteArray(env, reinterpret_cast<uint8_t*>(text),
267 static_cast<size_t>(strlen(text)));
268 ASSERT_TRUE(byte_array.obj());
269
270 env->SetObjectArrayElement(array.obj(), i, byte_array.obj());
271 ASSERT_FALSE(HasException(env));
272 }
273
274 // Convert to std::vector<std::string>, check the content.
275 std::vector<std::string> vec;
276 JavaArrayOfByteArrayToStringVector(env, array.obj(), &vec);
277
278 EXPECT_EQ(static_cast<size_t>(kMaxItems), vec.size());
279 for (int i = 0; i < kMaxItems; ++i) {
280 snprintf(text, sizeof text, "%d", i);
281 EXPECT_STREQ(text, vec[i].c_str());
282 }
283 }
284
TEST(JniArray,JavaArrayOfIntArrayToIntVector)285 TEST(JniArray, JavaArrayOfIntArrayToIntVector) {
286 const size_t kNumItems = 4;
287 JNIEnv* env = AttachCurrentThread();
288
289 // Create an int[][] object.
290 ScopedJavaLocalRef<jclass> int_array_clazz(env, env->FindClass("[I"));
291 ASSERT_TRUE(int_array_clazz.obj());
292
293 ScopedJavaLocalRef<jobjectArray> array(
294 env, env->NewObjectArray(kNumItems, int_array_clazz.obj(), nullptr));
295 ASSERT_TRUE(array.obj());
296
297 // Populate int[][] object.
298 const int kInts0[] = {0, 1, -1, std::numeric_limits<int32_t>::min(),
299 std::numeric_limits<int32_t>::max()};
300 const size_t kLen0 = arraysize(kInts0);
301 ScopedJavaLocalRef<jintArray> int_array0 = ToJavaIntArray(env, kInts0, kLen0);
302 env->SetObjectArrayElement(array.obj(), 0, int_array0.obj());
303
304 const int kInts1[] = {3, 4, 5};
305 const size_t kLen1 = arraysize(kInts1);
306 ScopedJavaLocalRef<jintArray> int_array1 = ToJavaIntArray(env, kInts1, kLen1);
307 env->SetObjectArrayElement(array.obj(), 1, int_array1.obj());
308
309 const int kInts2[] = {};
310 const size_t kLen2 = 0;
311 ScopedJavaLocalRef<jintArray> int_array2 = ToJavaIntArray(env, kInts2, kLen2);
312 env->SetObjectArrayElement(array.obj(), 2, int_array2.obj());
313
314 const int kInts3[] = {16};
315 const size_t kLen3 = arraysize(kInts3);
316 ScopedJavaLocalRef<jintArray> int_array3 = ToJavaIntArray(env, kInts3, kLen3);
317 env->SetObjectArrayElement(array.obj(), 3, int_array3.obj());
318
319 // Convert to std::vector<std::vector<int>>, check the content.
320 std::vector<std::vector<int>> out;
321 JavaArrayOfIntArrayToIntVector(env, array.obj(), &out);
322
323 EXPECT_EQ(kNumItems, out.size());
324 CheckIntArrayConversion(env, int_array0, out[0], kLen0);
325 CheckIntArrayConversion(env, int_array1, out[1], kLen1);
326 CheckIntArrayConversion(env, int_array2, out[2], kLen2);
327 CheckIntArrayConversion(env, int_array3, out[3], kLen3);
328 }
329
330 } // namespace android
331 } // namespace base
332