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/jni_helper.h"
6
7#include "base/android/jni_android.h"
8#include "base/at_exit.h"
9#include "base/logging.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12namespace content {
13
14namespace {
15
16const char kJavaLangObject[] = "java/lang/Object";
17const char kGetClass[] = "getClass";
18const char kToString[] = "toString";
19const char kReturningJavaLangClass[] = "()Ljava/lang/Class;";
20const char kReturningJavaLangString[] = "()Ljava/lang/String;";
21
22const char* g_last_method;
23const char* g_last_jni_signature;
24jmethodID g_last_method_id;
25
26const JNINativeInterface* g_previous_functions;
27
28jmethodID GetMethodIDWrapper(JNIEnv* env, jclass clazz, const char* method,
29                             const char* jni_signature) {
30  g_last_method = method;
31  g_last_jni_signature = jni_signature;
32  g_last_method_id = g_previous_functions->GetMethodID(env, clazz, method,
33                                                       jni_signature);
34  return g_last_method_id;
35}
36
37}  // namespace
38
39class JNIAndroidTest : public testing::Test {
40 protected:
41  virtual void SetUp() {
42    JNIEnv* env = base::android::AttachCurrentThread();
43    g_previous_functions = env->functions;
44    hooked_functions = *g_previous_functions;
45    env->functions = &hooked_functions;
46    hooked_functions.GetMethodID = &GetMethodIDWrapper;
47  }
48
49  virtual void TearDown() {
50    JNIEnv* env = base::android::AttachCurrentThread();
51    env->functions = g_previous_functions;
52    Reset();
53  }
54
55  void Reset() {
56    g_last_method = 0;
57    g_last_jni_signature = 0;
58    g_last_method_id = NULL;
59  }
60  // Needed to cleanup the cached method map in the implementation between
61  // runs (e.g. if using --gtest_repeat)
62  base::ShadowingAtExitManager exit_manager;
63  // From JellyBean release, the instance of this struct provided in JNIEnv is
64  // read-only, so we deep copy it to allow individual functions to be hooked.
65  JNINativeInterface hooked_functions;
66};
67
68TEST_F(JNIAndroidTest, GetMethodIDFromClassNameCaching) {
69  JNIEnv* env = base::android::AttachCurrentThread();
70
71  Reset();
72  jmethodID id1 = GetMethodIDFromClassName(env, kJavaLangObject, kGetClass,
73                                           kReturningJavaLangClass);
74  EXPECT_STREQ(kGetClass, g_last_method);
75  EXPECT_STREQ(kReturningJavaLangClass, g_last_jni_signature);
76  EXPECT_EQ(g_last_method_id, id1);
77
78  Reset();
79  jmethodID id2 = GetMethodIDFromClassName(env, kJavaLangObject, kGetClass,
80                                           kReturningJavaLangClass);
81  EXPECT_STREQ(0, g_last_method);
82  EXPECT_STREQ(0, g_last_jni_signature);
83  EXPECT_EQ(NULL, g_last_method_id);
84  EXPECT_EQ(id1, id2);
85
86  Reset();
87  jmethodID id3 = GetMethodIDFromClassName(env, kJavaLangObject, kToString,
88                                           kReturningJavaLangString);
89  EXPECT_STREQ(kToString, g_last_method);
90  EXPECT_STREQ(kReturningJavaLangString, g_last_jni_signature);
91  EXPECT_EQ(g_last_method_id, id3);
92}
93
94}  // namespace content
95