| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/android/jni_array.h" |
| |
| #include <limits> |
| |
| #include "base/android/jni_android.h" |
| #include "base/android/scoped_java_ref.h" |
| #include "base/macros.h" |
| #include "starboard/common/string.h" |
| #include "starboard/types.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace base { |
| namespace android { |
| |
| TEST(JniArray, BasicConversions) { |
| const uint8_t kBytes[] = {0, 1, 2, 3}; |
| const size_t kLen = arraysize(kBytes); |
| JNIEnv* env = AttachCurrentThread(); |
| ScopedJavaLocalRef<jbyteArray> bytes = ToJavaByteArray(env, kBytes, kLen); |
| ASSERT_TRUE(bytes.obj()); |
| |
| std::vector<uint8_t> inputVector(kBytes, kBytes + kLen); |
| ScopedJavaLocalRef<jbyteArray> bytesFromVector = |
| ToJavaByteArray(env, inputVector); |
| ASSERT_TRUE(bytesFromVector.obj()); |
| |
| std::vector<uint8_t> vectorFromBytes(5); |
| std::vector<uint8_t> vectorFromVector(5); |
| JavaByteArrayToByteVector(env, bytes.obj(), &vectorFromBytes); |
| JavaByteArrayToByteVector(env, bytesFromVector.obj(), &vectorFromVector); |
| EXPECT_EQ(4U, vectorFromBytes.size()); |
| EXPECT_EQ(4U, vectorFromVector.size()); |
| std::vector<uint8_t> expected_vec(kBytes, kBytes + kLen); |
| EXPECT_EQ(expected_vec, vectorFromBytes); |
| EXPECT_EQ(expected_vec, vectorFromVector); |
| |
| AppendJavaByteArrayToByteVector(env, bytes.obj(), &vectorFromBytes); |
| EXPECT_EQ(8U, vectorFromBytes.size()); |
| expected_vec.insert(expected_vec.end(), kBytes, kBytes + kLen); |
| EXPECT_EQ(expected_vec, vectorFromBytes); |
| } |
| |
| TEST(JniArray, ByteArrayStringConversions) { |
| JNIEnv* env = AttachCurrentThread(); |
| std::string inputString("hello\0world"); |
| ScopedJavaLocalRef<jbyteArray> bytesFromString = |
| ToJavaByteArray(env, inputString); |
| ASSERT_TRUE(bytesFromString.obj()); |
| |
| std::string stringFromString; |
| JavaByteArrayToString(env, bytesFromString.obj(), &stringFromString); |
| EXPECT_EQ(inputString, stringFromString); |
| } |
| |
| void CheckBoolConversion(JNIEnv* env, |
| const bool* bool_array, |
| const size_t len, |
| const ScopedJavaLocalRef<jbooleanArray>& booleans) { |
| ASSERT_TRUE(booleans.obj()); |
| |
| jsize java_array_len = env->GetArrayLength(booleans.obj()); |
| ASSERT_EQ(static_cast<jsize>(len), java_array_len); |
| |
| jboolean value; |
| for (size_t i = 0; i < len; ++i) { |
| env->GetBooleanArrayRegion(booleans.obj(), i, 1, &value); |
| ASSERT_EQ(bool_array[i], value); |
| } |
| } |
| |
| TEST(JniArray, BoolConversions) { |
| const bool kBools[] = {false, true, false}; |
| const size_t kLen = arraysize(kBools); |
| |
| JNIEnv* env = AttachCurrentThread(); |
| CheckBoolConversion(env, kBools, kLen, ToJavaBooleanArray(env, kBools, kLen)); |
| } |
| |
| void CheckIntConversion( |
| JNIEnv* env, |
| const int* int_array, |
| const size_t len, |
| const ScopedJavaLocalRef<jintArray>& ints) { |
| ASSERT_TRUE(ints.obj()); |
| |
| jsize java_array_len = env->GetArrayLength(ints.obj()); |
| ASSERT_EQ(static_cast<jsize>(len), java_array_len); |
| |
| jint value; |
| for (size_t i = 0; i < len; ++i) { |
| env->GetIntArrayRegion(ints.obj(), i, 1, &value); |
| ASSERT_EQ(int_array[i], value); |
| } |
| } |
| |
| TEST(JniArray, IntConversions) { |
| const int kInts[] = {0, 1, -1, std::numeric_limits<int32_t>::min(), |
| std::numeric_limits<int32_t>::max()}; |
| const size_t kLen = arraysize(kInts); |
| |
| JNIEnv* env = AttachCurrentThread(); |
| CheckIntConversion(env, kInts, kLen, ToJavaIntArray(env, kInts, kLen)); |
| |
| const std::vector<int> vec(kInts, kInts + kLen); |
| CheckIntConversion(env, kInts, kLen, ToJavaIntArray(env, vec)); |
| } |
| |
| void CheckLongConversion(JNIEnv* env, |
| const int64_t* long_array, |
| const size_t len, |
| const ScopedJavaLocalRef<jlongArray>& longs) { |
| ASSERT_TRUE(longs.obj()); |
| |
| jsize java_array_len = env->GetArrayLength(longs.obj()); |
| ASSERT_EQ(static_cast<jsize>(len), java_array_len); |
| |
| jlong value; |
| for (size_t i = 0; i < len; ++i) { |
| env->GetLongArrayRegion(longs.obj(), i, 1, &value); |
| ASSERT_EQ(long_array[i], value); |
| } |
| } |
| |
| TEST(JniArray, LongConversions) { |
| const int64_t kLongs[] = {0, 1, -1, std::numeric_limits<int64_t>::min(), |
| std::numeric_limits<int64_t>::max()}; |
| const size_t kLen = arraysize(kLongs); |
| |
| JNIEnv* env = AttachCurrentThread(); |
| CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, kLongs, kLen)); |
| |
| const std::vector<int64_t> vec(kLongs, kLongs + kLen); |
| CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, vec)); |
| } |
| |
| void CheckIntArrayConversion(JNIEnv* env, |
| ScopedJavaLocalRef<jintArray> jints, |
| std::vector<int> int_vector, |
| const size_t len) { |
| jint value; |
| for (size_t i = 0; i < len; ++i) { |
| env->GetIntArrayRegion(jints.obj(), i, 1, &value); |
| ASSERT_EQ(int_vector[i], value); |
| } |
| } |
| |
| void CheckBoolArrayConversion(JNIEnv* env, |
| ScopedJavaLocalRef<jbooleanArray> jbooleans, |
| std::vector<bool> bool_vector, |
| const size_t len) { |
| jboolean value; |
| for (size_t i = 0; i < len; ++i) { |
| env->GetBooleanArrayRegion(jbooleans.obj(), i, 1, &value); |
| ASSERT_EQ(bool_vector[i], value); |
| } |
| } |
| |
| void CheckFloatConversion( |
| JNIEnv* env, |
| const float* float_array, |
| const size_t len, |
| const ScopedJavaLocalRef<jfloatArray>& floats) { |
| ASSERT_TRUE(floats.obj()); |
| |
| jsize java_array_len = env->GetArrayLength(floats.obj()); |
| ASSERT_EQ(static_cast<jsize>(len), java_array_len); |
| |
| jfloat value; |
| for (size_t i = 0; i < len; ++i) { |
| env->GetFloatArrayRegion(floats.obj(), i, 1, &value); |
| ASSERT_EQ(float_array[i], value); |
| } |
| } |
| |
| TEST(JniArray, FloatConversions) { |
| const float kFloats[] = { 0.0f, 1.0f, -10.0f}; |
| const size_t kLen = arraysize(kFloats); |
| |
| JNIEnv* env = AttachCurrentThread(); |
| CheckFloatConversion(env, kFloats, kLen, |
| ToJavaFloatArray(env, kFloats, kLen)); |
| |
| const std::vector<float> vec(kFloats, kFloats + kLen); |
| CheckFloatConversion(env, kFloats, kLen, ToJavaFloatArray(env, vec)); |
| } |
| |
| TEST(JniArray, JavaBooleanArrayToBoolVector) { |
| const bool kBools[] = {false, true, false}; |
| const size_t kLen = arraysize(kBools); |
| |
| JNIEnv* env = AttachCurrentThread(); |
| ScopedJavaLocalRef<jbooleanArray> jbooleans(env, env->NewBooleanArray(kLen)); |
| ASSERT_TRUE(jbooleans.obj()); |
| |
| for (size_t i = 0; i < kLen; ++i) { |
| jboolean j = static_cast<jboolean>(kBools[i]); |
| env->SetBooleanArrayRegion(jbooleans.obj(), i, 1, &j); |
| ASSERT_FALSE(HasException(env)); |
| } |
| |
| std::vector<bool> bools; |
| JavaBooleanArrayToBoolVector(env, jbooleans.obj(), &bools); |
| |
| ASSERT_EQ(static_cast<jsize>(bools.size()), |
| env->GetArrayLength(jbooleans.obj())); |
| |
| CheckBoolArrayConversion(env, jbooleans, bools, kLen); |
| } |
| |
| TEST(JniArray, JavaIntArrayToIntVector) { |
| const int kInts[] = {0, 1, -1}; |
| const size_t kLen = arraysize(kInts); |
| |
| JNIEnv* env = AttachCurrentThread(); |
| ScopedJavaLocalRef<jintArray> jints(env, env->NewIntArray(kLen)); |
| ASSERT_TRUE(jints.obj()); |
| |
| for (size_t i = 0; i < kLen; ++i) { |
| jint j = static_cast<jint>(kInts[i]); |
| env->SetIntArrayRegion(jints.obj(), i, 1, &j); |
| ASSERT_FALSE(HasException(env)); |
| } |
| |
| std::vector<int> ints; |
| JavaIntArrayToIntVector(env, jints.obj(), &ints); |
| |
| ASSERT_EQ(static_cast<jsize>(ints.size()), env->GetArrayLength(jints.obj())); |
| |
| CheckIntArrayConversion(env, jints, ints, kLen); |
| } |
| |
| TEST(JniArray, JavaLongArrayToInt64Vector) { |
| const int64_t kInt64s[] = {0LL, 1LL, -1LL}; |
| const size_t kLen = arraysize(kInt64s); |
| |
| JNIEnv* env = AttachCurrentThread(); |
| ScopedJavaLocalRef<jlongArray> jlongs(env, env->NewLongArray(kLen)); |
| ASSERT_TRUE(jlongs.obj()); |
| |
| for (size_t i = 0; i < kLen; ++i) { |
| jlong j = static_cast<jlong>(kInt64s[i]); |
| env->SetLongArrayRegion(jlongs.obj(), i, 1, &j); |
| ASSERT_FALSE(HasException(env)); |
| } |
| |
| std::vector<int64_t> int64s; |
| JavaLongArrayToInt64Vector(env, jlongs.obj(), &int64s); |
| |
| ASSERT_EQ(static_cast<jsize>(int64s.size()), |
| env->GetArrayLength(jlongs.obj())); |
| |
| jlong value; |
| for (size_t i = 0; i < kLen; ++i) { |
| env->GetLongArrayRegion(jlongs.obj(), i, 1, &value); |
| ASSERT_EQ(int64s[i], value); |
| ASSERT_EQ(kInt64s[i], int64s[i]); |
| } |
| } |
| |
| TEST(JniArray, JavaLongArrayToLongVector) { |
| const int64_t kInt64s[] = {0LL, 1LL, -1LL}; |
| const size_t kLen = arraysize(kInt64s); |
| |
| JNIEnv* env = AttachCurrentThread(); |
| ScopedJavaLocalRef<jlongArray> jlongs(env, env->NewLongArray(kLen)); |
| ASSERT_TRUE(jlongs.obj()); |
| |
| for (size_t i = 0; i < kLen; ++i) { |
| jlong j = static_cast<jlong>(kInt64s[i]); |
| env->SetLongArrayRegion(jlongs.obj(), i, 1, &j); |
| ASSERT_FALSE(HasException(env)); |
| } |
| |
| std::vector<jlong> jlongs_vector; |
| JavaLongArrayToLongVector(env, jlongs.obj(), &jlongs_vector); |
| |
| ASSERT_EQ(static_cast<jsize>(jlongs_vector.size()), |
| env->GetArrayLength(jlongs.obj())); |
| |
| jlong value; |
| for (size_t i = 0; i < kLen; ++i) { |
| env->GetLongArrayRegion(jlongs.obj(), i, 1, &value); |
| ASSERT_EQ(jlongs_vector[i], value); |
| } |
| } |
| |
| TEST(JniArray, JavaFloatArrayToFloatVector) { |
| const float kFloats[] = {0.0, 0.5, -0.5}; |
| const size_t kLen = arraysize(kFloats); |
| |
| JNIEnv* env = AttachCurrentThread(); |
| ScopedJavaLocalRef<jfloatArray> jfloats(env, env->NewFloatArray(kLen)); |
| ASSERT_TRUE(jfloats.obj()); |
| |
| for (size_t i = 0; i < kLen; ++i) { |
| jfloat j = static_cast<jfloat>(kFloats[i]); |
| env->SetFloatArrayRegion(jfloats.obj(), i, 1, &j); |
| ASSERT_FALSE(HasException(env)); |
| } |
| |
| std::vector<float> floats; |
| JavaFloatArrayToFloatVector(env, jfloats.obj(), &floats); |
| |
| ASSERT_EQ(static_cast<jsize>(floats.size()), |
| env->GetArrayLength(jfloats.obj())); |
| |
| jfloat value; |
| for (size_t i = 0; i < kLen; ++i) { |
| env->GetFloatArrayRegion(jfloats.obj(), i, 1, &value); |
| ASSERT_EQ(floats[i], value); |
| } |
| } |
| |
| TEST(JniArray, JavaArrayOfByteArrayToStringVector) { |
| const int kMaxItems = 50; |
| JNIEnv* env = AttachCurrentThread(); |
| |
| // Create a byte[][] object. |
| ScopedJavaLocalRef<jclass> byte_array_clazz(env, env->FindClass("[B")); |
| ASSERT_TRUE(byte_array_clazz.obj()); |
| |
| ScopedJavaLocalRef<jobjectArray> array( |
| env, env->NewObjectArray(kMaxItems, byte_array_clazz.obj(), NULL)); |
| ASSERT_TRUE(array.obj()); |
| |
| // Create kMaxItems byte buffers. |
| char text[16]; |
| for (int i = 0; i < kMaxItems; ++i) { |
| snprintf(text, sizeof text, "%d", i); |
| ScopedJavaLocalRef<jbyteArray> byte_array = |
| ToJavaByteArray(env, reinterpret_cast<uint8_t*>(text), |
| static_cast<size_t>(SbStringGetLength(text))); |
| ASSERT_TRUE(byte_array.obj()); |
| |
| env->SetObjectArrayElement(array.obj(), i, byte_array.obj()); |
| ASSERT_FALSE(HasException(env)); |
| } |
| |
| // Convert to std::vector<std::string>, check the content. |
| std::vector<std::string> vec; |
| JavaArrayOfByteArrayToStringVector(env, array.obj(), &vec); |
| |
| EXPECT_EQ(static_cast<size_t>(kMaxItems), vec.size()); |
| for (int i = 0; i < kMaxItems; ++i) { |
| snprintf(text, sizeof text, "%d", i); |
| EXPECT_STREQ(text, vec[i].c_str()); |
| } |
| } |
| |
| TEST(JniArray, JavaArrayOfIntArrayToIntVector) { |
| const size_t kNumItems = 4; |
| JNIEnv* env = AttachCurrentThread(); |
| |
| // Create an int[][] object. |
| ScopedJavaLocalRef<jclass> int_array_clazz(env, env->FindClass("[I")); |
| ASSERT_TRUE(int_array_clazz.obj()); |
| |
| ScopedJavaLocalRef<jobjectArray> array( |
| env, env->NewObjectArray(kNumItems, int_array_clazz.obj(), nullptr)); |
| ASSERT_TRUE(array.obj()); |
| |
| // Populate int[][] object. |
| const int kInts0[] = {0, 1, -1, std::numeric_limits<int32_t>::min(), |
| std::numeric_limits<int32_t>::max()}; |
| const size_t kLen0 = arraysize(kInts0); |
| ScopedJavaLocalRef<jintArray> int_array0 = ToJavaIntArray(env, kInts0, kLen0); |
| env->SetObjectArrayElement(array.obj(), 0, int_array0.obj()); |
| |
| const int kInts1[] = {3, 4, 5}; |
| const size_t kLen1 = arraysize(kInts1); |
| ScopedJavaLocalRef<jintArray> int_array1 = ToJavaIntArray(env, kInts1, kLen1); |
| env->SetObjectArrayElement(array.obj(), 1, int_array1.obj()); |
| |
| const int kInts2[] = {}; |
| const size_t kLen2 = 0; |
| ScopedJavaLocalRef<jintArray> int_array2 = ToJavaIntArray(env, kInts2, kLen2); |
| env->SetObjectArrayElement(array.obj(), 2, int_array2.obj()); |
| |
| const int kInts3[] = {16}; |
| const size_t kLen3 = arraysize(kInts3); |
| ScopedJavaLocalRef<jintArray> int_array3 = ToJavaIntArray(env, kInts3, kLen3); |
| env->SetObjectArrayElement(array.obj(), 3, int_array3.obj()); |
| |
| // Convert to std::vector<std::vector<int>>, check the content. |
| std::vector<std::vector<int>> out; |
| JavaArrayOfIntArrayToIntVector(env, array.obj(), &out); |
| |
| EXPECT_EQ(kNumItems, out.size()); |
| CheckIntArrayConversion(env, int_array0, out[0], kLen0); |
| CheckIntArrayConversion(env, int_array1, out[1], kLen1); |
| CheckIntArrayConversion(env, int_array2, out[2], kLen2); |
| CheckIntArrayConversion(env, int_array3, out[3], kLen3); |
| } |
| |
| } // namespace android |
| } // namespace base |