Codebase list mozc / upstream/latest base / android_jni_mock.cc
upstream/latest

Tree @upstream/latest (Download .tar.gz)

android_jni_mock.cc @upstream/latestraw · history · blame

// Copyright 2010-2014, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "base/android_jni_mock.h"

#include "base/logging.h"

namespace mozc {
namespace jni {

MockJNIEnv::MockJNIEnv() {
  SetUpJNIEnv();
}

MockJNIEnv::~MockJNIEnv() {
  ClearArrayMap();
  TearDownJNIEnv();
}

// Setting up a JNIEnv instance.
void MockJNIEnv::SetUpJNIEnv() {
  JNINativeInterface *functions = new JNINativeInterface;
  functions->reserved0 = this;
  functions->FindClass = MockJNIEnv::FindClassProxy;
  functions->GetStaticMethodID = MockJNIEnv::GetStaticMethodIDProxy;
  functions->PushLocalFrame = MockJNIEnv::PushLocalFrameProxy;
  functions->PopLocalFrame = MockJNIEnv::PopLocalFrameProxy;
  functions->NewGlobalRef = MockJNIEnv::NewGlobalRefProxy;
  functions->DeleteGlobalRef = MockJNIEnv::DeleteGlobalRefProxy;

  functions->CallStaticObjectMethodV =
      MockJNIEnv::CallStaticObjectMethodVProxy;
  functions->ExceptionOccurred = MockJNIEnv::ExceptionOccurredProxy;

  functions->NewByteArray = MockJNIEnv::NewByteArrayProxy;
  functions->GetArrayLength = MockJNIEnv::GetArrayLengthProxy;
  functions->GetByteArrayRegion = MockJNIEnv::GetByteArrayRegionProxy;
  functions->SetByteArrayRegion = MockJNIEnv::SetByteArrayRegionProxy;

  env_.functions = functions;
}

void MockJNIEnv::TearDownJNIEnv() {
  delete env_.functions;
}

void MockJNIEnv::ClearArrayMap() {
  for (map<jbyteArray, pair<jsize, jbyte*> >::iterator iter =
           byte_array_map_.begin();
       iter != byte_array_map_.end(); ++iter) {
    delete iter->first;
    delete [] iter->second.second;
  }
  byte_array_map_.clear();
}

jclass MockJNIEnv::FindClass(const char *class_path) {
  static const char kHttpClientPath[] =
      "org/mozc/android/inputmethod/japanese/nativecallback/HttpClient";
  if (strcmp(class_path, kHttpClientPath) == 0) {
    return &mock_http_client_class_;
  }
  return NULL;
}

jmethodID MockJNIEnv::GetStaticMethodID(
    jclass cls, const char *name, const char *signature) {
  if (cls == &mock_http_client_class_) {
    if (strcmp(name, "request") == 0 &&
        strcmp(signature, "([B[B[B)[B") == 0) {
      return reinterpret_cast<jmethodID>(&mock_request_);
    }
    return NULL;
  }
  return NULL;
}

jobject MockJNIEnv::CallStaticObjectMethodV(
    jclass cls, jmethodID method, va_list args) {
  if (cls == &mock_http_client_class_) {
    CHECK(mock_http_client_.get() != NULL)
        << "mock_http_client_ is not initialized.";
    if (method == reinterpret_cast<jmethodID>(&mock_request_)) {
      jbyteArray method = va_arg(args, jbyteArray);
      jbyteArray url = va_arg(args, jbyteArray);
      jbyteArray post_data = va_arg(args, jbyteArray);
      return mock_http_client_->Request(method, url, post_data);
    }
    LOG(FATAL) << "Unexpected call.";
    return NULL;
  }
  LOG(FATAL) << "Unexpected call.";
  return NULL;
}

// Utilities to manage jbyteArray instances.
jbyteArray MockJNIEnv::NewByteArray(jsize size) {
  // Use non-public type _jbyteArray, which is the dereferenced type of
  // jbyteArray. We can use the same technique as MockJMethodId if necessary,
  // but this hack looks simpler.
  jbyteArray result = new _jbyteArray;
  jbyte *buf = new jbyte[size];
  byte_array_map_[result] = make_pair(size, buf);
  return result;
}

jsize MockJNIEnv::GetArrayLength(jarray array) {
  map<jbyteArray, pair<jsize, jbyte*> >::iterator iter =
      byte_array_map_.find(static_cast<jbyteArray>(array));
  if (iter != byte_array_map_.end()) {
    return iter->second.first;
  }
  return 0;
}

jbyte *MockJNIEnv::GetByteArrayElements(jbyteArray array, jboolean *is_copy) {
  map<jbyteArray, pair<jsize, jbyte*> >::iterator iter =
      byte_array_map_.find(array);
  if (iter != byte_array_map_.end()) {
    if (is_copy) {
      *is_copy = JNI_FALSE;
    }
    return iter->second.second;
  }
  return NULL;
}
void MockJNIEnv::GetByteArrayRegion(
      jbyteArray array, jsize start, jsize len, jbyte *buf) {
  const jsize size = GetArrayLength(array);
  CHECK(start <= size);
  CHECK(start + len <= size);
  memcpy(buf, GetByteArrayElements(array, NULL) + start, len);
}

void MockJNIEnv::SetByteArrayRegion(
      jbyteArray array, jsize start, jsize len, const jbyte *buf) {
  const jsize size = GetArrayLength(array);
  CHECK(start <= size);
  CHECK(start + len <= size);
  memcpy(GetByteArrayElements(array, NULL) + start, buf, len);
}

string MockJNIEnv::JByteArrayToString(jbyteArray array) {
  jboolean is_copy;
  jbyte *buffer = GetByteArrayElements(array, &is_copy);
  CHECK(!is_copy);
  return string(reinterpret_cast<char*>(buffer), GetArrayLength(array));
}

jbyteArray MockJNIEnv::StringToJByteArray(const string &str) {
  jbyteArray result = NewByteArray(str.size());
  jboolean is_copy;
  jbyte *buffer = GetByteArrayElements(result, &is_copy);
  CHECK(!is_copy);
  memcpy(buffer, str.data(), str.size());
  return result;
}

// static proxy methods.
jclass MockJNIEnv::FindClassProxy(JNIEnv *env, const char *class_path) {
  return static_cast<MockJNIEnv*>(env->functions->reserved0)
      ->FindClass(class_path);
}

jmethodID MockJNIEnv::GetStaticMethodIDProxy(
    JNIEnv *env, jclass cls, const char *name, const char *signature) {
  return static_cast<MockJNIEnv*>(env->functions->reserved0)
      ->GetStaticMethodID(cls, name, signature);
}

jint MockJNIEnv::PushLocalFrameProxy(JNIEnv *, jint) {
  return 0;
}

jobject MockJNIEnv::PopLocalFrameProxy(JNIEnv *, jobject) {
  return NULL;
}

jobject MockJNIEnv::NewGlobalRefProxy(JNIEnv *, jobject obj) {
  return obj;
}

void MockJNIEnv::DeleteGlobalRefProxy(JNIEnv *, jobject) {
}

jobject MockJNIEnv::CallStaticObjectMethodVProxy(
    JNIEnv *env, jclass cls, jmethodID method, va_list args) {
  return static_cast<MockJNIEnv*>(env->functions->reserved0)
      ->CallStaticObjectMethodV(cls, method, args);
}

jthrowable MockJNIEnv::ExceptionOccurredProxy(JNIEnv *) {
  return NULL;
}

jbyteArray MockJNIEnv::NewByteArrayProxy(JNIEnv *env, jsize size) {
  return static_cast<MockJNIEnv*>(env->functions->reserved0)
      ->NewByteArray(size);
}

jsize MockJNIEnv::GetArrayLengthProxy(JNIEnv *env, jarray array) {
  return static_cast<MockJNIEnv*>(env->functions->reserved0)
      ->GetArrayLength(array);
}

void MockJNIEnv::GetByteArrayRegionProxy(
      JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf) {
  static_cast<MockJNIEnv*>(env->functions->reserved0)
      ->GetByteArrayRegion(array, start, len, buf);
}

void MockJNIEnv::SetByteArrayRegionProxy(
      JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf) {
  static_cast<MockJNIEnv*>(env->functions->reserved0)
      ->SetByteArrayRegion(array, start, len, buf);
}

MockJavaVM::MockJavaVM() {
  SetUpJavaVM();
}

MockJavaVM::~MockJavaVM() {
  TearDownJavaVM();
}

jint MockJavaVM::GetEnv(void **env, jint version) {
  *env = env_.mutable_env();
  return JNI_OK;
}

jint MockJavaVM::GetEnvProxy(JavaVM *jvm, void **env, jint version) {
  return static_cast<MockJavaVM*>(jvm->functions->reserved0)
      ->GetEnv(env, version);
}

void MockJavaVM::SetUpJavaVM() {
  JNIInvokeInterface *functions = new JNIInvokeInterface;
  functions->reserved0 = this;
  functions->GetEnv = MockJavaVM::GetEnvProxy;

  jvm_.functions = functions;
}

void MockJavaVM::TearDownJavaVM() {
  delete jvm_.functions;
}

}  // jni
}  // mozc