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