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