1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "base/android_jni_mock.h"
31
32 #include "base/logging.h"
33
34 namespace mozc {
35 namespace jni {
36
MockJNIEnv()37 MockJNIEnv::MockJNIEnv() {
38 SetUpJNIEnv();
39 }
40
~MockJNIEnv()41 MockJNIEnv::~MockJNIEnv() {
42 ClearArrayMap();
43 TearDownJNIEnv();
44 }
45
46 // Setting up a JNIEnv instance.
SetUpJNIEnv()47 void MockJNIEnv::SetUpJNIEnv() {
48 JNINativeInterface *functions = new JNINativeInterface;
49 functions->reserved0 = this;
50 functions->FindClass = MockJNIEnv::FindClassProxy;
51 functions->GetStaticMethodID = MockJNIEnv::GetStaticMethodIDProxy;
52 functions->PushLocalFrame = MockJNIEnv::PushLocalFrameProxy;
53 functions->PopLocalFrame = MockJNIEnv::PopLocalFrameProxy;
54 functions->NewGlobalRef = MockJNIEnv::NewGlobalRefProxy;
55 functions->DeleteGlobalRef = MockJNIEnv::DeleteGlobalRefProxy;
56
57 functions->CallStaticObjectMethodV =
58 MockJNIEnv::CallStaticObjectMethodVProxy;
59 functions->ExceptionOccurred = MockJNIEnv::ExceptionOccurredProxy;
60
61 functions->NewByteArray = MockJNIEnv::NewByteArrayProxy;
62 functions->GetArrayLength = MockJNIEnv::GetArrayLengthProxy;
63 functions->GetByteArrayRegion = MockJNIEnv::GetByteArrayRegionProxy;
64 functions->SetByteArrayRegion = MockJNIEnv::SetByteArrayRegionProxy;
65
66 env_.functions = functions;
67 }
68
TearDownJNIEnv()69 void MockJNIEnv::TearDownJNIEnv() {
70 delete env_.functions;
71 }
72
ClearArrayMap()73 void MockJNIEnv::ClearArrayMap() {
74 for (std::map<jbyteArray, std::pair<jsize, jbyte*> >::iterator iter =
75 byte_array_map_.begin();
76 iter != byte_array_map_.end(); ++iter) {
77 delete iter->first;
78 delete [] iter->second.second;
79 }
80 byte_array_map_.clear();
81 }
82
FindClass(const char * class_path)83 jclass MockJNIEnv::FindClass(const char *class_path) {
84 static const char kHttpClientPath[] =
85 "org/mozc/android/inputmethod/japanese/nativecallback/HttpClient";
86 if (strcmp(class_path, kHttpClientPath) == 0) {
87 return &mock_http_client_class_;
88 }
89 return NULL;
90 }
91
GetStaticMethodID(jclass cls,const char * name,const char * signature)92 jmethodID MockJNIEnv::GetStaticMethodID(
93 jclass cls, const char *name, const char *signature) {
94 if (cls == &mock_http_client_class_) {
95 if (strcmp(name, "request") == 0 &&
96 strcmp(signature, "([B[B[B)[B") == 0) {
97 return reinterpret_cast<jmethodID>(&mock_request_);
98 }
99 return NULL;
100 }
101 return NULL;
102 }
103
CallStaticObjectMethodV(jclass cls,jmethodID method,va_list args)104 jobject MockJNIEnv::CallStaticObjectMethodV(
105 jclass cls, jmethodID method, va_list args) {
106 if (cls == &mock_http_client_class_) {
107 CHECK(mock_http_client_.get() != NULL)
108 << "mock_http_client_ is not initialized.";
109 if (method == reinterpret_cast<jmethodID>(&mock_request_)) {
110 jbyteArray method = va_arg(args, jbyteArray);
111 jbyteArray url = va_arg(args, jbyteArray);
112 jbyteArray post_data = va_arg(args, jbyteArray);
113 return mock_http_client_->Request(method, url, post_data);
114 }
115 LOG(FATAL) << "Unexpected call.";
116 return NULL;
117 }
118 LOG(FATAL) << "Unexpected call.";
119 return NULL;
120 }
121
122 // Utilities to manage jbyteArray instances.
NewByteArray(jsize size)123 jbyteArray MockJNIEnv::NewByteArray(jsize size) {
124 // Use non-public type _jbyteArray, which is the dereferenced type of
125 // jbyteArray. We can use the same technique as MockJMethodId if necessary,
126 // but this hack looks simpler.
127 jbyteArray result = new _jbyteArray;
128 jbyte *buf = new jbyte[size];
129 byte_array_map_[result] = std::make_pair(size, buf);
130 return result;
131 }
132
GetArrayLength(jarray array)133 jsize MockJNIEnv::GetArrayLength(jarray array) {
134 std::map<jbyteArray, std::pair<jsize, jbyte*> >::iterator iter =
135 byte_array_map_.find(static_cast<jbyteArray>(array));
136 if (iter != byte_array_map_.end()) {
137 return iter->second.first;
138 }
139 return 0;
140 }
141
GetByteArrayElements(jbyteArray array,jboolean * is_copy)142 jbyte *MockJNIEnv::GetByteArrayElements(jbyteArray array, jboolean *is_copy) {
143 std::map<jbyteArray, std::pair<jsize, jbyte*> >::iterator iter =
144 byte_array_map_.find(array);
145 if (iter != byte_array_map_.end()) {
146 if (is_copy) {
147 *is_copy = JNI_FALSE;
148 }
149 return iter->second.second;
150 }
151 return NULL;
152 }
GetByteArrayRegion(jbyteArray array,jsize start,jsize len,jbyte * buf)153 void MockJNIEnv::GetByteArrayRegion(
154 jbyteArray array, jsize start, jsize len, jbyte *buf) {
155 const jsize size = GetArrayLength(array);
156 CHECK(start <= size);
157 CHECK(start + len <= size);
158 memcpy(buf, GetByteArrayElements(array, NULL) + start, len);
159 }
160
SetByteArrayRegion(jbyteArray array,jsize start,jsize len,const jbyte * buf)161 void MockJNIEnv::SetByteArrayRegion(
162 jbyteArray array, jsize start, jsize len, const jbyte *buf) {
163 const jsize size = GetArrayLength(array);
164 CHECK(start <= size);
165 CHECK(start + len <= size);
166 memcpy(GetByteArrayElements(array, NULL) + start, buf, len);
167 }
168
JByteArrayToString(jbyteArray array)169 string MockJNIEnv::JByteArrayToString(jbyteArray array) {
170 jboolean is_copy;
171 jbyte *buffer = GetByteArrayElements(array, &is_copy);
172 CHECK(!is_copy);
173 return string(reinterpret_cast<char*>(buffer), GetArrayLength(array));
174 }
175
StringToJByteArray(const string & str)176 jbyteArray MockJNIEnv::StringToJByteArray(const string &str) {
177 jbyteArray result = NewByteArray(str.size());
178 jboolean is_copy;
179 jbyte *buffer = GetByteArrayElements(result, &is_copy);
180 CHECK(!is_copy);
181 memcpy(buffer, str.data(), str.size());
182 return result;
183 }
184
185 // static proxy methods.
FindClassProxy(JNIEnv * env,const char * class_path)186 jclass MockJNIEnv::FindClassProxy(JNIEnv *env, const char *class_path) {
187 return static_cast<MockJNIEnv*>(env->functions->reserved0)
188 ->FindClass(class_path);
189 }
190
GetStaticMethodIDProxy(JNIEnv * env,jclass cls,const char * name,const char * signature)191 jmethodID MockJNIEnv::GetStaticMethodIDProxy(
192 JNIEnv *env, jclass cls, const char *name, const char *signature) {
193 return static_cast<MockJNIEnv*>(env->functions->reserved0)
194 ->GetStaticMethodID(cls, name, signature);
195 }
196
PushLocalFrameProxy(JNIEnv *,jint)197 jint MockJNIEnv::PushLocalFrameProxy(JNIEnv *, jint) {
198 return 0;
199 }
200
PopLocalFrameProxy(JNIEnv *,jobject)201 jobject MockJNIEnv::PopLocalFrameProxy(JNIEnv *, jobject) {
202 return NULL;
203 }
204
NewGlobalRefProxy(JNIEnv *,jobject obj)205 jobject MockJNIEnv::NewGlobalRefProxy(JNIEnv *, jobject obj) {
206 return obj;
207 }
208
DeleteGlobalRefProxy(JNIEnv *,jobject)209 void MockJNIEnv::DeleteGlobalRefProxy(JNIEnv *, jobject) {
210 }
211
CallStaticObjectMethodVProxy(JNIEnv * env,jclass cls,jmethodID method,va_list args)212 jobject MockJNIEnv::CallStaticObjectMethodVProxy(
213 JNIEnv *env, jclass cls, jmethodID method, va_list args) {
214 return static_cast<MockJNIEnv*>(env->functions->reserved0)
215 ->CallStaticObjectMethodV(cls, method, args);
216 }
217
ExceptionOccurredProxy(JNIEnv *)218 jthrowable MockJNIEnv::ExceptionOccurredProxy(JNIEnv *) {
219 return NULL;
220 }
221
NewByteArrayProxy(JNIEnv * env,jsize size)222 jbyteArray MockJNIEnv::NewByteArrayProxy(JNIEnv *env, jsize size) {
223 return static_cast<MockJNIEnv*>(env->functions->reserved0)
224 ->NewByteArray(size);
225 }
226
GetArrayLengthProxy(JNIEnv * env,jarray array)227 jsize MockJNIEnv::GetArrayLengthProxy(JNIEnv *env, jarray array) {
228 return static_cast<MockJNIEnv*>(env->functions->reserved0)
229 ->GetArrayLength(array);
230 }
231
GetByteArrayRegionProxy(JNIEnv * env,jbyteArray array,jsize start,jsize len,jbyte * buf)232 void MockJNIEnv::GetByteArrayRegionProxy(
233 JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf) {
234 static_cast<MockJNIEnv*>(env->functions->reserved0)
235 ->GetByteArrayRegion(array, start, len, buf);
236 }
237
SetByteArrayRegionProxy(JNIEnv * env,jbyteArray array,jsize start,jsize len,const jbyte * buf)238 void MockJNIEnv::SetByteArrayRegionProxy(
239 JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf) {
240 static_cast<MockJNIEnv*>(env->functions->reserved0)
241 ->SetByteArrayRegion(array, start, len, buf);
242 }
243
MockJavaVM()244 MockJavaVM::MockJavaVM() {
245 SetUpJavaVM();
246 }
247
~MockJavaVM()248 MockJavaVM::~MockJavaVM() {
249 TearDownJavaVM();
250 }
251
GetEnv(void ** env,jint version)252 jint MockJavaVM::GetEnv(void **env, jint version) {
253 *env = env_.mutable_env();
254 return JNI_OK;
255 }
256
GetEnvProxy(JavaVM * jvm,void ** env,jint version)257 jint MockJavaVM::GetEnvProxy(JavaVM *jvm, void **env, jint version) {
258 return static_cast<MockJavaVM*>(jvm->functions->reserved0)
259 ->GetEnv(env, version);
260 }
261
SetUpJavaVM()262 void MockJavaVM::SetUpJavaVM() {
263 JNIInvokeInterface *functions = new JNIInvokeInterface;
264 functions->reserved0 = this;
265 functions->GetEnv = MockJavaVM::GetEnvProxy;
266
267 jvm_.functions = functions;
268 }
269
TearDownJavaVM()270 void MockJavaVM::TearDownJavaVM() {
271 delete jvm_.functions;
272 }
273
274 } // jni
275 } // mozc
276