Move some really old tests to the cxx bridge

Reviewed By: mhorowitz

Differential Revision: D3507905

fbshipit-source-id: cbe55495a991bf6eef961319ba8b219e660dce05
This commit is contained in:
Chris Hopman
2016-07-25 12:19:46 -07:00
committed by Facebook Github Bot 0
parent c658cc545f
commit d67258eb91
13 changed files with 429 additions and 398 deletions

View File

@@ -40,6 +40,11 @@ std::vector<MethodCall> parseMethodCalls(const std::string& json) throw(std::inv
folly::to<std::string>("Did not get valid calls back from JS: ", json.c_str()));
}
if (moduleIds.size() != methodIds.size() || moduleIds.size() != params.size()) {
throw std::invalid_argument(
folly::to<std::string>("Did not get valid calls back from JS: ", json.c_str()));
}
if (jsonData.size() > REQUEST_CALLID) {
if (!jsonData[REQUEST_CALLID].isInt()) {
throw std::invalid_argument(

View File

@@ -7,11 +7,16 @@ jni_instrumentation_test_lib(
soname = 'libxplat-bridge.so',
srcs = [
'CxxMessageQueueTest.cpp',
'value.cpp',
'methodcall.cpp',
'jsclogging.cpp',
'jscexecutor.cpp',
],
compiler_flags = [
'-fexceptions',
],
deps = [
'//native/third-party/android-ndk:android',
'//xplat/third-party/gmock:gtest',
react_native_xplat_target('cxxreact:bridge'),
],

View File

@@ -0,0 +1,270 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <gtest/gtest.h>
#include <cxxreact/JSCExecutor.h>
#include <cxxreact/MessageQueueThread.h>
#include <cxxreact/MethodCall.h>
using namespace facebook;
using namespace facebook::react;
// TODO(12340362): Fix these tests. And add checks for sizes.
/*
namespace {
std::string capturedMethodCalls;
struct NullDelegate : ExecutorDelegate {
virtual void registerExecutor(std::unique_ptr<JSExecutor> executor,
std::shared_ptr<MessageQueueThread> queue) {
std::terminate();
}
virtual std::unique_ptr<JSExecutor> unregisterExecutor(JSExecutor& executor) {
std::terminate();
}
virtual std::vector<std::string> moduleNames() {
return std::vector<std::string>{};
}
virtual folly::dynamic getModuleConfig(const std::string& name) {
std::terminate();
}
virtual void callNativeModules(
JSExecutor& executor, std::string callJSON, bool isEndOfBatch) {
// TODO: capture calljson
std::terminate();
}
virtual MethodCallResult callSerializableNativeHook(
JSExecutor& executor, unsigned int moduleId, unsigned int methodId, folly::dynamic&& args) {
std::terminate();
}
};
struct FakeMessageQueue : MessageQueueThread {
virtual void runOnQueue(std::function<void()>&& runnable) {
// This is wrong, but oh well.
runnable();
}
virtual void runOnQueueSync(std::function<void()>&& runnable) {
runnable();
}
virtual void quitSynchronous() {
std::terminate();
}
};
std::vector<MethodCall> executeForMethodCalls(
JSCExecutor& e,
int moduleId,
int methodId,
folly::dynamic args = folly::dynamic::array()) {
e.callFunction(folly::to<std::string>(moduleId), folly::to<std::string>(methodId), std::move(args));
return parseMethodCalls(capturedMethodCalls);
}
void loadApplicationScript(JSCExecutor& e, std::string jsText) {
e.loadApplicationScript(std::unique_ptr<JSBigString>(new JSBigStdString(jsText)), "");
}
void setGlobalVariable(JSCExecutor& e, std::string name, std::string jsonObject) {
e.setGlobalVariable(name, std::unique_ptr<JSBigString>(new JSBigStdString(jsonObject)));
}
}
TEST(JSCExecutor, Initialize) {
JSCExecutor executor(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
}
TEST(JSCExecutor, Two) {
JSCExecutor exec1(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
JSCExecutor exec2(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
}
TEST(JSCExecutor, CallFunction) {
auto jsText = ""
"var Bridge = {"
" callFunctionReturnFlushedQueue: function (module, method, args) {"
" return [[module + 1], [method + 1], [args]];"
" },"
"};"
"function require() { return Bridge; }"
"";
JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
loadApplicationScript(e, jsText);
folly::dynamic args = folly::dynamic::array();
args.push_back(true);
args.push_back(0.4);
args.push_back("hello, world");
args.push_back(4.0);
auto returnedCalls = executeForMethodCalls(e, 10, 9, args);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
EXPECT_EQ(11, returnedCall.moduleId);
EXPECT_EQ(10, returnedCall.methodId);
ASSERT_EQ(4, returnedCall.arguments.size());
EXPECT_EQ(args[0], returnedCall.arguments[0]);
EXPECT_EQ(args[1], returnedCall.arguments[1]);
EXPECT_EQ(args[2], returnedCall.arguments[2]);
EXPECT_EQ(folly::dynamic(4.0), returnedCall.arguments[3]);
}
TEST(JSCExecutor, CallFunctionWithMap) {
auto jsText = ""
"var Bridge = {"
" callFunctionReturnFlushedQueue: function (module, method, args) {"
" var s = args[0].foo + args[0].bar + args[0].baz;"
" return [[module], [method], [[s]]];"
" },"
"};"
"function require() { return Bridge; }"
"";
JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
loadApplicationScript(e, jsText);
folly::dynamic args = folly::dynamic::array();
folly::dynamic map = folly::dynamic::object
("foo", folly::dynamic("hello"))
("bar", folly::dynamic(4.0))
("baz", folly::dynamic(true))
;
args.push_back(std::move(map));
auto returnedCalls = executeForMethodCalls(e, 10, 9, args);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(1, returnedCall.arguments.size());
EXPECT_EQ("hello4true", returnedCall.arguments[0].getString());
}
TEST(JSCExecutor, CallFunctionReturningMap) {
auto jsText = ""
"var Bridge = {"
" callFunctionReturnFlushedQueue: function (module, method, args) {"
" var s = { foo: 4, bar: true };"
" return [[module], [method], [[s]]];"
" },"
"};"
"function require() { return Bridge; }"
"";
JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
loadApplicationScript(e, jsText);
auto returnedCalls = executeForMethodCalls(e, 10, 9);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(1, returnedCall.arguments.size());
ASSERT_EQ(folly::dynamic::OBJECT, returnedCall.arguments[0].type());
auto& returnedMap = returnedCall.arguments[0];
auto foo = returnedMap.at("foo");
EXPECT_EQ(folly::dynamic(4.0), foo);
auto bar = returnedMap.at("bar");
EXPECT_EQ(folly::dynamic(true), bar);
}
TEST(JSCExecutor, CallFunctionWithArray) {
auto jsText = ""
"var Bridge = {"
" callFunctionReturnFlushedQueue: function (module, method, args) {"
" var s = args[0][0]+ args[0][1] + args[0][2] + args[0].length;"
" return [[module], [method], [[s]]];"
" },"
"};"
"function require() { return Bridge; }"
"";
JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
loadApplicationScript(e, jsText);
std::vector<folly::dynamic> args;
std::vector<folly::dynamic> array {
folly::dynamic("hello"),
folly::dynamic(4.0),
folly::dynamic(true),
};
args.push_back(std::move(array));
auto returnedCalls = executeForMethodCalls(e, 10, 9, args);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(1, returnedCall.arguments.size());
EXPECT_EQ("hello4true3", returnedCall.arguments[0].getString());
}
TEST(JSCExecutor, CallFunctionReturningNumberArray) {
auto jsText = ""
"var Bridge = {"
" callFunctionReturnFlushedQueue: function (module, method, args) {"
" var s = [3, 1, 4];"
" return [[module], [method], [[s]]];"
" },"
"};"
"function require() { return Bridge; }"
"";
JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
loadApplicationScript(e, jsText);
auto returnedCalls = executeForMethodCalls(e, 10, 9);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(1, returnedCall.arguments.size());
ASSERT_EQ(folly::dynamic::ARRAY, returnedCall.arguments[0].type());
auto& array = returnedCall.arguments[0];
EXPECT_EQ(3, array.size());
EXPECT_EQ(folly::dynamic(3.0), array[0]);
EXPECT_EQ(folly::dynamic(4.0), array[2]);
}
TEST(JSCExecutor, SetSimpleGlobalVariable) {
auto jsText = ""
"var Bridge = {"
" callFunctionReturnFlushedQueue: function (module, method, args) {"
" return [[module], [method], [[__foo]]];"
" },"
"};"
"function require() { return Bridge; }"
"";
JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
loadApplicationScript(e, jsText);
setGlobalVariable(e, "__foo", "42");
auto returnedCalls = executeForMethodCalls(e, 10, 9);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(1, returnedCall.arguments.size());
ASSERT_EQ(42.0, returnedCall.arguments[0].getDouble());
}
TEST(JSCExecutor, SetObjectGlobalVariable) {
auto jsText = ""
"var Bridge = {"
" callFunctionReturnFlushedQueue: function (module, method, args) {"
" return [[module], [method], [[__foo]]];"
" },"
"};"
"function require() { return Bridge; }"
"";
JSCExecutor e(std::make_shared<NullDelegate>(), std::make_shared<FakeMessageQueue>(), "", folly::dynamic::object);
loadApplicationScript(e, jsText);
auto jsonObject = ""
"{"
" \"foo\": \"hello\","
" \"bar\": 4,"
" \"baz\": true"
"}"
"";
setGlobalVariable(e, "__foo", jsonObject);
auto returnedCalls = executeForMethodCalls(e, 10, 9);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(1, returnedCall.arguments.size());
ASSERT_EQ(folly::dynamic::OBJECT, returnedCall.arguments[0].type());
auto& returnedMap = returnedCall.arguments[0];
auto foo = returnedMap.at("foo");
EXPECT_EQ(folly::dynamic("hello"), foo);
auto bar = returnedMap.at("bar");
EXPECT_EQ(folly::dynamic(4.0), bar);
auto baz = returnedMap.at("baz");
EXPECT_EQ(folly::dynamic(true), baz);
}
*/

View File

@@ -0,0 +1,44 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <gtest/gtest.h>
#include <cxxreact/JSCExecutor.h>
using namespace facebook;
using namespace facebook::react;
/*
static const char* expectedLogMessageSubstring = NULL;
static bool hasSeenExpectedLogMessage = false;
static void mockLogHandler(int pri, const char *tag, const char *msg) {
if (expectedLogMessageSubstring == NULL) {
return;
}
hasSeenExpectedLogMessage |= (strstr(msg, expectedLogMessageSubstring) != NULL);
}
class JSCLoggingTest : public testing::Test {
protected:
virtual void SetUp() override {
setLogHandler(&mockLogHandler);
}
virtual void TearDown() override {
setLogHandler(NULL);
expectedLogMessageSubstring = NULL;
hasSeenExpectedLogMessage = false;
}
};
TEST_F(JSCLoggingTest, LogException) {
auto jsText = "throw new Error('I am a banana!');";
expectedLogMessageSubstring = "I am a banana!";
JSCExecutor e;
e.loadApplicationScript(jsText, "");
ASSERT_TRUE(hasSeenExpectedLogMessage);
}
*/

View File

@@ -0,0 +1,137 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <gtest/gtest.h>
#include <cxxreact/MethodCall.h>
using namespace facebook;
using namespace facebook::react;
TEST(parseMethodCalls, SingleReturnCallNoArgs) {
auto jsText = "[[7],[3],[\"[]\"]]";
auto returnedCalls = parseMethodCalls(jsText);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(0, returnedCall.arguments.size());
ASSERT_EQ(7, returnedCall.moduleId);
ASSERT_EQ(3, returnedCall.methodId);
}
TEST(parseMethodCalls, InvalidReturnFormat) {
try {
parseMethodCalls("{\"foo\":1}");
ADD_FAILURE();
} catch (const std::invalid_argument&) {
// ignored
}
try {
parseMethodCalls("[{\"foo\":1}]");
ADD_FAILURE();
} catch (const std::invalid_argument&) {
// ignored
}
try {
parseMethodCalls("[1,4,{\"foo\":2}]");
ADD_FAILURE();
} catch (const std::invalid_argument&) {
// ignored
}
try {
parseMethodCalls("[[1],[4],{\"foo\":2}]");
ADD_FAILURE();
} catch (const std::invalid_argument&) {
// ignored
}
try {
parseMethodCalls("[[1],[4],[]]");
ADD_FAILURE();
} catch (const std::invalid_argument&) {
// ignored
}
}
TEST(parseMethodCalls, NumberReturn) {
auto jsText = "[[0],[0],[\"[\\\"foobar\\\"]\"]]";
auto returnedCalls = parseMethodCalls(jsText);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(1, returnedCall.arguments.size());
ASSERT_EQ(folly::dynamic::STRING, returnedCall.arguments[0].type());
ASSERT_EQ("foobar", returnedCall.arguments[0].asString());
}
TEST(parseMethodCalls, StringReturn) {
auto jsText = "[[0],[0],[\"[42.16]\"]]";
auto returnedCalls = parseMethodCalls(jsText);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(1, returnedCall.arguments.size());
ASSERT_EQ(folly::dynamic::DOUBLE, returnedCall.arguments[0].type());
ASSERT_EQ(42.16, returnedCall.arguments[0].asDouble());
}
TEST(parseMethodCalls, BooleanReturn) {
auto jsText = "[[0],[0],[\"[false]\"]]";
auto returnedCalls = parseMethodCalls(jsText);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(1, returnedCall.arguments.size());
ASSERT_EQ(folly::dynamic::BOOL, returnedCall.arguments[0].type());
ASSERT_FALSE(returnedCall.arguments[0].asBool());
}
TEST(parseMethodCalls, NullReturn) {
auto jsText = "[[0],[0],[\"[null]\"]]";
auto returnedCalls = parseMethodCalls(jsText);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(1, returnedCall.arguments.size());
ASSERT_EQ(folly::dynamic::NULLT, returnedCall.arguments[0].type());
}
TEST(parseMethodCalls, MapReturn) {
auto jsText = "[[0],[0],[\"[{\\\"foo\\\": \\\"hello\\\", \\\"bar\\\": 4.0, \\\"baz\\\": true}]\"]]";
auto returnedCalls = parseMethodCalls(jsText);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(1, returnedCall.arguments.size());
ASSERT_EQ(folly::dynamic::OBJECT, returnedCall.arguments[0].type());
auto& returnedMap = returnedCall.arguments[0];
auto foo = returnedMap.at("foo");
EXPECT_EQ(folly::dynamic("hello"), foo);
auto bar = returnedMap.at("bar");
EXPECT_EQ(folly::dynamic(4.0), bar);
auto baz = returnedMap.at("baz");
EXPECT_EQ(folly::dynamic(true), baz);
}
TEST(parseMethodCalls, ArrayReturn) {
auto jsText = "[[0],[0],[\"[[\\\"foo\\\", 42.0, false]]\"]]";
auto returnedCalls = parseMethodCalls(jsText);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(1, returnedCall.arguments.size());
ASSERT_EQ(folly::dynamic::ARRAY, returnedCall.arguments[0].type());
auto& returnedArray = returnedCall.arguments[0];
ASSERT_EQ(3, returnedArray.size());
ASSERT_EQ(folly::dynamic("foo"), returnedArray[0]);
ASSERT_EQ(folly::dynamic(42.0), returnedArray[1]);
ASSERT_EQ(folly::dynamic(false), returnedArray[2]);
}
TEST(parseMethodCalls, ReturnMultipleParams) {
auto jsText = "[[0],[0],[\"[\\\"foo\\\", 14, null, false]\"]]";
auto returnedCalls = parseMethodCalls(jsText);
ASSERT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
ASSERT_EQ(4, returnedCall.arguments.size());
ASSERT_EQ(folly::dynamic::STRING, returnedCall.arguments[0].type());
ASSERT_EQ(folly::dynamic::INT64, returnedCall.arguments[1].type());
ASSERT_EQ(folly::dynamic::NULLT, returnedCall.arguments[2].type());
ASSERT_EQ(folly::dynamic::BOOL, returnedCall.arguments[3].type());
}
TEST(parseMethodCalls, ParseTwoCalls) {
auto jsText = "[[0,0],[1,1],[\"[]\",\"[]\"]]";
auto returnedCalls = parseMethodCalls(jsText);
ASSERT_EQ(2, returnedCalls.size());
}

View File

@@ -0,0 +1,40 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <gtest/gtest.h>
#include <folly/json.h>
#include <cxxreact/Value.h>
using namespace facebook;
using namespace facebook::react;
// TODO(cjhopman): Fix these tests.
/*
TEST(Value, Undefined) {
JSContextRef ctx = JSGlobalContextCreateInGroup(nullptr, nullptr);
Value v(ctx, JSValueMakeUndefined(ctx));
auto s = String::adopt(JSValueToStringCopy(ctx, v, nullptr));
EXPECT_EQ("undefined", s.str());
}
TEST(Value, FromJSON) {
JSContextRef ctx = JSGlobalContextCreateInGroup(nullptr, nullptr);
String s("{\"a\": 4}");
Value v(Value::fromJSON(ctx, s));
EXPECT_TRUE(JSValueIsObject(ctx, v));
}
TEST(Value, ToJSONString) {
JSContextRef ctx = JSGlobalContextCreateInGroup(nullptr, nullptr);
String s("{\"a\": 4}");
Value v(Value::fromJSON(ctx, s));
folly::dynamic dyn = folly::parseJson(v.toJSONString());
ASSERT_NE(nullptr, dyn);
EXPECT_TRUE(dyn.isObject());
auto val = dyn.at("a");
ASSERT_NE(nullptr, val);
ASSERT_TRUE(val.isInt());
EXPECT_EQ(4, val.getInt());
EXPECT_EQ(4.0f, val.asDouble());
}
*/