| 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 |