OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "content/browser/renderer_host/java/gin_java_method_invocation_helper.h
" | |
6 | |
7 #include "base/android/jni_android.h" | |
8 #include "content/browser/renderer_host/java/jni_helper.h" | |
9 #include "content/common/android/gin_java_bridge_value.h" | |
10 #include "testing/gtest/include/gtest/gtest.h" | |
11 | |
12 namespace content { | |
13 | |
14 namespace { | |
15 | |
16 class NullObjectDelegate | |
17 : public GinJavaMethodInvocationHelper::ObjectDelegate { | |
18 public: | |
19 NullObjectDelegate() {} | |
20 | |
21 virtual ~NullObjectDelegate() {} | |
22 | |
23 virtual base::android::ScopedJavaLocalRef<jobject> GetLocalRef( | |
24 JNIEnv* env) OVERRIDE { | |
25 return base::android::ScopedJavaLocalRef<jobject>(); | |
26 } | |
27 | |
28 virtual base::android::ScopedJavaLocalRef<jclass> GetLocalClassRef( | |
29 JNIEnv* env) OVERRIDE { | |
30 return base::android::ScopedJavaLocalRef<jclass>(); | |
31 } | |
32 | |
33 virtual const JavaMethod* FindMethod(const std::string& method_name, | |
34 size_t num_parameters) OVERRIDE { | |
35 return NULL; | |
36 } | |
37 | |
38 virtual bool IsObjectGetClassMethod(const JavaMethod* method) OVERRIDE { | |
39 return false; | |
40 } | |
41 | |
42 virtual const base::android::JavaRef<jclass>& GetSafeAnnotationClass() | |
43 OVERRIDE { | |
44 return safe_annotation_class_; | |
45 } | |
46 | |
47 private: | |
48 base::android::ScopedJavaLocalRef<jclass> safe_annotation_class_; | |
49 | |
50 DISALLOW_COPY_AND_ASSIGN(NullObjectDelegate); | |
51 }; | |
52 | |
53 class NullDispatcherDelegate | |
54 : public GinJavaMethodInvocationHelper::DispatcherDelegate { | |
55 public: | |
56 NullDispatcherDelegate() {} | |
57 | |
58 virtual ~NullDispatcherDelegate() {} | |
59 | |
60 virtual JavaObjectWeakGlobalRef GetObjectWeakRef( | |
61 GinJavaBoundObject::ObjectID object_id) OVERRIDE { | |
62 return JavaObjectWeakGlobalRef(); | |
63 } | |
64 | |
65 DISALLOW_COPY_AND_ASSIGN(NullDispatcherDelegate); | |
66 }; | |
67 | |
68 } // namespace | |
69 | |
70 class GinJavaMethodInvocationHelperTest : public testing::Test { | |
71 }; | |
72 | |
73 namespace { | |
74 | |
75 class CountingDispatcherDelegate | |
76 : public GinJavaMethodInvocationHelper::DispatcherDelegate { | |
77 public: | |
78 CountingDispatcherDelegate() {} | |
79 | |
80 virtual ~CountingDispatcherDelegate() {} | |
81 | |
82 virtual JavaObjectWeakGlobalRef GetObjectWeakRef( | |
83 GinJavaBoundObject::ObjectID object_id) OVERRIDE { | |
84 counters_[object_id]++; | |
85 return JavaObjectWeakGlobalRef(); | |
86 } | |
87 | |
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; | |
95 } | |
96 } | |
97 | |
98 private: | |
99 typedef std::map<GinJavaBoundObject::ObjectID, int> Counters; | |
100 Counters counters_; | |
101 | |
102 DISALLOW_COPY_AND_ASSIGN(CountingDispatcherDelegate); | |
103 }; | |
104 | |
105 } // namespace | |
106 | |
107 TEST_F(GinJavaMethodInvocationHelperTest, RetrievalOfObjectsNoObjects) { | |
108 base::ListValue no_objects; | |
109 for (int i = 0; i < 10; ++i) { | |
110 no_objects.AppendInteger(i); | |
111 } | |
112 | |
113 scoped_refptr<GinJavaMethodInvocationHelper> helper = | |
114 new GinJavaMethodInvocationHelper( | |
115 scoped_ptr<GinJavaMethodInvocationHelper::ObjectDelegate>( | |
116 new NullObjectDelegate()), | |
117 "foo", | |
118 no_objects); | |
119 CountingDispatcherDelegate counter; | |
120 helper->Init(&counter); | |
121 counter.AssertInvocationsCount(0, 0); | |
122 } | |
123 | |
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); | |
146 | |
147 scoped_refptr<GinJavaMethodInvocationHelper> helper = | |
148 new GinJavaMethodInvocationHelper( | |
149 scoped_ptr<GinJavaMethodInvocationHelper::ObjectDelegate>( | |
150 new NullObjectDelegate()), | |
151 "foo", | |
152 objects); | |
153 CountingDispatcherDelegate counter; | |
154 helper->Init(&counter); | |
155 counter.AssertInvocationsCount(1, 6); | |
156 } | |
157 | |
158 namespace { | |
159 | |
160 class ObjectIsGoneObjectDelegate : public NullObjectDelegate { | |
161 public: | |
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( | |
170 env, | |
171 env->ToReflectedMethod( | |
172 base::android::GetClass(env, "java/lang/Object").obj(), | |
173 method_id, | |
174 false)); | |
175 EXPECT_TRUE(method_obj.obj()); | |
176 method_.reset(new JavaMethod(method_obj)); | |
177 } | |
178 | |
179 virtual ~ObjectIsGoneObjectDelegate() {} | |
180 | |
181 virtual base::android::ScopedJavaLocalRef<jobject> GetLocalRef( | |
182 JNIEnv* env) OVERRIDE { | |
183 get_local_ref_called_ = true; | |
184 return NullObjectDelegate::GetLocalRef(env); | |
185 } | |
186 | |
187 virtual const JavaMethod* FindMethod(const std::string& method_name, | |
188 size_t num_parameters) OVERRIDE { | |
189 return method_.get(); | |
190 } | |
191 | |
192 bool get_local_ref_called() { return get_local_ref_called_; } | |
193 | |
194 const std::string& get_method_name() { return method_->name(); } | |
195 | |
196 protected: | |
197 scoped_ptr<JavaMethod> method_; | |
198 bool get_local_ref_called_; | |
199 | |
200 private: | |
201 DISALLOW_COPY_AND_ASSIGN(ObjectIsGoneObjectDelegate); | |
202 }; | |
203 | |
204 } // namespace | |
205 | |
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>( | |
213 object_delegate), | |
214 object_delegate->get_method_name(), | |
215 no_objects); | |
216 NullDispatcherDelegate dispatcher; | |
217 helper->Init(&dispatcher); | |
218 EXPECT_FALSE(object_delegate->get_local_ref_called()); | |
219 EXPECT_EQ(kGinJavaBridgeNoError, helper->GetInvocationError()); | |
220 helper->Invoke(); | |
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()); | |
225 } | |
226 | |
227 namespace { | |
228 | |
229 class MethodNotFoundObjectDelegate : public NullObjectDelegate { | |
230 public: | |
231 MethodNotFoundObjectDelegate() : find_method_called_(false) {} | |
232 | |
233 virtual ~MethodNotFoundObjectDelegate() {} | |
234 | |
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"))); | |
239 } | |
240 | |
241 virtual const JavaMethod* FindMethod(const std::string& method_name, | |
242 size_t num_parameters) OVERRIDE { | |
243 find_method_called_ = true; | |
244 return NULL; | |
245 } | |
246 | |
247 bool find_method_called() const { return find_method_called_; } | |
248 | |
249 protected: | |
250 bool find_method_called_; | |
251 | |
252 private: | |
253 DISALLOW_COPY_AND_ASSIGN(MethodNotFoundObjectDelegate); | |
254 }; | |
255 | |
256 } // namespace | |
257 | |
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>( | |
265 object_delegate), | |
266 "foo", | |
267 no_objects); | |
268 NullDispatcherDelegate dispatcher; | |
269 helper->Init(&dispatcher); | |
270 EXPECT_FALSE(object_delegate->find_method_called()); | |
271 EXPECT_EQ(kGinJavaBridgeNoError, helper->GetInvocationError()); | |
272 helper->Invoke(); | |
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()); | |
277 } | |
278 | |
279 namespace { | |
280 | |
281 class GetClassObjectDelegate : public MethodNotFoundObjectDelegate { | |
282 public: | |
283 GetClassObjectDelegate() : get_class_called_(false) {} | |
284 | |
285 virtual ~GetClassObjectDelegate() {} | |
286 | |
287 virtual const JavaMethod* FindMethod(const std::string& method_name, | |
288 size_t num_parameters) OVERRIDE { | |
289 find_method_called_ = true; | |
290 return kFakeGetClass; | |
291 } | |
292 | |
293 virtual bool IsObjectGetClassMethod(const JavaMethod* method) OVERRIDE { | |
294 get_class_called_ = true; | |
295 return kFakeGetClass == method; | |
296 } | |
297 | |
298 bool get_class_called() const { return get_class_called_; } | |
299 | |
300 private: | |
301 static const JavaMethod* kFakeGetClass; | |
302 bool get_class_called_; | |
303 | |
304 DISALLOW_COPY_AND_ASSIGN(GetClassObjectDelegate); | |
305 }; | |
306 | |
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; | |
312 | |
313 } // namespace | |
314 | |
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>( | |
322 object_delegate), | |
323 "foo", | |
324 no_objects); | |
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()); | |
330 helper->Invoke(); | |
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()); | |
337 } | |
338 | |
339 } // namespace content | |
OLD | NEW |