initial commit taken from gitlab.lrz.de

This commit is contained in:
privatereese
2018-08-24 18:09:42 +02:00
parent ae54ed4c48
commit fc05486403
28494 changed files with 2159823 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target")
TEST_SRCS = [
"RecoverableErrorTest.cpp",
"jsarg_helpers.cpp",
"jsbigstring.cpp",
"jscexecutor.cpp",
"jsclogging.cpp",
"methodcall.cpp",
"value.cpp",
]
if not IS_OSS_BUILD:
load("@xplat//build_defs:fb_xplat_cxx.bzl", "cxx_test")
load("@xplat//configurations/buck/android:jni_instrumentation_test", "jni_instrumentation_test_lib")
load("@xplat//configurations/buck:default_platform_defs.bzl", "APPLE")
jni_instrumentation_test_lib(
name = 'tests',
class_under_test = 'com/facebook/react/XplatBridgeTest',
soname = 'libxplat-bridge.so',
srcs = TEST_SRCS,
compiler_flags = [
'-fexceptions',
'-frtti',
'-std=c++14',
],
deps = [
'xplat//third-party/linker_lib:android',
'xplat//third-party/gmock:gtest',
react_native_xplat_target('cxxreact:bridge'),
],
visibility = [
'fbandroid//instrumentation_tests/...'
],
)
cxx_test(
name = 'tests',
srcs = TEST_SRCS,
compiler_flags = [
'-fexceptions',
'-frtti',
],
platforms = APPLE,
deps = [
'xplat//folly:molly',
'xplat//third-party/gmock:gtest',
react_native_xplat_target('cxxreact:bridge'),
react_native_xplat_target('jschelpers:jschelpers'),
],
visibility = [
react_native_xplat_target('cxxreact/...'),
],
)

View File

@@ -0,0 +1,36 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <gtest/gtest.h>
#include <exception>
#include <stdexcept>
#include <cxxreact/RecoverableError.h>
using namespace facebook::react;
TEST(RecoverableError, RunRethrowingAsRecoverableRecoverTest) {
try {
RecoverableError::runRethrowingAsRecoverable<std::runtime_error>([]() {
throw std::runtime_error("catch me");
});
FAIL() << "Unthrown exception";
} catch (const RecoverableError &err) {
ASSERT_STREQ(err.what(), "facebook::react::Recoverable: catch me");
} catch (...) {
FAIL() << "Uncaught exception";
}
}
TEST(RecoverableError, RunRethrowingAsRecoverableFallthroughTest) {
try {
RecoverableError::runRethrowingAsRecoverable<std::runtime_error>([]() {
throw std::logic_error("catch me");
});
FAIL() << "Unthrown exception";
} catch (const RecoverableError &err) {
FAIL() << "Recovered exception that should have fallen through";
} catch (const std::exception &err) {
ASSERT_STREQ(err.what(), "catch me");
}
}

View File

