• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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