Home | History | Annotate | Download | only in android
      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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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