@@ -0,0 +1,100 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <cxxreact/JsArgumentHelpers.h>
#include <folly/dynamic.h>
#include <gtest/gtest.h>
#include <algorithm>
using namespace std;
using namespace folly;
using namespace facebook::xplat;
#define EXPECT_JSAE(statement, exstr) do { \
try { \
statement; \
FAIL() << "Expected JsArgumentException(" << (exstr) << ") not thrown"; \
} catch (const JsArgumentException& ex) { \
EXPECT_EQ(ex.what(), std::string(exstr)); \
} \
} while(0) // let any other exception escape, gtest will deal.
TEST(JsArgumentHelpersTest, args) {
const bool aBool = true;
const int64_t anInt = 17;
const double aDouble = 3.14;
const string aString = "word";
const dynamic anArray = dynamic::array("a", "b", "c");
const dynamic anObject = dynamic::object("k1", "v1")("k2", "v2");
const string aNumericString = to<string>(anInt);
folly::dynamic args = dynamic::array(aBool, anInt, aDouble, aString, anArray, anObject, aNumericString);
EXPECT_EQ(jsArgAsBool(args, 0), aBool);
EXPECT_EQ(jsArgAsInt(args, 1), anInt);
EXPECT_EQ(jsArgAsDouble(args, 2), aDouble);
EXPECT_EQ(jsArgAsString(args, 3), aString);
EXPECT_EQ(jsArgAsArray(args, 4), anArray);
EXPECT_EQ(jsArgAsObject(args, 5), anObject);
// const args
const folly::dynamic& cargs = args;
const folly::dynamic& a4 = jsArgAsArray(cargs, 4);
EXPECT_EQ(a4, anArray);
EXPECT_EQ(jsArgAsObject(cargs, 5), anObject);
// helpers returning dynamic should return same object without copying
EXPECT_EQ(&jsArgAsArray(args, 4), &(args[4]));
EXPECT_EQ(&jsArgAsArray(cargs, 4), &(args[4]));
// dynamics returned for mutable args should be mutable. The test is that
// this compiles.
jsArgAsArray(args, 4)[2] = "d";
jsArgAsArray(args, 4)[2] = "c";
// These fail to compile due to constness.
// jsArgAsArray(cargs, 4)[2] = "d";
// jsArgAsArray(cargs, 4)[2] = "c";
// ref-qualified member function tests
EXPECT_EQ(jsArgN(args, 3, &folly::dynamic::getString), aString);
EXPECT_EQ(jsArg(args[3], &folly::dynamic::getString), aString);
// conversions
EXPECT_EQ(jsArgAsDouble(args, 1), anInt * 1.0);
EXPECT_EQ(jsArgAsString(args, 1), aNumericString);
EXPECT_EQ(jsArgAsInt(args, 6), anInt);
// Test exception messages.
// out_of_range
EXPECT_JSAE(jsArgAsBool(args, 7),
"JavaScript provided 7 arguments for C++ method which references at least "
"8 arguments: out of range in dynamic array");
// Conv range_error (invalid value conversion)
const std::string exhead = "Could not convert argument 3 to required type: ";
const std::string extail = ": Invalid leading character: \"word\"";
try {
jsArgAsInt(args, 3);
FAIL() << "Expected JsArgumentException(" << exhead << "..." << extail << ") not thrown";
} catch (const JsArgumentException& ex) {
const std::string exwhat = ex.what();
EXPECT_GT(exwhat.size(), exhead.size());
EXPECT_GT(exwhat.size(), extail.size());
EXPECT_TRUE(std::equal(exhead.cbegin(), exhead.cend(), exwhat.cbegin()))
<< "JsArgumentException('" << exwhat << "') does not begin with '" << exhead << "'";
EXPECT_TRUE(std::equal(extail.crbegin(), extail.crend(), exwhat.crbegin()))
<< "JsArgumentException('" << exwhat << "') does not end with '" << extail << "'";
}
// inconvertible types
EXPECT_JSAE(jsArgAsArray(args, 2),
"Argument 3 of type double is not required type Array");
EXPECT_JSAE(jsArgAsInt(args, 4),
"Error converting javascript arg 4 to C++: "
"TypeError: expected dynamic type `int/double/bool/string', but had type `array'");
// type predicate failure
EXPECT_JSAE(jsArgAsObject(args, 4),
"Argument 5 of type array is not required type Object");
}

View File

