• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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 <algorithm>
11 #include <array>
12 #include <limits>
13 
14 #include "base/android/jni_android.h"
15 #include "base/android/jni_string.h"
16 #include "base/android/scoped_java_ref.h"
17 #include "base/containers/span.h"
18 #include "base/containers/to_vector.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 
23 namespace base::android {
24 
TEST(JniArray,GetLength)25 TEST(JniArray, GetLength) {
26   const auto bytes = std::to_array<uint8_t>({0, 1, 2, 3});
27   JNIEnv* env = AttachCurrentThread();
28   ScopedJavaLocalRef<jbyteArray> j_bytes = ToJavaByteArray(env, bytes);
29   ASSERT_TRUE(j_bytes);
30   ASSERT_EQ(4U, SafeGetArrayLength(env, j_bytes));
31 
32   ScopedJavaLocalRef<jbyteArray> j_empty_bytes =
33       ToJavaByteArray(env, base::span<uint8_t>());
34   ASSERT_TRUE(j_empty_bytes);
35   ASSERT_EQ(0U, SafeGetArrayLength(env, j_empty_bytes));
36 }
37 
TEST(JniArray,BasicConversions)38 TEST(JniArray, BasicConversions) {
39   const auto bytes = std::to_array<uint8_t>({0, 1, 2, 3});
40   JNIEnv* env = AttachCurrentThread();
41   ScopedJavaLocalRef<jbyteArray> bytes_from_span = ToJavaByteArray(env, bytes);
42   ASSERT_TRUE(bytes_from_span);
43   ASSERT_EQ(4U, SafeGetArrayLength(env, bytes_from_span));
44 
45   auto input_string = std::string(base::as_string_view(bytes));
46   ScopedJavaLocalRef<jbyteArray> bytes_from_string =
47       ToJavaByteArray(env, input_string);
48   ASSERT_TRUE(bytes_from_string);
49   ASSERT_EQ(4U, SafeGetArrayLength(env, bytes_from_string));
50 
51   ScopedJavaLocalRef<jbyteArray> bytes_from_ptr =
52       UNSAFE_BUFFERS(ToJavaByteArray(env, bytes.data(), bytes.size()));
53   ASSERT_TRUE(bytes_from_ptr);
54   ASSERT_EQ(4U, SafeGetArrayLength(env, bytes_from_ptr));
55 
56   std::vector<uint8_t> vector_from_span(5);
57   std::vector<uint8_t> vector_from_string(5);
58   std::vector<uint8_t> vector_from_ptr(5);
59   JavaByteArrayToByteVector(env, bytes_from_span, &vector_from_span);
60   JavaByteArrayToByteVector(env, bytes_from_string, &vector_from_string);
61   JavaByteArrayToByteVector(env, bytes_from_ptr, &vector_from_ptr);
62   EXPECT_EQ(4U, vector_from_span.size());
63   EXPECT_EQ(4U, vector_from_string.size());
64   EXPECT_EQ(4U, vector_from_ptr.size());
65   EXPECT_EQ(bytes, span(vector_from_span));
66   EXPECT_EQ(bytes, span(vector_from_string));
67   EXPECT_EQ(bytes, span(vector_from_ptr));
68 }
69 
TEST(JniArray,ByteArrayStringConversions)70 TEST(JniArray, ByteArrayStringConversions) {
71   JNIEnv* env = AttachCurrentThread();
72   std::string input_string("hello\0world", 11u);
73   ScopedJavaLocalRef<jbyteArray> bytes_from_string =
74       ToJavaByteArray(env, input_string);
75   ASSERT_TRUE(bytes_from_string);
76 
77   std::string string_from_string;
78   JavaByteArrayToString(env, bytes_from_string, &string_from_string);
79   EXPECT_EQ(input_string, string_from_string);
80 }
81 
CheckBoolConversion(JNIEnv * env,span<const bool> bool_array,const ScopedJavaLocalRef<jbooleanArray> & booleans)82 void CheckBoolConversion(JNIEnv* env,
83                          span<const bool> bool_array,
84                          const ScopedJavaLocalRef<jbooleanArray>& booleans) {
85   ASSERT_TRUE(booleans);
86 
87   jsize java_array_len = env->GetArrayLength(booleans.obj());
88   ASSERT_EQ(checked_cast<jsize>(bool_array.size()), java_array_len);
89 
90   jboolean value;
91   for (size_t i = 0; i < bool_array.size(); ++i) {
92     env->GetBooleanArrayRegion(booleans.obj(), checked_cast<jsize>(i), jsize{1},
93                                &value);
94     ASSERT_EQ(bool_array[i], value);
95   }
96 }
97 
TEST(JniArray,BoolConversions)98 TEST(JniArray, BoolConversions) {
99   const bool kBools[] = {false, true, false};
100 
101   JNIEnv* env = AttachCurrentThread();
102   CheckBoolConversion(env, kBools, ToJavaBooleanArray(env, kBools));
103 }
104 
TEST(JniArray,BoolVectorConversions)105 TEST(JniArray, BoolVectorConversions) {
106   const auto kBools = std::to_array<bool>({false, true, false});
107   const auto kBoolVector = std::vector<bool>({false, true, false});
108 
109   JNIEnv* env = AttachCurrentThread();
110   CheckBoolConversion(env, kBools, ToJavaBooleanArray(env, kBoolVector));
111 }
112 
CheckIntConversion(JNIEnv * env,span<const int> in,const ScopedJavaLocalRef<jintArray> & ints)113 void CheckIntConversion(JNIEnv* env,
114                         span<const int> in,
115                         const ScopedJavaLocalRef<jintArray>& ints) {
116   ASSERT_TRUE(ints);
117 
118   jsize java_array_len = env->GetArrayLength(ints.obj());
119   ASSERT_EQ(checked_cast<jsize>(in.size()), java_array_len);
120 
121   jint value;
122   for (size_t i = 0; i < in.size(); ++i) {
123     env->GetIntArrayRegion(ints.obj(), i, 1, &value);
124     ASSERT_EQ(in[i], value);
125   }
126 }
127 
TEST(JniArray,IntConversions)128 TEST(JniArray, IntConversions) {
129   const int kInts[] = {0, 1, -1, std::numeric_limits<int32_t>::min(),
130                        std::numeric_limits<int32_t>::max()};
131 
132   JNIEnv* env = AttachCurrentThread();
133   CheckIntConversion(env, kInts, ToJavaIntArray(env, kInts));
134 }
135 
CheckLongConversion(JNIEnv * env,span<const int64_t> in,const ScopedJavaLocalRef<jlongArray> & longs)136 void CheckLongConversion(JNIEnv* env,
137                          span<const int64_t> in,
138                          const ScopedJavaLocalRef<jlongArray>& longs) {
139   ASSERT_TRUE(longs);
140 
141   jsize java_array_len = env->GetArrayLength(longs.obj());
142   ASSERT_EQ(checked_cast<jsize>(in.size()), java_array_len);
143 
144   jlong value;
145   for (size_t i = 0; i < in.size(); ++i) {
146     env->GetLongArrayRegion(longs.obj(), i, 1, &value);
147     ASSERT_EQ(in[i], value);
148   }
149 }
150 
TEST(JniArray,LongConversions)151 TEST(JniArray, LongConversions) {
152   const int64_t kLongs[] = {0, 1, -1, std::numeric_limits<int64_t>::min(),
153                             std::numeric_limits<int64_t>::max()};
154 
155   JNIEnv* env = AttachCurrentThread();
156   CheckLongConversion(env, kLongs, ToJavaLongArray(env, kLongs));
157 }
158 
CheckFloatConversion(JNIEnv * env,span<const float> in,const ScopedJavaLocalRef<jfloatArray> & floats)159 void CheckFloatConversion(JNIEnv* env,
160                           span<const float> in,
161                           const ScopedJavaLocalRef<jfloatArray>& floats) {
162   ASSERT_TRUE(floats);
163 
164   jsize java_array_len = env->GetArrayLength(floats.obj());
165   ASSERT_EQ(checked_cast<jsize>(in.size()), java_array_len);
166 
167   jfloat value;
168   for (size_t i = 0; i < in.size(); ++i) {
169     env->GetFloatArrayRegion(floats.obj(), i, 1, &value);
170     ASSERT_EQ(in[i], value);
171   }
172 }
173 
TEST(JniArray,FloatConversions)174 TEST(JniArray, FloatConversions) {
175   const float kFloats[] = {0.0f, 1.0f, -10.0f};
176 
177   JNIEnv* env = AttachCurrentThread();
178   CheckFloatConversion(env, kFloats, ToJavaFloatArray(env, kFloats));
179 }
180 
CheckDoubleConversion(JNIEnv * env,span<const double> in,const ScopedJavaLocalRef<jdoubleArray> & doubles)181 void CheckDoubleConversion(JNIEnv* env,
182                            span<const double> in,
183                            const ScopedJavaLocalRef<jdoubleArray>& doubles) {
184   ASSERT_TRUE(doubles);
185 
186   jsize java_array_len = env->GetArrayLength(doubles.obj());
187   ASSERT_EQ(checked_cast<jsize>(in.size()), java_array_len);
188 
189   jdouble value;
190   for (size_t i = 0; i < in.size(); ++i) {
191     env->GetDoubleArrayRegion(doubles.obj(), i, 1, &value);
192     ASSERT_EQ(in[i], value);
193   }
194 }
195 
TEST(JniArray,DoubleConversions)196 TEST(JniArray, DoubleConversions) {
197   const double kDoubles[] = {0.0, 1.0, -10.0};
198 
199   JNIEnv* env = AttachCurrentThread();
200   CheckDoubleConversion(env, kDoubles, ToJavaDoubleArray(env, kDoubles));
201 }
202 
TEST(JniArray,ArrayOfStringArrayConversionUTF8)203 TEST(JniArray, ArrayOfStringArrayConversionUTF8) {
204   std::vector<std::vector<std::string>> kArrays = {
205       {"a", "f"}, {"a", ""}, {}, {""}, {"今日は"}};
206 
207   JNIEnv* env = AttachCurrentThread();
208   ScopedJavaLocalRef<jobjectArray> joa = ToJavaArrayOfStringArray(env, kArrays);
209 
210   std::vector<std::vector<std::string>> out;
211   Java2dStringArrayTo2dStringVector(env, joa, &out);
212   ASSERT_TRUE(kArrays == out);
213 }
214 
TEST(JniArray,ArrayOfStringArrayConversionUTF16)215 TEST(JniArray, ArrayOfStringArrayConversionUTF16) {
216   std::vector<std::vector<std::u16string>> kArrays = {
217       {u"a", u"f"}, {u"a", u""}, {}, {u""}};
218 
219   JNIEnv* env = AttachCurrentThread();
220   ScopedJavaLocalRef<jobjectArray> joa = ToJavaArrayOfStringArray(env, kArrays);
221 
222   std::vector<std::vector<std::u16string>> out;
223   Java2dStringArrayTo2dStringVector(env, joa, &out);
224   ASSERT_TRUE(kArrays == out);
225 }
226 
CheckBoolArrayConversion(JNIEnv * env,ScopedJavaLocalRef<jbooleanArray> jbooleans,std::vector<bool> bool_vector)227 void CheckBoolArrayConversion(JNIEnv* env,
228                               ScopedJavaLocalRef<jbooleanArray> jbooleans,
229                               std::vector<bool> bool_vector) {
230   jboolean value;
231   for (size_t i = 0; i < bool_vector.size(); ++i) {
232     env->GetBooleanArrayRegion(jbooleans.obj(), i, 1, &value);
233     ASSERT_EQ(bool_vector[i], value);
234   }
235 }
236 
TEST(JniArray,JavaBooleanArrayToBoolVector)237 TEST(JniArray, JavaBooleanArrayToBoolVector) {
238   const auto kBools = std::to_array<bool>({false, true, false});
239 
240   JNIEnv* env = AttachCurrentThread();
241   ScopedJavaLocalRef<jbooleanArray> jbooleans(
242       env, env->NewBooleanArray(kBools.size()));
243   ASSERT_TRUE(jbooleans);
244 
245   for (size_t i = 0; i < kBools.size(); ++i) {
246     jboolean j = static_cast<jboolean>(kBools[i]);
247     env->SetBooleanArrayRegion(jbooleans.obj(), i, 1, &j);
248     ASSERT_FALSE(HasException(env));
249   }
250 
251   std::vector<bool> bools;
252   JavaBooleanArrayToBoolVector(env, jbooleans, &bools);
253 
254   ASSERT_EQ(checked_cast<jsize>(bools.size()),
255             env->GetArrayLength(jbooleans.obj()));
256   ASSERT_EQ(bools.size(), kBools.size());
257 
258   CheckBoolArrayConversion(env, jbooleans, bools);
259 }
260 
CheckIntArrayConversion(JNIEnv * env,ScopedJavaLocalRef<jintArray> jints,std::vector<int> int_vector)261 void CheckIntArrayConversion(JNIEnv* env,
262                              ScopedJavaLocalRef<jintArray> jints,
263                              std::vector<int> int_vector) {
264   jint value;
265   for (size_t i = 0; i < int_vector.size(); ++i) {
266     env->GetIntArrayRegion(jints.obj(), i, 1, &value);
267     ASSERT_EQ(int_vector[i], value);
268   }
269 }
270 
TEST(JniArray,JavaIntArrayToIntVector)271 TEST(JniArray, JavaIntArrayToIntVector) {
272   const auto kInts = std::to_array<int>({0, 1, -1});
273 
274   JNIEnv* env = AttachCurrentThread();
275   ScopedJavaLocalRef<jintArray> jints(env, env->NewIntArray(kInts.size()));
276   ASSERT_TRUE(jints);
277 
278   for (size_t i = 0; i < kInts.size(); ++i) {
279     jint j = static_cast<jint>(kInts[i]);
280     env->SetIntArrayRegion(jints.obj(), i, 1, &j);
281     ASSERT_FALSE(HasException(env));
282   }
283 
284   std::vector<int> ints;
285   JavaIntArrayToIntVector(env, jints, &ints);
286 
287   ASSERT_EQ(checked_cast<jsize>(ints.size()), env->GetArrayLength(jints.obj()));
288   ASSERT_EQ(ints.size(), kInts.size());
289 
290   CheckIntArrayConversion(env, jints, ints);
291 }
292 
TEST(JniArray,JavaLongArrayToInt64Vector)293 TEST(JniArray, JavaLongArrayToInt64Vector) {
294   const auto kInt64s = std::to_array<int64_t>({0LL, 1LL, -1LL});
295 
296   JNIEnv* env = AttachCurrentThread();
297   ScopedJavaLocalRef<jlongArray> jlongs(env, env->NewLongArray(kInt64s.size()));
298   ASSERT_TRUE(jlongs);
299 
300   for (size_t i = 0; i < kInt64s.size(); ++i) {
301     jlong j = static_cast<jlong>(kInt64s[i]);
302     env->SetLongArrayRegion(jlongs.obj(), i, 1, &j);
303     ASSERT_FALSE(HasException(env));
304   }
305 
306   std::vector<int64_t> int64s;
307   JavaLongArrayToInt64Vector(env, jlongs, &int64s);
308 
309   ASSERT_EQ(checked_cast<jsize>(int64s.size()),
310             env->GetArrayLength(jlongs.obj()));
311   ASSERT_EQ(int64s.size(), kInt64s.size());
312 
313   jlong value;
314   for (size_t i = 0; i < kInt64s.size(); ++i) {
315     env->GetLongArrayRegion(jlongs.obj(), i, 1, &value);
316     ASSERT_EQ(int64s[i], value);
317     ASSERT_EQ(kInt64s[i], int64s[i]);
318   }
319 }
320 
TEST(JniArray,JavaLongArrayToLongVector)321 TEST(JniArray, JavaLongArrayToLongVector) {
322   const auto kInt64s = std::to_array<int64_t>({0LL, 1LL, -1LL});
323 
324   JNIEnv* env = AttachCurrentThread();
325   ScopedJavaLocalRef<jlongArray> jlongs(env, env->NewLongArray(kInt64s.size()));
326   ASSERT_TRUE(jlongs);
327 
328   for (size_t i = 0; i < kInt64s.size(); ++i) {
329     jlong j = static_cast<jlong>(kInt64s[i]);
330     env->SetLongArrayRegion(jlongs.obj(), i, 1, &j);
331     ASSERT_FALSE(HasException(env));
332   }
333 
334   std::vector<jlong> jlongs_vector;
335   JavaLongArrayToLongVector(env, jlongs, &jlongs_vector);
336 
337   ASSERT_EQ(checked_cast<jsize>(jlongs_vector.size()),
338             env->GetArrayLength(jlongs.obj()));
339   ASSERT_EQ(jlongs_vector.size(), kInt64s.size());
340 
341   jlong value;
342   for (size_t i = 0; i < kInt64s.size(); ++i) {
343     env->GetLongArrayRegion(jlongs.obj(), i, 1, &value);
344     ASSERT_EQ(jlongs_vector[i], value);
345   }
346 }
347 
TEST(JniArray,JavaFloatArrayToFloatVector)348 TEST(JniArray, JavaFloatArrayToFloatVector) {
349   const auto kFloats = std::to_array<float>({0.0, 0.5, -0.5});
350 
351   JNIEnv* env = AttachCurrentThread();
352   ScopedJavaLocalRef<jfloatArray> jfloats(env,
353                                           env->NewFloatArray(kFloats.size()));
354   ASSERT_TRUE(jfloats);
355 
356   for (size_t i = 0; i < kFloats.size(); ++i) {
357     jfloat j = static_cast<jfloat>(kFloats[i]);
358     env->SetFloatArrayRegion(jfloats.obj(), i, 1, &j);
359     ASSERT_FALSE(HasException(env));
360   }
361 
362   std::vector<float> floats;
363   JavaFloatArrayToFloatVector(env, jfloats, &floats);
364 
365   ASSERT_EQ(checked_cast<jsize>(floats.size()),
366             env->GetArrayLength(jfloats.obj()));
367   ASSERT_EQ(floats.size(), kFloats.size());
368 
369   jfloat value;
370   for (size_t i = 0; i < kFloats.size(); ++i) {
371     env->GetFloatArrayRegion(jfloats.obj(), i, 1, &value);
372     ASSERT_EQ(floats[i], value);
373   }
374 }
375 
TEST(JniArray,JavaDoubleArrayToDoubleVector)376 TEST(JniArray, JavaDoubleArrayToDoubleVector) {
377   const auto kDoubles = std::to_array<double>(
378       {0.0, 0.5, -0.5, std::numeric_limits<double>::min()});
379   JNIEnv* env = AttachCurrentThread();
380   ScopedJavaLocalRef<jdoubleArray> jdoubles(
381       env, env->NewDoubleArray(kDoubles.size()));
382   ASSERT_TRUE(jdoubles);
383 
384   env->SetDoubleArrayRegion(jdoubles.obj(), 0, kDoubles.size(),
385                             reinterpret_cast<const jdouble*>(kDoubles.data()));
386   ASSERT_FALSE(HasException(env));
387 
388   std::vector<double> doubles;
389   JavaDoubleArrayToDoubleVector(env, jdoubles, &doubles);
390   ASSERT_EQ(kDoubles, base::span(doubles));
391 }
392 
TEST(JniArray,JavaArrayOfByteArrayToStringVector)393 TEST(JniArray, JavaArrayOfByteArrayToStringVector) {
394   const int kMaxItems = 50;
395   JNIEnv* env = AttachCurrentThread();
396 
397   // Create a byte[][] object.
398   ScopedJavaLocalRef<jclass> byte_array_clazz(env, env->FindClass("[B"));
399   ASSERT_TRUE(byte_array_clazz);
400 
401   ScopedJavaLocalRef<jobjectArray> array(
402       env, env->NewObjectArray(kMaxItems, byte_array_clazz.obj(), NULL));
403   ASSERT_TRUE(array);
404 
405   // Create kMaxItems byte buffers.
406   char text[16];
407   for (int i = 0; i < kMaxItems; ++i) {
408     snprintf(text, std::ranges::size(text), "%d", i);
409     ScopedJavaLocalRef<jbyteArray> byte_array =
410         ToJavaByteArray(env, base::as_byte_span(text));
411     ASSERT_TRUE(byte_array);
412 
413     env->SetObjectArrayElement(array.obj(), i, byte_array.obj());
414     ASSERT_FALSE(HasException(env));
415   }
416 
417   // Convert to std::vector<std::string>, check the content.
418   std::vector<std::string> vec;
419   JavaArrayOfByteArrayToStringVector(env, array, &vec);
420 
421   EXPECT_EQ(static_cast<size_t>(kMaxItems), vec.size());
422   for (int i = 0; i < kMaxItems; ++i) {
423     snprintf(text, sizeof text, "%d", i);
424     EXPECT_STREQ(text, vec[i].c_str());
425   }
426 }
427 
TEST(JniArray,JavaArrayOfByteArrayToBytesVector)428 TEST(JniArray, JavaArrayOfByteArrayToBytesVector) {
429   const size_t kMaxItems = 50;
430   const uint8_t kStep = 37;
431   JNIEnv* env = AttachCurrentThread();
432 
433   // Create a byte[][] object.
434   ScopedJavaLocalRef<jclass> byte_array_clazz(env, env->FindClass("[B"));
435   ASSERT_TRUE(byte_array_clazz);
436 
437   ScopedJavaLocalRef<jobjectArray> array(
438       env, env->NewObjectArray(kMaxItems, byte_array_clazz.obj(), nullptr));
439   ASSERT_TRUE(array);
440 
441   // Create kMaxItems byte buffers with size |i|+1 on each step;
442   std::vector<std::vector<uint8_t>> input_bytes;
443   input_bytes.reserve(kMaxItems);
444   for (size_t i = 0; i < kMaxItems; ++i) {
445     std::vector<uint8_t> cur_bytes(i + 1);
446     for (size_t j = 0; j < cur_bytes.size(); ++j)
447       cur_bytes[j] = static_cast<uint8_t>(i + j * kStep);
448     ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(env, cur_bytes);
449     ASSERT_TRUE(byte_array);
450 
451     env->SetObjectArrayElement(array.obj(), i, byte_array.obj());
452     ASSERT_FALSE(HasException(env));
453 
454     input_bytes.push_back(std::move(cur_bytes));
455   }
456   ASSERT_EQ(kMaxItems, input_bytes.size());
457 
458   // Convert to std::vector<std::vector<uint8_t>>, check the content.
459   std::vector<std::vector<uint8_t>> result;
460   JavaArrayOfByteArrayToBytesVector(env, array, &result);
461 
462   EXPECT_EQ(input_bytes.size(), result.size());
463   for (size_t i = 0; i < kMaxItems; ++i)
464     EXPECT_THAT(result[i], ::testing::ElementsAreArray(input_bytes.at(i)));
465 }
466 
TEST(JniArray,JavaArrayOfStringArrayToVectorOfStringVector)467 TEST(JniArray, JavaArrayOfStringArrayToVectorOfStringVector) {
468   const std::vector<std::vector<std::u16string>> kArrays = {
469       {u"a", u"f"}, {u"a", u""}, {}, {u""}};
470 
471   JNIEnv* env = AttachCurrentThread();
472 
473   ScopedJavaLocalRef<jobjectArray> array(
474       env, env->NewObjectArray(kArrays.size(),
475                                env->FindClass("[Ljava/lang/String;"), NULL));
476   ASSERT_TRUE(array);
477 
478   ScopedJavaLocalRef<jclass> string_clazz(env,
479                                           env->FindClass("java/lang/String"));
480   ASSERT_TRUE(string_clazz);
481 
482   for (size_t i = 0; i < kArrays.size(); ++i) {
483     const std::vector<std::u16string>& child_data = kArrays[i];
484 
485     ScopedJavaLocalRef<jobjectArray> child_array(
486         env, env->NewObjectArray(child_data.size(), string_clazz.obj(), NULL));
487     ASSERT_TRUE(child_array);
488 
489     for (size_t j = 0; j < child_data.size(); ++j) {
490       ScopedJavaLocalRef<jstring> item =
491           base::android::ConvertUTF16ToJavaString(env, child_data[j]);
492       env->SetObjectArrayElement(child_array.obj(), j, item.obj());
493       ASSERT_FALSE(HasException(env));
494     }
495     env->SetObjectArrayElement(array.obj(), i, child_array.obj());
496   }
497 
498   std::vector<std::vector<std::u16string>> vec;
499   Java2dStringArrayTo2dStringVector(env, array, &vec);
500 
501   ASSERT_EQ(kArrays, vec);
502 }
503 
TEST(JniArray,JavaArrayOfIntArrayToIntVector)504 TEST(JniArray, JavaArrayOfIntArrayToIntVector) {
505   const size_t kNumItems = 4;
506   JNIEnv* env = AttachCurrentThread();
507 
508   // Create an int[][] object.
509   ScopedJavaLocalRef<jclass> int_array_clazz(env, env->FindClass("[I"));
510   ASSERT_TRUE(int_array_clazz);
511 
512   ScopedJavaLocalRef<jobjectArray> array(
513       env, env->NewObjectArray(kNumItems, int_array_clazz.obj(), nullptr));
514   ASSERT_TRUE(array);
515 
516   // Populate int[][] object.
517   const auto kInts0 =
518       std::to_array<int>({0, 1, -1, std::numeric_limits<int32_t>::min(),
519                           std::numeric_limits<int32_t>::max()});
520   ScopedJavaLocalRef<jintArray> int_array0 = ToJavaIntArray(env, kInts0);
521   env->SetObjectArrayElement(array.obj(), 0, int_array0.obj());
522 
523   const auto kInts1 = std::to_array<int>({3, 4, 5});
524   ScopedJavaLocalRef<jintArray> int_array1 = ToJavaIntArray(env, kInts1);
525   env->SetObjectArrayElement(array.obj(), 1, int_array1.obj());
526 
527   const auto kInts2 = std::array<int, 0>();
528   ScopedJavaLocalRef<jintArray> int_array2 = ToJavaIntArray(env, kInts2);
529   env->SetObjectArrayElement(array.obj(), 2, int_array2.obj());
530 
531   const auto kInts3 = std::to_array<int>({16});
532   ScopedJavaLocalRef<jintArray> int_array3 = ToJavaIntArray(env, kInts3);
533   env->SetObjectArrayElement(array.obj(), 3, int_array3.obj());
534 
535   // Convert to std::vector<std::vector<int>>, check the content.
536   std::vector<std::vector<int>> out;
537   JavaArrayOfIntArrayToIntVector(env, array, &out);
538 
539   EXPECT_EQ(kNumItems, out.size());
540   EXPECT_EQ(kInts0.size(), out[0].size());
541   EXPECT_EQ(kInts1.size(), out[1].size());
542   EXPECT_EQ(kInts2.size(), out[2].size());
543   EXPECT_EQ(kInts3.size(), out[3].size());
544   CheckIntArrayConversion(env, int_array0, out[0]);
545   CheckIntArrayConversion(env, int_array1, out[1]);
546   CheckIntArrayConversion(env, int_array2, out[2]);
547   CheckIntArrayConversion(env, int_array3, out[3]);
548 }
549 
TEST(JniArray,ToJavaArrayOfObjectsOfClass)550 TEST(JniArray, ToJavaArrayOfObjectsOfClass) {
551   JNIEnv* env = AttachCurrentThread();
552 
553   std::vector<ScopedJavaLocalRef<jobject>> objects = {
554       ScopedJavaLocalRef<jobject>(ConvertUTF8ToJavaString(env, "one")),
555       ScopedJavaLocalRef<jobject>(ConvertUTF8ToJavaString(env, "two")),
556       ScopedJavaLocalRef<jobject>(ConvertUTF8ToJavaString(env, "three")),
557   };
558 
559   ScopedJavaLocalRef<jobjectArray> j_array =
560       ToJavaArrayOfObjects(env, jni_zero::g_string_class, objects);
561   ASSERT_TRUE(j_array);
562 
563   EXPECT_EQ("one",
564             ConvertJavaStringToUTF8(
565                 env, ScopedJavaLocalRef<jstring>(
566                          env, static_cast<jstring>(env->GetObjectArrayElement(
567                                   j_array.obj(), 0)))));
568   EXPECT_EQ("two",
569             ConvertJavaStringToUTF8(
570                 env, ScopedJavaLocalRef<jstring>(
571                          env, static_cast<jstring>(env->GetObjectArrayElement(
572                                   j_array.obj(), 1)))));
573   EXPECT_EQ("three",
574             ConvertJavaStringToUTF8(
575                 env, ScopedJavaLocalRef<jstring>(
576                          env, static_cast<jstring>(env->GetObjectArrayElement(
577                                   j_array.obj(), 2)))));
578 }
579 
TEST(JniArray,ToJavaArrayOfObjectLocalRef)580 TEST(JniArray, ToJavaArrayOfObjectLocalRef) {
581   JNIEnv* env = AttachCurrentThread();
582 
583   std::vector<ScopedJavaLocalRef<jobject>> objects = {
584       ScopedJavaLocalRef<jobject>(ConvertUTF8ToJavaString(env, "one")),
585       ScopedJavaLocalRef<jobject>(ConvertUTF8ToJavaString(env, "two")),
586       ScopedJavaLocalRef<jobject>(ConvertUTF8ToJavaString(env, "three")),
587   };
588 
589   ScopedJavaLocalRef<jobjectArray> j_array = ToJavaArrayOfObjects(env, objects);
590   ASSERT_TRUE(j_array);
591 
592   EXPECT_EQ("one",
593             ConvertJavaStringToUTF8(
594                 env, ScopedJavaLocalRef<jstring>(
595                          env, static_cast<jstring>(env->GetObjectArrayElement(
596                                   j_array.obj(), 0)))));
597   EXPECT_EQ("two",
598             ConvertJavaStringToUTF8(
599                 env, ScopedJavaLocalRef<jstring>(
600                          env, static_cast<jstring>(env->GetObjectArrayElement(
601                                   j_array.obj(), 1)))));
602   EXPECT_EQ("three",
603             ConvertJavaStringToUTF8(
604                 env, ScopedJavaLocalRef<jstring>(
605                          env, static_cast<jstring>(env->GetObjectArrayElement(
606                                   j_array.obj(), 2)))));
607 }
608 
TEST(JniArray,ToJavaArrayOfObjectGlobalRef)609 TEST(JniArray, ToJavaArrayOfObjectGlobalRef) {
610   JNIEnv* env = AttachCurrentThread();
611 
612   std::vector<ScopedJavaGlobalRef<jobject>> objects = {
613       ScopedJavaGlobalRef<jobject>(ConvertUTF8ToJavaString(env, "one")),
614       ScopedJavaGlobalRef<jobject>(ConvertUTF8ToJavaString(env, "two")),
615       ScopedJavaGlobalRef<jobject>(ConvertUTF8ToJavaString(env, "three")),
616   };
617 
618   ScopedJavaLocalRef<jobjectArray> j_array = ToJavaArrayOfObjects(env, objects);
619   ASSERT_TRUE(j_array);
620 
621   EXPECT_EQ("one",
622             ConvertJavaStringToUTF8(
623                 env, ScopedJavaLocalRef<jstring>(
624                          env, static_cast<jstring>(env->GetObjectArrayElement(
625                                   j_array.obj(), 0)))));
626   EXPECT_EQ("two",
627             ConvertJavaStringToUTF8(
628                 env, ScopedJavaLocalRef<jstring>(
629                          env, static_cast<jstring>(env->GetObjectArrayElement(
630                                   j_array.obj(), 1)))));
631   EXPECT_EQ("three",
632             ConvertJavaStringToUTF8(
633                 env, ScopedJavaLocalRef<jstring>(
634                          env, static_cast<jstring>(env->GetObjectArrayElement(
635                                   j_array.obj(), 2)))));
636 }
637 }  // namespace base::android
638