first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#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&) {
FAIL() << "Recovered exception that should have fallen through";
} catch (const std::exception& err) {
ASSERT_STREQ(err.what(), "catch me");
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <cxxreact/JsArgumentHelpers.h>
#include <folly/dynamic.h>
#include <gtest/gtest.h>
#include <algorithm>
using namespace facebook::xplat;
using dynamic = folly::dynamic;
#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 std::string aString = "word";
const dynamic anArray = dynamic::array("a", "b", "c");
const dynamic anObject = dynamic::object("k1", "v1")("k2", "v2");
const std::string aNumericString = std::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,82 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <fcntl.h>
#include <sys/mman.h>
#include <cxxreact/JSBigString.h>
#include <gtest/gtest.h>
using namespace facebook::react;
namespace {
int tempFileFromString(const std::string& contents) {
const char* tmpDir = getenv("TMPDIR");
if (tmpDir == nullptr) {
tmpDir = "/tmp";
}
std::string tmp{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;
}
}; // namespace
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
EXPECT_EQ(needle.length(), bigStr.size());
for (unsigned int i = 0; i < needle.length(); ++i) {
EXPECT_EQ(needle[i], bigStr.c_str()[i]);
}
}
TEST(JSBigFileString, MapPartAtLargeOffsetTest) {
std::string data(8 * 4096, 'X');
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
EXPECT_EQ(needle.length(), bigStr.size());
for (unsigned int i = 0; i < needle.length(); ++i) {
EXPECT_EQ(needle[i], bigStr.c_str()[i]);
}
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#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::react;
using dynamic = folly::dynamic;
TEST(parseMethodCalls, SingleReturnCallNoArgs) {
auto jsText = "[[7],[3],[[]]]";
auto returnedCalls = parseMethodCalls(folly::parseJson(jsText));
EXPECT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
EXPECT_EQ(0, returnedCall.arguments.size());
EXPECT_EQ(7, returnedCall.moduleId);
EXPECT_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));
EXPECT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
EXPECT_EQ(1, returnedCall.arguments.size());
EXPECT_EQ(folly::dynamic::STRING, returnedCall.arguments[0].type());
EXPECT_EQ("foobar", returnedCall.arguments[0].asString());
}
TEST(parseMethodCalls, StringReturn) {
auto jsText = "[[0],[0],[[42.16]]]";
auto returnedCalls = parseMethodCalls(folly::parseJson(jsText));
EXPECT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
EXPECT_EQ(1, returnedCall.arguments.size());
EXPECT_EQ(folly::dynamic::DOUBLE, returnedCall.arguments[0].type());
EXPECT_EQ(42.16, returnedCall.arguments[0].asDouble());
}
TEST(parseMethodCalls, BooleanReturn) {
auto jsText = "[[0],[0],[[false]]]";
auto returnedCalls = parseMethodCalls(folly::parseJson(jsText));
EXPECT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
EXPECT_EQ(1, returnedCall.arguments.size());
EXPECT_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));
EXPECT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
EXPECT_EQ(1, returnedCall.arguments.size());
EXPECT_EQ(folly::dynamic::NULLT, returnedCall.arguments[0].type());
}
TEST(parseMethodCalls, MapReturn) {
auto jsText = R"([[0],[0],[[{"foo": "hello", "bar": 4.0, "baz": true}]]])";
auto returnedCalls = parseMethodCalls(folly::parseJson(jsText));
EXPECT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
EXPECT_EQ(1, returnedCall.arguments.size());
EXPECT_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));
EXPECT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
EXPECT_EQ(1, returnedCall.arguments.size());
EXPECT_EQ(folly::dynamic::ARRAY, returnedCall.arguments[0].type());
auto& returnedArray = returnedCall.arguments[0];
EXPECT_EQ(3, returnedArray.size());
EXPECT_EQ(folly::dynamic("foo"), returnedArray[0]);
EXPECT_EQ(folly::dynamic(42.0), returnedArray[1]);
EXPECT_EQ(folly::dynamic(false), returnedArray[2]);
}
TEST(parseMethodCalls, ReturnMultipleParams) {
auto jsText = "[[0],[0],[[\"foo\", 14, null, false]]]";
auto returnedCalls = parseMethodCalls(folly::parseJson(jsText));
EXPECT_EQ(1, returnedCalls.size());
auto returnedCall = returnedCalls[0];
EXPECT_EQ(4, returnedCall.arguments.size());
EXPECT_EQ(folly::dynamic::STRING, returnedCall.arguments[0].type());
EXPECT_EQ(folly::dynamic::INT64, returnedCall.arguments[1].type());
EXPECT_EQ(folly::dynamic::NULLT, returnedCall.arguments[2].type());
EXPECT_EQ(folly::dynamic::BOOL, returnedCall.arguments[3].type());
}
TEST(parseMethodCalls, ParseTwoCalls) {
auto jsText = "[[0,0],[1,1],[[],[]]]";
auto returnedCalls = parseMethodCalls(folly::parseJson(jsText));
EXPECT_EQ(2, returnedCalls.size());
}