xref: /aosp_15_r20/external/libchrome/base/android/jni_array_unittest.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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