scoped_java_ref_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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. #include "base/android/scoped_java_ref.h"
  5. #include <iterator>
  6. #include <type_traits>
  7. #include "base/android/jni_android.h"
  8. #include "base/android/jni_string.h"
  9. #include "testing/gtest/include/gtest/gtest.h"
  10. #define EXPECT_SAME_OBJECT(a, b) \
  11. EXPECT_TRUE(env->IsSameObject((a).obj(), (b).obj()))
  12. namespace base {
  13. namespace android {
  14. namespace {
  15. int g_local_refs = 0;
  16. int g_global_refs = 0;
  17. const JNINativeInterface* g_previous_functions;
  18. jobject NewGlobalRef(JNIEnv* env, jobject obj) {
  19. ++g_global_refs;
  20. return g_previous_functions->NewGlobalRef(env, obj);
  21. }
  22. void DeleteGlobalRef(JNIEnv* env, jobject obj) {
  23. --g_global_refs;
  24. return g_previous_functions->DeleteGlobalRef(env, obj);
  25. }
  26. jobject NewLocalRef(JNIEnv* env, jobject obj) {
  27. ++g_local_refs;
  28. return g_previous_functions->NewLocalRef(env, obj);
  29. }
  30. void DeleteLocalRef(JNIEnv* env, jobject obj) {
  31. --g_local_refs;
  32. return g_previous_functions->DeleteLocalRef(env, obj);
  33. }
  34. } // namespace
  35. class ScopedJavaRefTest : public testing::Test {
  36. protected:
  37. void SetUp() override {
  38. g_local_refs = 0;
  39. g_global_refs = 0;
  40. JNIEnv* env = AttachCurrentThread();
  41. g_previous_functions = env->functions;
  42. hooked_functions = *g_previous_functions;
  43. env->functions = &hooked_functions;
  44. // We inject our own functions in JNINativeInterface so we can keep track
  45. // of the reference counting ourselves.
  46. hooked_functions.NewGlobalRef = &NewGlobalRef;
  47. hooked_functions.DeleteGlobalRef = &DeleteGlobalRef;
  48. hooked_functions.NewLocalRef = &NewLocalRef;
  49. hooked_functions.DeleteLocalRef = &DeleteLocalRef;
  50. }
  51. void TearDown() override {
  52. JNIEnv* env = AttachCurrentThread();
  53. env->functions = g_previous_functions;
  54. }
  55. // From JellyBean release, the instance of this struct provided in JNIEnv is
  56. // read-only, so we deep copy it to allow individual functions to be hooked.
  57. JNINativeInterface hooked_functions;
  58. };
  59. // The main purpose of this is testing the various conversions compile.
  60. TEST_F(ScopedJavaRefTest, Conversions) {
  61. JNIEnv* env = AttachCurrentThread();
  62. ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(env, "string");
  63. ScopedJavaGlobalRef<jstring> global(str);
  64. // Contextual conversions to bool should be allowed.
  65. EXPECT_TRUE(str);
  66. EXPECT_FALSE(JavaRef<jobject>());
  67. // All the types should convert from nullptr, even JavaRef.
  68. {
  69. JavaRef<jstring> null_ref(nullptr);
  70. EXPECT_FALSE(null_ref);
  71. ScopedJavaLocalRef<jobject> null_local(nullptr);
  72. EXPECT_FALSE(null_local);
  73. ScopedJavaGlobalRef<jarray> null_global(nullptr);
  74. EXPECT_FALSE(null_global);
  75. }
  76. // Local and global refs should {copy,move}-{construct,assign}.
  77. // Moves should leave the source as null.
  78. {
  79. ScopedJavaLocalRef<jstring> str2(str);
  80. EXPECT_SAME_OBJECT(str2, str);
  81. ScopedJavaLocalRef<jstring> str3(std::move(str2));
  82. EXPECT_SAME_OBJECT(str3, str);
  83. EXPECT_FALSE(str2);
  84. ScopedJavaLocalRef<jstring> str4;
  85. str4 = str;
  86. EXPECT_SAME_OBJECT(str4, str);
  87. ScopedJavaLocalRef<jstring> str5;
  88. str5 = std::move(str4);
  89. EXPECT_SAME_OBJECT(str5, str);
  90. EXPECT_FALSE(str4);
  91. }
  92. {
  93. ScopedJavaGlobalRef<jstring> str2(global);
  94. EXPECT_SAME_OBJECT(str2, str);
  95. ScopedJavaGlobalRef<jstring> str3(std::move(str2));
  96. EXPECT_SAME_OBJECT(str3, str);
  97. EXPECT_FALSE(str2);
  98. ScopedJavaGlobalRef<jstring> str4;
  99. str4 = global;
  100. EXPECT_SAME_OBJECT(str4, str);
  101. ScopedJavaGlobalRef<jstring> str5;
  102. str5 = std::move(str4);
  103. EXPECT_SAME_OBJECT(str5, str);
  104. EXPECT_FALSE(str4);
  105. }
  106. // As above but going from jstring to jobject.
  107. {
  108. ScopedJavaLocalRef<jobject> obj2(str);
  109. EXPECT_SAME_OBJECT(obj2, str);
  110. ScopedJavaLocalRef<jobject> obj3(std::move(obj2));
  111. EXPECT_SAME_OBJECT(obj3, str);
  112. EXPECT_FALSE(obj2);
  113. ScopedJavaLocalRef<jobject> obj4;
  114. obj4 = str;
  115. EXPECT_SAME_OBJECT(obj4, str);
  116. ScopedJavaLocalRef<jobject> obj5;
  117. obj5 = std::move(obj4);
  118. EXPECT_SAME_OBJECT(obj5, str);
  119. EXPECT_FALSE(obj4);
  120. }
  121. {
  122. ScopedJavaGlobalRef<jobject> obj2(global);
  123. EXPECT_SAME_OBJECT(obj2, str);
  124. ScopedJavaGlobalRef<jobject> obj3(std::move(obj2));
  125. EXPECT_SAME_OBJECT(obj3, str);
  126. EXPECT_FALSE(obj2);
  127. ScopedJavaGlobalRef<jobject> obj4;
  128. obj4 = global;
  129. EXPECT_SAME_OBJECT(obj4, str);
  130. ScopedJavaGlobalRef<jobject> obj5;
  131. obj5 = std::move(obj4);
  132. EXPECT_SAME_OBJECT(obj5, str);
  133. EXPECT_FALSE(obj4);
  134. }
  135. // Explicit copy construction or assignment between global<->local is allowed,
  136. // but not implicit conversions.
  137. {
  138. ScopedJavaLocalRef<jstring> new_local(global);
  139. EXPECT_SAME_OBJECT(new_local, str);
  140. new_local = global;
  141. EXPECT_SAME_OBJECT(new_local, str);
  142. ScopedJavaGlobalRef<jstring> new_global(str);
  143. EXPECT_SAME_OBJECT(new_global, str);
  144. new_global = str;
  145. EXPECT_SAME_OBJECT(new_local, str);
  146. static_assert(!std::is_convertible<ScopedJavaLocalRef<jobject>,
  147. ScopedJavaGlobalRef<jobject>>::value,
  148. "");
  149. static_assert(!std::is_convertible<ScopedJavaGlobalRef<jobject>,
  150. ScopedJavaLocalRef<jobject>>::value,
  151. "");
  152. }
  153. // Converting between local/global while also converting to jobject also works
  154. // because JavaRef<jobject> is the base class.
  155. {
  156. ScopedJavaGlobalRef<jobject> global_obj(str);
  157. ScopedJavaLocalRef<jobject> local_obj(global);
  158. const JavaRef<jobject>& obj_ref1(str);
  159. const JavaRef<jobject>& obj_ref2(global);
  160. EXPECT_SAME_OBJECT(obj_ref1, obj_ref2);
  161. EXPECT_SAME_OBJECT(global_obj, obj_ref2);
  162. }
  163. global.Reset(str);
  164. const JavaRef<jstring>& str_ref = str;
  165. EXPECT_EQ("string", ConvertJavaStringToUTF8(str_ref));
  166. str.Reset();
  167. }
  168. TEST_F(ScopedJavaRefTest, RefCounts) {
  169. JNIEnv* env = AttachCurrentThread();
  170. ScopedJavaLocalRef<jstring> str;
  171. // The ConvertJavaStringToUTF8 below creates a new string that would normally
  172. // return a local ref. We simulate that by starting the g_local_refs count at
  173. // 1.
  174. g_local_refs = 1;
  175. str.Reset(ConvertUTF8ToJavaString(env, "string"));
  176. EXPECT_EQ(1, g_local_refs);
  177. EXPECT_EQ(0, g_global_refs);
  178. {
  179. ScopedJavaGlobalRef<jstring> global_str(str);
  180. ScopedJavaGlobalRef<jobject> global_obj(global_str);
  181. EXPECT_EQ(1, g_local_refs);
  182. EXPECT_EQ(2, g_global_refs);
  183. auto str2 = ScopedJavaLocalRef<jstring>::Adopt(env, str.Release());
  184. EXPECT_EQ(1, g_local_refs);
  185. {
  186. ScopedJavaLocalRef<jstring> str3(str2);
  187. EXPECT_EQ(2, g_local_refs);
  188. }
  189. EXPECT_EQ(1, g_local_refs);
  190. {
  191. ScopedJavaLocalRef<jstring> str4((ScopedJavaLocalRef<jstring>(str2)));
  192. EXPECT_EQ(2, g_local_refs);
  193. }
  194. EXPECT_EQ(1, g_local_refs);
  195. {
  196. ScopedJavaLocalRef<jstring> str5;
  197. str5 = ScopedJavaLocalRef<jstring>(str2);
  198. EXPECT_EQ(2, g_local_refs);
  199. }
  200. EXPECT_EQ(1, g_local_refs);
  201. str2.Reset();
  202. EXPECT_EQ(0, g_local_refs);
  203. global_str.Reset();
  204. EXPECT_EQ(1, g_global_refs);
  205. ScopedJavaGlobalRef<jobject> global_obj2(global_obj);
  206. EXPECT_EQ(2, g_global_refs);
  207. }
  208. EXPECT_EQ(0, g_local_refs);
  209. EXPECT_EQ(0, g_global_refs);
  210. }
  211. class JavaObjectArrayReaderTest : public testing::Test {
  212. protected:
  213. void SetUp() override {
  214. JNIEnv* env = AttachCurrentThread();
  215. int_class_ = GetClass(env, "java/lang/Integer");
  216. int_constructor_ = MethodID::Get<MethodID::TYPE_INSTANCE>(
  217. env, int_class_.obj(), "<init>", "(I)V");
  218. array_ = MakeArray(array_len_);
  219. // Make array_len_ different Integer objects, keep a reference to each,
  220. // and add them to the array.
  221. for (jint i = 0; i < array_len_; ++i) {
  222. jobject member = env->NewObject(int_class_.obj(), int_constructor_, i);
  223. ASSERT_NE(member, nullptr);
  224. array_members_[i] = ScopedJavaLocalRef<jobject>::Adopt(env, member);
  225. env->SetObjectArrayElement(array_.obj(), i, member);
  226. }
  227. }
  228. // Make an Integer[] with len elements, all initialized to null.
  229. ScopedJavaLocalRef<jobjectArray> MakeArray(jsize len) {
  230. JNIEnv* env = AttachCurrentThread();
  231. jobjectArray array = env->NewObjectArray(len, int_class_.obj(), nullptr);
  232. EXPECT_NE(array, nullptr);
  233. return ScopedJavaLocalRef<jobjectArray>::Adopt(env, array);
  234. }
  235. static constexpr jsize array_len_ = 10;
  236. ScopedJavaLocalRef<jclass> int_class_;
  237. jmethodID int_constructor_;
  238. ScopedJavaLocalRef<jobject> array_members_[array_len_];
  239. ScopedJavaLocalRef<jobjectArray> array_;
  240. };
  241. // Must actually define the variable until C++17 :(
  242. constexpr jsize JavaObjectArrayReaderTest::array_len_;
  243. TEST_F(JavaObjectArrayReaderTest, ZeroLengthArray) {
  244. JavaObjectArrayReader<jobject> zero_length(MakeArray(0));
  245. EXPECT_TRUE(zero_length.empty());
  246. EXPECT_EQ(zero_length.size(), 0);
  247. EXPECT_EQ(zero_length.begin(), zero_length.end());
  248. }
  249. // Verify that we satisfy the C++ "InputIterator" named requirements.
  250. TEST_F(JavaObjectArrayReaderTest, InputIteratorRequirements) {
  251. typedef JavaObjectArrayReader<jobject>::iterator It;
  252. JNIEnv* env = AttachCurrentThread();
  253. JavaObjectArrayReader<jobject> reader(array_);
  254. It i = reader.begin();
  255. EXPECT_TRUE(std::is_copy_constructible<It>::value);
  256. It copy = i;
  257. EXPECT_EQ(copy, i);
  258. EXPECT_EQ(It(i), i);
  259. EXPECT_TRUE(std::is_copy_assignable<It>::value);
  260. It assign = reader.end();
  261. It& assign2 = (assign = i);
  262. EXPECT_EQ(assign, i);
  263. EXPECT_EQ(assign2, assign);
  264. EXPECT_TRUE(std::is_destructible<It>::value);
  265. // Swappable
  266. It left = reader.begin(), right = reader.end();
  267. std::swap(left, right);
  268. EXPECT_EQ(left, reader.end());
  269. EXPECT_EQ(right, reader.begin());
  270. // Basic check that iterator_traits works
  271. bool same_type = std::is_same<std::iterator_traits<It>::iterator_category,
  272. std::input_iterator_tag>::value;
  273. EXPECT_TRUE(same_type);
  274. // Comparisons
  275. EXPECT_EQ(reader.begin(), reader.begin());
  276. EXPECT_NE(reader.begin(), reader.end());
  277. // Dereferencing
  278. ScopedJavaLocalRef<jobject> o = *(reader.begin());
  279. EXPECT_SAME_OBJECT(o, array_members_[0]);
  280. EXPECT_TRUE(env->IsSameObject(o.obj(), reader.begin()->obj()));
  281. // Incrementing
  282. It preinc = ++(reader.begin());
  283. EXPECT_SAME_OBJECT(*preinc, array_members_[1]);
  284. It postinc = reader.begin();
  285. EXPECT_SAME_OBJECT(*postinc++, array_members_[0]);
  286. EXPECT_SAME_OBJECT(*postinc, array_members_[1]);
  287. }
  288. // Check that range-based for and the convenience function work as expected.
  289. TEST_F(JavaObjectArrayReaderTest, RangeBasedFor) {
  290. JNIEnv* env = AttachCurrentThread();
  291. int i = 0;
  292. for (ScopedJavaLocalRef<jobject> element : array_.ReadElements<jobject>()) {
  293. EXPECT_SAME_OBJECT(element, array_members_[i++]);
  294. }
  295. EXPECT_EQ(i, array_len_);
  296. }
  297. } // namespace android
  298. } // namespace base