Home | History | Annotate | Download | only in java
      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/android/java/gin_java_method_invocation_helper.h"
      6 
      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"
     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
    340