@@ -0,0 +1,56 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <sys/mman.h>
#include <fcntl.h>
#include <folly/File.h>
#include <gtest/gtest.h>
#include <cxxreact/JSBigString.h>
using namespace facebook;
using namespace facebook::react;
namespace {
int tempFileFromString(std::string contents)
{
std::string tmp {getenv("TMPDIR")};
tmp += "/temp.XXXXXX";
std::vector<char> tmpBuf {tmp.begin(), tmp.end()};
tmpBuf.push_back('\0');
const int fd = mkstemp(tmpBuf.data());
write(fd, contents.c_str(), contents.size() + 1);
return fd;
}
};
TEST(JSBigFileString, MapWholeFileTest) {
std::string data {"Hello, world"};
const auto size = data.length() + 1;
// Initialise Big String
int fd = tempFileFromString("Hello, world");
JSBigFileString bigStr {fd, size};
// Test
ASSERT_STREQ(data.c_str(), bigStr.c_str());
}
TEST(JSBigFileString, MapPartTest) {
std::string data {"Hello, world"};
// Sub-string to actually map
std::string needle {"or"};
off_t offset = data.find(needle);
// Initialise Big String
int fd = tempFileFromString(data);
JSBigFileString bigStr {fd, needle.size(), offset};
// Test
ASSERT_EQ(needle.length(), bigStr.size());
for (unsigned int i = 0; i < needle.length(); ++i) {
ASSERT_EQ(needle[i], bigStr.c_str()[i]);
}
}

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,152 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <cxxreact/MethodCall.h>
#include <folly/json.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
#include <gtest/gtest.h>
#pragma GCC diagnostic pop
using namespace facebook;
using namespace facebook::react;
using namespace folly;
TEST(parseMethodCalls, SingleReturnCallNoArgs) {
auto jsText = "[[7],[3],[[]]]";
auto returnedCalls = parseMethodCalls(folly::parseJson(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 {
auto input = dynamic::object("foo", 1);
parseMethodCalls(std::move(input));
ADD_FAILURE();
} catch (const std::invalid_argument&) {
// ignored
}
try {
auto input = dynamic::array(dynamic::object("foo", 1));
parseMethodCalls(std::move(input));
ADD_FAILURE();
} catch (const std::invalid_argument&) {
// ignored
}
try {
auto input = dynamic::array(1, 4, dynamic::object("foo", 2));
parseMethodCalls(std::move(input));
ADD_FAILURE();
} catch (const std::invalid_argument&) {
// ignored
}
try {
auto input = dynamic::array(dynamic::array(1),
dynamic::array(4),
dynamic::object("foo", 2));
parseMethodCalls(std::move(input));
ADD_FAILURE();
} catch (const std::invalid_argument&) {
// ignored
}
try {
auto input = dynamic::array(dynamic::array(1),
dynamic::array(4),
dynamic::array());
parseMethodCalls(std::move(input));
ADD_FAILURE();
} catch (const std::invalid_argument&) {
// ignored
}
}
TEST(parseMethodCalls, NumberReturn) {
auto jsText = "[[0],[0],[[\"foobar\"]]]";
auto returnedCalls = parseMethodCalls(folly::parseJson(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(folly::parseJson(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(folly::parseJson(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(folly::parseJson(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(folly::parseJson(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(folly::parseJson(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(folly::parseJson(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(folly::parseJson(jsText));
ASSERT_EQ(2, returnedCalls.size());
}

View File

@@ -0,0 +1,105 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <string>
#include <gtest/gtest.h>
#include <folly/json.h>
#include <jschelpers/Value.h>
#ifdef WITH_FBJSCEXTENSION
#undef ASSERT
#include <JavaScriptCore/config.h>
#include "OpaqueJSString.h"
#endif
#include <stdexcept>
using namespace facebook::react;
#ifdef ANDROID
#include <android/looper.h>
static void prepare() {
ALooper_prepare(0);
}
#else
static void prepare() {}
#endif
TEST(Value, Undefined) {
prepare();
JSGlobalContextRef ctx = JSC_JSGlobalContextCreateInGroup(false, nullptr, nullptr);
auto v = Value::makeUndefined(ctx);
auto s = String::adopt(ctx, JSC_JSValueToStringCopy(ctx, v, nullptr));
EXPECT_EQ("undefined", s.str());
JSC_JSGlobalContextRelease(ctx);
}
TEST(Value, FromJSON) {
prepare();
JSGlobalContextRef ctx = JSC_JSGlobalContextCreateInGroup(false, nullptr, nullptr);
String s(ctx, "{\"a\": 4}");
Value v(Value::fromJSON(s));
EXPECT_TRUE(v.isObject());
JSC_JSGlobalContextRelease(ctx);
}
TEST(Value, ToJSONString) {
prepare();
JSGlobalContextRef ctx = JSC_JSGlobalContextCreateInGroup(false, nullptr, nullptr);
String s(ctx, "{\"a\": 4}");
Value v(Value::fromJSON(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.isNumber());
EXPECT_EQ(4, val.asInt());
EXPECT_EQ(4.0f, val.asDouble());
JSC_JSGlobalContextRelease(ctx);
}
#ifdef WITH_FBJSCEXTENSION
// Just test that handling invalid data doesn't crash.
TEST(Value, FromBadUtf8) {
prepare();
JSGlobalContextRef ctx = JSC_JSGlobalContextCreateInGroup(false, nullptr, nullptr);
// 110xxxxx 10xxxxxx
auto dyn = folly::dynamic("\xC0");
Value::fromDynamic(ctx, dyn);
dyn = folly::dynamic("\xC0\x00");
Value::fromDynamic(ctx, dyn);
// 1110xxxx 10xxxxxx 10xxxxxx
dyn = "\xE0";
Value::fromDynamic(ctx, dyn);
Value(ctx, Value::fromDynamic(ctx, dyn)).toJSONString();
dyn = "\xE0\x00";
Value::fromDynamic(ctx, dyn);
Value(ctx, Value::fromDynamic(ctx, dyn)).toJSONString();
dyn = "\xE0\x00\x00";
Value::fromDynamic(ctx, dyn);
Value(ctx, Value::fromDynamic(ctx, dyn)).toJSONString();
dyn = "\xE0\xA0\x00";
Value::fromDynamic(ctx, dyn);
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
dyn = "\xF0";
Value::fromDynamic(ctx, dyn);
Value(ctx, Value::fromDynamic(ctx, dyn)).toJSONString();
dyn = "\xF0\x00\x00\x00";
Value::fromDynamic(ctx, dyn);
dyn = "\xF0\x80\x80\x00";
Value::fromDynamic(ctx, dyn);
Value(ctx, Value::fromDynamic(ctx, dyn)).toJSONString();
JSC_JSGlobalContextRelease(ctx);
}
// Just test that handling invalid data doesn't crash.
TEST(Value, BadUtf16) {
prepare();
JSGlobalContextRef ctx = JSC_JSGlobalContextCreateInGroup(false, nullptr, nullptr);
UChar buf[] = { 0xDD00, 0xDD00, 0xDD00, 0x1111 };
JSStringRef ref = OpaqueJSString::create(buf, 4).leakRef();
Value v(ctx, ref);
v.toJSONString(0);
JSC_JSGlobalContextRelease(ctx);
}
#endif