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