Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / android / java / gin_java_method_invocation_helper_unittest.cc
blobfcda3cda9345ef6930a571119a4305713c4ffc8f
1 // Copyright 2014 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.
5 #include "content/browser/android/java/gin_java_method_invocation_helper.h"
7 #include "base/android/jni_android.h"
8 #include "content/browser/android/java/jni_helper.h"
9 #include "content/common/android/gin_java_bridge_value.h"
10 #include "testing/gtest/include/gtest/gtest.h"
12 namespace content {
14 namespace {
16 class NullObjectDelegate
17 : public GinJavaMethodInvocationHelper::ObjectDelegate {
18 public:
19 NullObjectDelegate() {}
21 ~NullObjectDelegate() override {}
23 base::android::ScopedJavaLocalRef<jobject> GetLocalRef(JNIEnv* env) override {
24 return base::android::ScopedJavaLocalRef<jobject>();
27 base::android::ScopedJavaLocalRef<jclass> GetLocalClassRef(
28 JNIEnv* env) override {
29 return base::android::ScopedJavaLocalRef<jclass>();
32 const JavaMethod* FindMethod(const std::string& method_name,
33 size_t num_parameters) override {
34 return NULL;
37 bool IsObjectGetClassMethod(const JavaMethod* method) override {
38 return false;
41 const base::android::JavaRef<jclass>& GetSafeAnnotationClass() override {
42 return safe_annotation_class_;
45 private:
46 base::android::ScopedJavaLocalRef<jclass> safe_annotation_class_;
48 DISALLOW_COPY_AND_ASSIGN(NullObjectDelegate);
51 class NullDispatcherDelegate
52 : public GinJavaMethodInvocationHelper::DispatcherDelegate {
53 public:
54 NullDispatcherDelegate() {}
56 ~NullDispatcherDelegate() override {}
58 JavaObjectWeakGlobalRef GetObjectWeakRef(
59 GinJavaBoundObject::ObjectID object_id) override {
60 return JavaObjectWeakGlobalRef();
63 DISALLOW_COPY_AND_ASSIGN(NullDispatcherDelegate);
66 } // namespace
68 class GinJavaMethodInvocationHelperTest : public testing::Test {
71 namespace {
73 class CountingDispatcherDelegate
74 : public GinJavaMethodInvocationHelper::DispatcherDelegate {
75 public:
76 CountingDispatcherDelegate() {}
78 ~CountingDispatcherDelegate() override {}
80 JavaObjectWeakGlobalRef GetObjectWeakRef(
81 GinJavaBoundObject::ObjectID object_id) override {
82 counters_[object_id]++;
83 return JavaObjectWeakGlobalRef();
86 void AssertInvocationsCount(GinJavaBoundObject::ObjectID begin_object_id,
87 GinJavaBoundObject::ObjectID end_object_id) {
88 EXPECT_EQ(end_object_id - begin_object_id,
89 static_cast<int>(counters_.size()));
90 for (GinJavaBoundObject::ObjectID i = begin_object_id;
91 i < end_object_id; ++i) {
92 EXPECT_LT(0, counters_[i]) << "ObjectID: " << i;
96 private:
97 typedef std::map<GinJavaBoundObject::ObjectID, int> Counters;
98 Counters counters_;
100 DISALLOW_COPY_AND_ASSIGN(CountingDispatcherDelegate);
103 } // namespace
105 TEST_F(GinJavaMethodInvocationHelperTest, RetrievalOfObjectsNoObjects) {
106 base::ListValue no_objects;
107 for (int i = 0; i < 10; ++i) {
108 no_objects.AppendInteger(i);
111 scoped_refptr<GinJavaMethodInvocationHelper> helper =
112 new GinJavaMethodInvocationHelper(
113 scoped_ptr<GinJavaMethodInvocationHelper::ObjectDelegate>(
114 new NullObjectDelegate()),
115 "foo",
116 no_objects);
117 CountingDispatcherDelegate counter;
118 helper->Init(&counter);
119 counter.AssertInvocationsCount(0, 0);
122 TEST_F(GinJavaMethodInvocationHelperTest, RetrievalOfObjectsHaveObjects) {
123 base::ListValue objects;
124 objects.AppendInteger(100);
125 objects.Append(GinJavaBridgeValue::CreateObjectIDValue(1).release());
126 base::ListValue* sub_list = new base::ListValue();
127 sub_list->AppendInteger(200);
128 sub_list->Append(GinJavaBridgeValue::CreateObjectIDValue(2).release());
129 objects.Append(sub_list);
130 base::DictionaryValue* sub_dict = new base::DictionaryValue();
131 sub_dict->SetInteger("1", 300);
132 sub_dict->Set("2", GinJavaBridgeValue::CreateObjectIDValue(3).release());
133 objects.Append(sub_dict);
134 base::ListValue* sub_list_with_dict = new base::ListValue();
135 base::DictionaryValue* sub_sub_dict = new base::DictionaryValue();
136 sub_sub_dict->Set("1", GinJavaBridgeValue::CreateObjectIDValue(4).release());
137 sub_list_with_dict->Append(sub_sub_dict);
138 objects.Append(sub_list_with_dict);
139 base::DictionaryValue* sub_dict_with_list = new base::DictionaryValue();
140 base::ListValue* sub_sub_list = new base::ListValue();
141 sub_sub_list->Append(GinJavaBridgeValue::CreateObjectIDValue(5).release());
142 sub_dict_with_list->Set("1", sub_sub_list);
143 objects.Append(sub_dict_with_list);
145 scoped_refptr<GinJavaMethodInvocationHelper> helper =
146 new GinJavaMethodInvocationHelper(
147 scoped_ptr<GinJavaMethodInvocationHelper::ObjectDelegate>(
148 new NullObjectDelegate()),
149 "foo",
150 objects);
151 CountingDispatcherDelegate counter;
152 helper->Init(&counter);
153 counter.AssertInvocationsCount(1, 6);
156 namespace {
158 class ObjectIsGoneObjectDelegate : public NullObjectDelegate {
159 public:
160 ObjectIsGoneObjectDelegate() :
161 get_local_ref_called_(false) {
162 // We need a Java Method object to create a valid JavaMethod instance.
163 JNIEnv* env = base::android::AttachCurrentThread();
164 jmethodID method_id =
165 GetMethodIDFromClassName(env, "java/lang/Object", "hashCode", "()I");
166 EXPECT_TRUE(method_id);
167 base::android::ScopedJavaLocalRef<jobject> method_obj(
168 env,
169 env->ToReflectedMethod(
170 base::android::GetClass(env, "java/lang/Object").obj(),
171 method_id,
172 false));
173 EXPECT_TRUE(method_obj.obj());
174 method_.reset(new JavaMethod(method_obj));
177 ~ObjectIsGoneObjectDelegate() override {}
179 base::android::ScopedJavaLocalRef<jobject> GetLocalRef(JNIEnv* env) override {
180 get_local_ref_called_ = true;
181 return NullObjectDelegate::GetLocalRef(env);
184 const JavaMethod* FindMethod(const std::string& method_name,
185 size_t num_parameters) override {
186 return method_.get();
189 bool get_local_ref_called() { return get_local_ref_called_; }
191 const std::string& get_method_name() { return method_->name(); }
193 protected:
194 scoped_ptr<JavaMethod> method_;
195 bool get_local_ref_called_;
197 private:
198 DISALLOW_COPY_AND_ASSIGN(ObjectIsGoneObjectDelegate);
201 } // namespace
203 TEST_F(GinJavaMethodInvocationHelperTest, HandleObjectIsGone) {
204 base::ListValue no_objects;
205 ObjectIsGoneObjectDelegate* object_delegate =
206 new ObjectIsGoneObjectDelegate();
207 scoped_refptr<GinJavaMethodInvocationHelper> helper =
208 new GinJavaMethodInvocationHelper(
209 scoped_ptr<GinJavaMethodInvocationHelper::ObjectDelegate>(
210 object_delegate),
211 object_delegate->get_method_name(),
212 no_objects);
213 NullDispatcherDelegate dispatcher;
214 helper->Init(&dispatcher);
215 EXPECT_FALSE(object_delegate->get_local_ref_called());
216 EXPECT_EQ(kGinJavaBridgeNoError, helper->GetInvocationError());
217 helper->Invoke();
218 EXPECT_TRUE(object_delegate->get_local_ref_called());
219 EXPECT_TRUE(helper->HoldsPrimitiveResult());
220 EXPECT_TRUE(helper->GetPrimitiveResult().empty());
221 EXPECT_EQ(kGinJavaBridgeObjectIsGone, helper->GetInvocationError());
224 namespace {
226 class MethodNotFoundObjectDelegate : public NullObjectDelegate {
227 public:
228 MethodNotFoundObjectDelegate() : find_method_called_(false) {}
230 ~MethodNotFoundObjectDelegate() override {}
232 base::android::ScopedJavaLocalRef<jobject> GetLocalRef(JNIEnv* env) override {
233 return base::android::ScopedJavaLocalRef<jobject>(
234 env, static_cast<jobject>(env->FindClass("java/lang/String")));
237 const JavaMethod* FindMethod(const std::string& method_name,
238 size_t num_parameters) override {
239 find_method_called_ = true;
240 return NULL;
243 bool find_method_called() const { return find_method_called_; }
245 protected:
246 bool find_method_called_;
248 private:
249 DISALLOW_COPY_AND_ASSIGN(MethodNotFoundObjectDelegate);
252 } // namespace
254 TEST_F(GinJavaMethodInvocationHelperTest, HandleMethodNotFound) {
255 base::ListValue no_objects;
256 MethodNotFoundObjectDelegate* object_delegate =
257 new MethodNotFoundObjectDelegate();
258 scoped_refptr<GinJavaMethodInvocationHelper> helper =
259 new GinJavaMethodInvocationHelper(
260 scoped_ptr<GinJavaMethodInvocationHelper::ObjectDelegate>(
261 object_delegate),
262 "foo",
263 no_objects);
264 NullDispatcherDelegate dispatcher;
265 helper->Init(&dispatcher);
266 EXPECT_FALSE(object_delegate->find_method_called());
267 EXPECT_EQ(kGinJavaBridgeNoError, helper->GetInvocationError());
268 helper->Invoke();
269 EXPECT_TRUE(object_delegate->find_method_called());
270 EXPECT_TRUE(helper->HoldsPrimitiveResult());
271 EXPECT_TRUE(helper->GetPrimitiveResult().empty());
272 EXPECT_EQ(kGinJavaBridgeMethodNotFound, helper->GetInvocationError());
275 namespace {
277 class GetClassObjectDelegate : public MethodNotFoundObjectDelegate {
278 public:
279 GetClassObjectDelegate() : get_class_called_(false) {}
281 ~GetClassObjectDelegate() override {}
283 const JavaMethod* FindMethod(const std::string& method_name,
284 size_t num_parameters) override {
285 find_method_called_ = true;
286 return kFakeGetClass;
289 bool IsObjectGetClassMethod(const JavaMethod* method) override {
290 get_class_called_ = true;
291 return kFakeGetClass == method;
294 bool get_class_called() const { return get_class_called_; }
296 private:
297 static const JavaMethod* kFakeGetClass;
298 bool get_class_called_;
300 DISALLOW_COPY_AND_ASSIGN(GetClassObjectDelegate);
303 // We don't expect GinJavaMethodInvocationHelper to actually invoke the
304 // method, since the point of the test is to verify whether calls to
305 // 'getClass' get blocked.
306 const JavaMethod* GetClassObjectDelegate::kFakeGetClass =
307 (JavaMethod*)0xdeadbeef;
309 } // namespace
311 TEST_F(GinJavaMethodInvocationHelperTest, HandleGetClassInvocation) {
312 base::ListValue no_objects;
313 GetClassObjectDelegate* object_delegate =
314 new GetClassObjectDelegate();
315 scoped_refptr<GinJavaMethodInvocationHelper> helper =
316 new GinJavaMethodInvocationHelper(
317 scoped_ptr<GinJavaMethodInvocationHelper::ObjectDelegate>(
318 object_delegate),
319 "foo",
320 no_objects);
321 NullDispatcherDelegate dispatcher;
322 helper->Init(&dispatcher);
323 EXPECT_FALSE(object_delegate->find_method_called());
324 EXPECT_FALSE(object_delegate->get_class_called());
325 EXPECT_EQ(kGinJavaBridgeNoError, helper->GetInvocationError());
326 helper->Invoke();
327 EXPECT_TRUE(object_delegate->find_method_called());
328 EXPECT_TRUE(object_delegate->get_class_called());
329 EXPECT_TRUE(helper->HoldsPrimitiveResult());
330 EXPECT_TRUE(helper->GetPrimitiveResult().empty());
331 EXPECT_EQ(kGinJavaBridgeAccessToObjectGetClassIsBlocked,
332 helper->GetInvocationError());
335 } // namespace content