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"
16 class NullObjectDelegate
17 : public GinJavaMethodInvocationHelper::ObjectDelegate
{
19 NullObjectDelegate() {}
21 virtual ~NullObjectDelegate() {}
23 virtual base::android::ScopedJavaLocalRef
<jobject
> GetLocalRef(
24 JNIEnv
* env
) OVERRIDE
{
25 return base::android::ScopedJavaLocalRef
<jobject
>();
28 virtual base::android::ScopedJavaLocalRef
<jclass
> GetLocalClassRef(
29 JNIEnv
* env
) OVERRIDE
{
30 return base::android::ScopedJavaLocalRef
<jclass
>();
33 virtual const JavaMethod
* FindMethod(const std::string
& method_name
,
34 size_t num_parameters
) OVERRIDE
{
38 virtual bool IsObjectGetClassMethod(const JavaMethod
* method
) OVERRIDE
{
42 virtual const base::android::JavaRef
<jclass
>& GetSafeAnnotationClass()
44 return safe_annotation_class_
;
48 base::android::ScopedJavaLocalRef
<jclass
> safe_annotation_class_
;
50 DISALLOW_COPY_AND_ASSIGN(NullObjectDelegate
);
53 class NullDispatcherDelegate
54 : public GinJavaMethodInvocationHelper::DispatcherDelegate
{
56 NullDispatcherDelegate() {}
58 virtual ~NullDispatcherDelegate() {}
60 virtual JavaObjectWeakGlobalRef
GetObjectWeakRef(
61 GinJavaBoundObject::ObjectID object_id
) OVERRIDE
{
62 return JavaObjectWeakGlobalRef();
65 DISALLOW_COPY_AND_ASSIGN(NullDispatcherDelegate
);
70 class GinJavaMethodInvocationHelperTest
: public testing::Test
{
75 class CountingDispatcherDelegate
76 : public GinJavaMethodInvocationHelper::DispatcherDelegate
{
78 CountingDispatcherDelegate() {}
80 virtual ~CountingDispatcherDelegate() {}
82 virtual JavaObjectWeakGlobalRef
GetObjectWeakRef(
83 GinJavaBoundObject::ObjectID object_id
) OVERRIDE
{
84 counters_
[object_id
]++;
85 return JavaObjectWeakGlobalRef();
88 void AssertInvocationsCount(GinJavaBoundObject::ObjectID begin_object_id
,
89 GinJavaBoundObject::ObjectID end_object_id
) {
90 EXPECT_EQ(end_object_id
- begin_object_id
,
91 static_cast<int>(counters_
.size()));
92 for (GinJavaBoundObject::ObjectID i
= begin_object_id
;
93 i
< end_object_id
; ++i
) {
94 EXPECT_LT(0, counters_
[i
]) << "ObjectID: " << i
;
99 typedef std::map
<GinJavaBoundObject::ObjectID
, int> Counters
;
102 DISALLOW_COPY_AND_ASSIGN(CountingDispatcherDelegate
);
107 TEST_F(GinJavaMethodInvocationHelperTest
, RetrievalOfObjectsNoObjects
) {
108 base::ListValue no_objects
;
109 for (int i
= 0; i
< 10; ++i
) {
110 no_objects
.AppendInteger(i
);
113 scoped_refptr
<GinJavaMethodInvocationHelper
> helper
=
114 new GinJavaMethodInvocationHelper(
115 scoped_ptr
<GinJavaMethodInvocationHelper::ObjectDelegate
>(
116 new NullObjectDelegate()),
119 CountingDispatcherDelegate counter
;
120 helper
->Init(&counter
);
121 counter
.AssertInvocationsCount(0, 0);
124 TEST_F(GinJavaMethodInvocationHelperTest
, RetrievalOfObjectsHaveObjects
) {
125 base::ListValue objects
;
126 objects
.AppendInteger(100);
127 objects
.Append(GinJavaBridgeValue::CreateObjectIDValue(1).release());
128 base::ListValue
* sub_list
= new base::ListValue();
129 sub_list
->AppendInteger(200);
130 sub_list
->Append(GinJavaBridgeValue::CreateObjectIDValue(2).release());
131 objects
.Append(sub_list
);
132 base::DictionaryValue
* sub_dict
= new base::DictionaryValue();
133 sub_dict
->SetInteger("1", 300);
134 sub_dict
->Set("2", GinJavaBridgeValue::CreateObjectIDValue(3).release());
135 objects
.Append(sub_dict
);
136 base::ListValue
* sub_list_with_dict
= new base::ListValue();
137 base::DictionaryValue
* sub_sub_dict
= new base::DictionaryValue();
138 sub_sub_dict
->Set("1", GinJavaBridgeValue::CreateObjectIDValue(4).release());
139 sub_list_with_dict
->Append(sub_sub_dict
);
140 objects
.Append(sub_list_with_dict
);
141 base::DictionaryValue
* sub_dict_with_list
= new base::DictionaryValue();
142 base::ListValue
* sub_sub_list
= new base::ListValue();
143 sub_sub_list
->Append(GinJavaBridgeValue::CreateObjectIDValue(5).release());
144 sub_dict_with_list
->Set("1", sub_sub_list
);
145 objects
.Append(sub_dict_with_list
);
147 scoped_refptr
<GinJavaMethodInvocationHelper
> helper
=
148 new GinJavaMethodInvocationHelper(
149 scoped_ptr
<GinJavaMethodInvocationHelper::ObjectDelegate
>(
150 new NullObjectDelegate()),
153 CountingDispatcherDelegate counter
;
154 helper
->Init(&counter
);
155 counter
.AssertInvocationsCount(1, 6);
160 class ObjectIsGoneObjectDelegate
: public NullObjectDelegate
{
162 ObjectIsGoneObjectDelegate() :
163 get_local_ref_called_(false) {
164 // We need a Java Method object to create a valid JavaMethod instance.
165 JNIEnv
* env
= base::android::AttachCurrentThread();
166 jmethodID method_id
=
167 GetMethodIDFromClassName(env
, "java/lang/Object", "hashCode", "()I");
168 EXPECT_TRUE(method_id
);
169 base::android::ScopedJavaLocalRef
<jobject
> method_obj(
171 env
->ToReflectedMethod(
172 base::android::GetClass(env
, "java/lang/Object").obj(),
175 EXPECT_TRUE(method_obj
.obj());
176 method_
.reset(new JavaMethod(method_obj
));
179 virtual ~ObjectIsGoneObjectDelegate() {}
181 virtual base::android::ScopedJavaLocalRef
<jobject
> GetLocalRef(
182 JNIEnv
* env
) OVERRIDE
{
183 get_local_ref_called_
= true;
184 return NullObjectDelegate::GetLocalRef(env
);
187 virtual const JavaMethod
* FindMethod(const std::string
& method_name
,
188 size_t num_parameters
) OVERRIDE
{
189 return method_
.get();
192 bool get_local_ref_called() { return get_local_ref_called_
; }
194 const std::string
& get_method_name() { return method_
->name(); }
197 scoped_ptr
<JavaMethod
> method_
;
198 bool get_local_ref_called_
;
201 DISALLOW_COPY_AND_ASSIGN(ObjectIsGoneObjectDelegate
);
206 TEST_F(GinJavaMethodInvocationHelperTest
, HandleObjectIsGone
) {
207 base::ListValue no_objects
;
208 ObjectIsGoneObjectDelegate
* object_delegate
=
209 new ObjectIsGoneObjectDelegate();
210 scoped_refptr
<GinJavaMethodInvocationHelper
> helper
=
211 new GinJavaMethodInvocationHelper(
212 scoped_ptr
<GinJavaMethodInvocationHelper::ObjectDelegate
>(
214 object_delegate
->get_method_name(),
216 NullDispatcherDelegate dispatcher
;
217 helper
->Init(&dispatcher
);
218 EXPECT_FALSE(object_delegate
->get_local_ref_called());
219 EXPECT_EQ(kGinJavaBridgeNoError
, helper
->GetInvocationError());
221 EXPECT_TRUE(object_delegate
->get_local_ref_called());
222 EXPECT_TRUE(helper
->HoldsPrimitiveResult());
223 EXPECT_TRUE(helper
->GetPrimitiveResult().empty());
224 EXPECT_EQ(kGinJavaBridgeObjectIsGone
, helper
->GetInvocationError());
229 class MethodNotFoundObjectDelegate
: public NullObjectDelegate
{
231 MethodNotFoundObjectDelegate() : find_method_called_(false) {}
233 virtual ~MethodNotFoundObjectDelegate() {}
235 virtual base::android::ScopedJavaLocalRef
<jobject
> GetLocalRef(
236 JNIEnv
* env
) OVERRIDE
{
237 return base::android::ScopedJavaLocalRef
<jobject
>(
238 env
, static_cast<jobject
>(env
->FindClass("java/lang/String")));
241 virtual const JavaMethod
* FindMethod(const std::string
& method_name
,
242 size_t num_parameters
) OVERRIDE
{
243 find_method_called_
= true;
247 bool find_method_called() const { return find_method_called_
; }
250 bool find_method_called_
;
253 DISALLOW_COPY_AND_ASSIGN(MethodNotFoundObjectDelegate
);
258 TEST_F(GinJavaMethodInvocationHelperTest
, HandleMethodNotFound
) {
259 base::ListValue no_objects
;
260 MethodNotFoundObjectDelegate
* object_delegate
=
261 new MethodNotFoundObjectDelegate();
262 scoped_refptr
<GinJavaMethodInvocationHelper
> helper
=
263 new GinJavaMethodInvocationHelper(
264 scoped_ptr
<GinJavaMethodInvocationHelper::ObjectDelegate
>(
268 NullDispatcherDelegate dispatcher
;
269 helper
->Init(&dispatcher
);
270 EXPECT_FALSE(object_delegate
->find_method_called());
271 EXPECT_EQ(kGinJavaBridgeNoError
, helper
->GetInvocationError());
273 EXPECT_TRUE(object_delegate
->find_method_called());
274 EXPECT_TRUE(helper
->HoldsPrimitiveResult());
275 EXPECT_TRUE(helper
->GetPrimitiveResult().empty());
276 EXPECT_EQ(kGinJavaBridgeMethodNotFound
, helper
->GetInvocationError());
281 class GetClassObjectDelegate
: public MethodNotFoundObjectDelegate
{
283 GetClassObjectDelegate() : get_class_called_(false) {}
285 virtual ~GetClassObjectDelegate() {}
287 virtual const JavaMethod
* FindMethod(const std::string
& method_name
,
288 size_t num_parameters
) OVERRIDE
{
289 find_method_called_
= true;
290 return kFakeGetClass
;
293 virtual bool IsObjectGetClassMethod(const JavaMethod
* method
) OVERRIDE
{
294 get_class_called_
= true;
295 return kFakeGetClass
== method
;
298 bool get_class_called() const { return get_class_called_
; }
301 static const JavaMethod
* kFakeGetClass
;
302 bool get_class_called_
;
304 DISALLOW_COPY_AND_ASSIGN(GetClassObjectDelegate
);
307 // We don't expect GinJavaMethodInvocationHelper to actually invoke the
308 // method, since the point of the test is to verify whether calls to
309 // 'getClass' get blocked.
310 const JavaMethod
* GetClassObjectDelegate::kFakeGetClass
=
311 (JavaMethod
*)0xdeadbeef;
315 TEST_F(GinJavaMethodInvocationHelperTest
, HandleGetClassInvocation
) {
316 base::ListValue no_objects
;
317 GetClassObjectDelegate
* object_delegate
=
318 new GetClassObjectDelegate();
319 scoped_refptr
<GinJavaMethodInvocationHelper
> helper
=
320 new GinJavaMethodInvocationHelper(
321 scoped_ptr
<GinJavaMethodInvocationHelper::ObjectDelegate
>(
325 NullDispatcherDelegate dispatcher
;
326 helper
->Init(&dispatcher
);
327 EXPECT_FALSE(object_delegate
->find_method_called());
328 EXPECT_FALSE(object_delegate
->get_class_called());
329 EXPECT_EQ(kGinJavaBridgeNoError
, helper
->GetInvocationError());
331 EXPECT_TRUE(object_delegate
->find_method_called());
332 EXPECT_TRUE(object_delegate
->get_class_called());
333 EXPECT_TRUE(helper
->HoldsPrimitiveResult());
334 EXPECT_TRUE(helper
->GetPrimitiveResult().empty());
335 EXPECT_EQ(kGinJavaBridgeAccessToObjectGetClassIsBlocked
,
336 helper
->GetInvocationError());
339 } // namespace content