Skip to content

Commit 64341fe

Browse files
DevmateUtgenCppGeneralFBOrg Botfacebook-github-bot
authored andcommitted
xplat/js/react-native-github/packages/react-native/ReactCommon/jsi/jsi/JSIDynamic.cpp
Reviewed By: christophpurrer Differential Revision: D121160587
1 parent 5880e42 commit 64341fe

1 file changed

Lines changed: 133 additions & 0 deletions

File tree

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include <jsi/JSIDynamic.h>
9+
10+
#include <gtest/gtest.h>
11+
#include <jsi/test/testlib.h>
12+
13+
using namespace facebook::jsi;
14+
15+
class JSIDynamicTest : public JSITestBase {};
16+
17+
TEST_P(JSIDynamicTest, testValueFromDynamicConvertsNestedCollections) {
18+
folly::dynamic input = folly::dynamic::object("nullValue", nullptr)(
19+
"enabled", true)("count", 42)("ratio", 1.5)(
20+
"children",
21+
folly::dynamic::array(
22+
folly::dynamic::object("name", "first")(
23+
"values", folly::dynamic::array(3, 5)),
24+
folly::dynamic::object("name", "second")("active", false)))(
25+
"metadata",
26+
folly::dynamic::object(7, "numeric key")(false, "unsupported key"));
27+
28+
Object result = valueFromDynamic(rt, input).getObject(rt);
29+
30+
EXPECT_TRUE(result.getProperty(rt, "nullValue").isNull());
31+
EXPECT_TRUE(result.getProperty(rt, "enabled").getBool());
32+
EXPECT_EQ(result.getProperty(rt, "count").getNumber(), 42);
33+
EXPECT_EQ(result.getProperty(rt, "ratio").getNumber(), 1.5);
34+
35+
Array children = result.getPropertyAsObject(rt, "children").getArray(rt);
36+
ASSERT_EQ(children.size(rt), 2);
37+
Object first = children.getValueAtIndex(rt, 0).getObject(rt);
38+
EXPECT_EQ(first.getProperty(rt, "name").getString(rt).utf8(rt), "first");
39+
Array values = first.getPropertyAsObject(rt, "values").getArray(rt);
40+
ASSERT_EQ(values.size(rt), 2);
41+
EXPECT_EQ(values.getValueAtIndex(rt, 0).getNumber(), 3);
42+
EXPECT_EQ(values.getValueAtIndex(rt, 1).getNumber(), 5);
43+
44+
Object second = children.getValueAtIndex(rt, 1).getObject(rt);
45+
EXPECT_EQ(second.getProperty(rt, "name").getString(rt).utf8(rt), "second");
46+
EXPECT_FALSE(second.getProperty(rt, "active").getBool());
47+
48+
Object metadata = result.getPropertyAsObject(rt, "metadata");
49+
EXPECT_EQ(
50+
metadata.getProperty(rt, "7").getString(rt).utf8(rt), "numeric key");
51+
EXPECT_EQ(metadata.getPropertyNames(rt).size(rt), 1);
52+
}
53+
54+
TEST_P(JSIDynamicTest, testDynamicFromValueConvertsNestedCollections) {
55+
Value input = eval(
56+
"({left: [{id: 1}, {id: 2}], "
57+
"right: {enabled: true, label: 'ready'}, value: 2.25})");
58+
folly::dynamic expected = folly::dynamic::object(
59+
"left",
60+
folly::dynamic::array(
61+
folly::dynamic::object("id", 1.0),
62+
folly::dynamic::object("id", 2.0)))(
63+
"right", folly::dynamic::object("enabled", true)("label", "ready"))(
64+
"value", 2.25);
65+
66+
folly::dynamic result = dynamicFromValue(rt, input);
67+
68+
EXPECT_EQ(result, expected);
69+
}
70+
71+
TEST_P(JSIDynamicTest, testDynamicFromValueNormalizesAndFiltersProperties) {
72+
Value input = eval(
73+
"({keep: 7, drop: 8, missing: undefined, "
74+
"callback: function() {}, items: [undefined, 'ok']})");
75+
folly::dynamic expected = folly::dynamic::object("keep", 7.0)(
76+
"callback", nullptr)("items", folly::dynamic::array(nullptr, "ok"));
77+
78+
folly::dynamic result = dynamicFromValue(
79+
rt, input, [](const std::string& key) { return key == "drop"; });
80+
81+
EXPECT_EQ(result, expected);
82+
}
83+
84+
TEST_P(JSIDynamicTest, testDynamicFromValueRejectsUnsupportedValues) {
85+
auto expectConversionError = [&](const char* expression,
86+
const char* expectedMessage) {
87+
try {
88+
dynamicFromValue(rt, eval(expression));
89+
FAIL() << "Expected conversion to throw for " << expression;
90+
} catch (const JSError& error) {
91+
EXPECT_NE(
92+
std::string(error.what()).find(expectedMessage), std::string::npos)
93+
<< error.what();
94+
}
95+
};
96+
97+
expectConversionError(
98+
"(function() {})", "JS Functions are not convertible to dynamic");
99+
expectConversionError("1n", "JS BigInts are not convertible to dynamic");
100+
expectConversionError(
101+
"Symbol('token')", "JS Symbols are not convertible to dynamic");
102+
}
103+
104+
TEST_P(JSIDynamicTest, testDynamicFromValueHandlesDeeplyNestedObjects) {
105+
constexpr size_t kDepth = 25000;
106+
std::string expression =
107+
"(function() { let head = {}; let node = head; "
108+
"for (let i = 0; i < " +
109+
std::to_string(kDepth) +
110+
"; ++i) { node.next = {}; node = node.next; } "
111+
"node.value = true; return head; })()";
112+
113+
folly::dynamic result = dynamicFromValue(rt, eval(expression.c_str()));
114+
115+
folly::dynamic* current = &result;
116+
size_t depth = 0;
117+
while (folly::dynamic* next = current->get_ptr("next")) {
118+
current = next;
119+
++depth;
120+
}
121+
EXPECT_EQ(depth, kDepth);
122+
EXPECT_TRUE((*current)["value"].getBool());
123+
124+
while (folly::dynamic* next = result.get_ptr("next")) {
125+
folly::dynamic child = std::move(*next);
126+
result = std::move(child);
127+
}
128+
}
129+
130+
INSTANTIATE_TEST_SUITE_P(
131+
Runtimes,
132+
JSIDynamicTest,
133+
::testing::ValuesIn(runtimeGenerators()));

0 commit comments

Comments
 (0)