Skip to content

Commit 35d3333

Browse files
rubennortekosmydel
authored andcommitted
Add test for LazyShadowTreeRevisionConsistencyManager and fix bugs
Summary: Changelog: [internal] `LazyShadowTreeRevisionConsistencyManager` wasn't correctly updating the locked revision, because `emplace` is a no-op if there's already a value for the key in the `unordered_map`. This fixes the issue and adds tests that actually showed it. Reviewed By: sammy-SC Differential Revision: D56761941 fbshipit-source-id: 340e9195b14460a591c48186bd365688c74ade04
1 parent ef88139 commit 35d3333

File tree

2 files changed

+306
-3
lines changed

2 files changed

+306
-3
lines changed

packages/react-native/ReactCommon/react/renderer/uimanager/consistency/LazyShadowTreeRevisionConsistencyManager.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ LazyShadowTreeRevisionConsistencyManager::
1818
void LazyShadowTreeRevisionConsistencyManager::updateCurrentRevision(
1919
SurfaceId surfaceId,
2020
RootShadowNode::Shared rootShadowNode) {
21-
capturedRootShadowNodesForConsistency_.emplace(
22-
surfaceId, std::move(rootShadowNode));
21+
capturedRootShadowNodesForConsistency_[surfaceId] = std::move(rootShadowNode);
2322
}
2423

2524
#pragma mark - ShadowTreeRevisionProvider
@@ -38,7 +37,7 @@ LazyShadowTreeRevisionConsistencyManager::getCurrentRevision(
3837
rootShadowNode = shadowTree.getCurrentRevision().rootShadowNode;
3938
});
4039

41-
capturedRootShadowNodesForConsistency_.emplace(surfaceId, rootShadowNode);
40+
capturedRootShadowNodesForConsistency_[surfaceId] = rootShadowNode;
4241

4342
return rootShadowNode;
4443
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
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 <gtest/gtest.h>
9+
#include <react/renderer/components/root/RootShadowNode.h>
10+
#include <react/renderer/element/testUtils.h>
11+
#include <react/renderer/mounting/ShadowTree.h>
12+
#include <react/renderer/mounting/ShadowTreeRegistry.h>
13+
#include <react/renderer/uimanager/consistency/LazyShadowTreeRevisionConsistencyManager.h>
14+
15+
namespace facebook::react {
16+
17+
class FakeShadowTreeDelegate : public ShadowTreeDelegate {
18+
public:
19+
RootShadowNode::Unshared shadowTreeWillCommit(
20+
const ShadowTree& /*shadowTree*/,
21+
const RootShadowNode::Shared& /*oldRootShadowNode*/,
22+
const RootShadowNode::Unshared& newRootShadowNode) const override {
23+
return newRootShadowNode;
24+
};
25+
26+
void shadowTreeDidFinishTransaction(
27+
MountingCoordinator::Shared mountingCoordinator,
28+
bool mountSynchronously) const override {};
29+
};
30+
31+
class LazyShadowTreeRevisionConsistencyManagerTest : public ::testing::Test {
32+
public:
33+
LazyShadowTreeRevisionConsistencyManagerTest()
34+
: consistencyManager_(shadowTreeRegistry_) {}
35+
36+
void TearDown() override {
37+
// this is necessary because otherwise the test will crash with an assertion
38+
// preventing the deallocation of the registry with registered shadow trees.
39+
auto ids = std::vector<SurfaceId>();
40+
41+
shadowTreeRegistry_.enumerate(
42+
[&ids](const ShadowTree& shadowTree, bool& /*stop*/) {
43+
ids.push_back(shadowTree.getSurfaceId());
44+
});
45+
46+
for (auto id : ids) {
47+
shadowTreeRegistry_.remove(id);
48+
}
49+
}
50+
51+
std::unique_ptr<ShadowTree> createShadowTree(SurfaceId surfaceId) {
52+
return std::make_unique<ShadowTree>(
53+
surfaceId,
54+
layoutConstraints_,
55+
layoutContext_,
56+
shadowTreeDelegate_,
57+
contextContainer_);
58+
}
59+
60+
ShadowTreeRegistry shadowTreeRegistry_{};
61+
LazyShadowTreeRevisionConsistencyManager consistencyManager_;
62+
63+
LayoutConstraints layoutConstraints_{};
64+
LayoutContext layoutContext_{};
65+
FakeShadowTreeDelegate shadowTreeDelegate_{};
66+
ContextContainer contextContainer_{};
67+
};
68+
69+
TEST_F(LazyShadowTreeRevisionConsistencyManagerTest, testLockedOnNoRevision) {
70+
consistencyManager_.lockRevisions();
71+
72+
EXPECT_EQ(consistencyManager_.getCurrentRevision(0), nullptr);
73+
74+
shadowTreeRegistry_.add(createShadowTree(0));
75+
76+
EXPECT_EQ(consistencyManager_.getCurrentRevision(0), nullptr);
77+
78+
auto element = Element<RootShadowNode>();
79+
auto builder = simpleComponentBuilder();
80+
auto newRootShadowNode = builder.build(element);
81+
82+
shadowTreeRegistry_.visit(
83+
0, [newRootShadowNode](const ShadowTree& shadowTree) {
84+
shadowTree.commit(
85+
[&](const RootShadowNode& /*oldRootShadowNode*/) {
86+
return newRootShadowNode;
87+
},
88+
{});
89+
});
90+
91+
EXPECT_EQ(consistencyManager_.getCurrentRevision(0), nullptr);
92+
93+
consistencyManager_.unlockRevisions();
94+
}
95+
96+
TEST_F(
97+
LazyShadowTreeRevisionConsistencyManagerTest,
98+
testLockedOnNoRevisionWithUpdate) {
99+
consistencyManager_.lockRevisions();
100+
101+
EXPECT_EQ(consistencyManager_.getCurrentRevision(0), nullptr);
102+
103+
shadowTreeRegistry_.add(createShadowTree(0));
104+
105+
EXPECT_EQ(consistencyManager_.getCurrentRevision(0), nullptr);
106+
107+
auto element = Element<RootShadowNode>();
108+
auto builder = simpleComponentBuilder();
109+
auto newRootShadowNode = builder.build(element);
110+
111+
shadowTreeRegistry_.visit(
112+
0, [newRootShadowNode](const ShadowTree& shadowTree) {
113+
shadowTree.commit(
114+
[&](const RootShadowNode& /*oldRootShadowNode*/) {
115+
return newRootShadowNode;
116+
},
117+
{});
118+
});
119+
120+
EXPECT_EQ(consistencyManager_.getCurrentRevision(0), nullptr);
121+
122+
consistencyManager_.updateCurrentRevision(0, newRootShadowNode);
123+
124+
EXPECT_NE(consistencyManager_.getCurrentRevision(0), nullptr);
125+
EXPECT_EQ(
126+
consistencyManager_.getCurrentRevision(0).get(), newRootShadowNode.get());
127+
128+
consistencyManager_.unlockRevisions();
129+
}
130+
131+
TEST_F(
132+
LazyShadowTreeRevisionConsistencyManagerTest,
133+
testLockedOnNoRevisionWithMultipleUpdates) {
134+
consistencyManager_.lockRevisions();
135+
136+
EXPECT_EQ(consistencyManager_.getCurrentRevision(0), nullptr);
137+
138+
shadowTreeRegistry_.add(createShadowTree(0));
139+
140+
EXPECT_EQ(consistencyManager_.getCurrentRevision(0), nullptr);
141+
142+
auto element = Element<RootShadowNode>();
143+
auto builder = simpleComponentBuilder();
144+
auto newRootShadowNode = builder.build(element);
145+
146+
shadowTreeRegistry_.visit(
147+
0, [newRootShadowNode](const ShadowTree& shadowTree) {
148+
shadowTree.commit(
149+
[&](const RootShadowNode& /*oldRootShadowNode*/) {
150+
return newRootShadowNode;
151+
},
152+
{});
153+
});
154+
155+
EXPECT_EQ(consistencyManager_.getCurrentRevision(0), nullptr);
156+
157+
consistencyManager_.updateCurrentRevision(0, newRootShadowNode);
158+
159+
EXPECT_EQ(
160+
consistencyManager_.getCurrentRevision(0).get(), newRootShadowNode.get());
161+
162+
auto newRootShadowNode2 = builder.build(element);
163+
164+
shadowTreeRegistry_.visit(
165+
0, [newRootShadowNode2](const ShadowTree& shadowTree) {
166+
shadowTree.commit(
167+
[&](const RootShadowNode& /*oldRootShadowNode*/) {
168+
return newRootShadowNode2;
169+
},
170+
{});
171+
});
172+
173+
consistencyManager_.updateCurrentRevision(0, newRootShadowNode2);
174+
175+
EXPECT_EQ(
176+
consistencyManager_.getCurrentRevision(0).get(),
177+
newRootShadowNode2.get());
178+
179+
consistencyManager_.unlockRevisions();
180+
}
181+
182+
TEST_F(
183+
LazyShadowTreeRevisionConsistencyManagerTest,
184+
testLockedOnExistingRevision) {
185+
shadowTreeRegistry_.add(createShadowTree(0));
186+
187+
auto element = Element<RootShadowNode>();
188+
auto builder = simpleComponentBuilder();
189+
auto newRootShadowNode = builder.build(element);
190+
191+
shadowTreeRegistry_.visit(
192+
0, [newRootShadowNode](const ShadowTree& shadowTree) {
193+
shadowTree.commit(
194+
[&](const RootShadowNode& /*oldRootShadowNode*/) {
195+
return newRootShadowNode;
196+
},
197+
{});
198+
});
199+
200+
consistencyManager_.lockRevisions();
201+
202+
EXPECT_EQ(
203+
consistencyManager_.getCurrentRevision(0).get(), newRootShadowNode.get());
204+
205+
consistencyManager_.unlockRevisions();
206+
}
207+
208+
TEST_F(
209+
LazyShadowTreeRevisionConsistencyManagerTest,
210+
testLockedOnExistingRevisionWithUpdates) {
211+
shadowTreeRegistry_.add(createShadowTree(0));
212+
213+
auto element = Element<RootShadowNode>();
214+
auto builder = simpleComponentBuilder();
215+
auto newRootShadowNode = builder.build(element);
216+
217+
shadowTreeRegistry_.visit(
218+
0, [newRootShadowNode](const ShadowTree& shadowTree) {
219+
shadowTree.commit(
220+
[&](const RootShadowNode& /*oldRootShadowNode*/) {
221+
return newRootShadowNode;
222+
},
223+
{});
224+
});
225+
226+
consistencyManager_.lockRevisions();
227+
228+
EXPECT_EQ(
229+
consistencyManager_.getCurrentRevision(0).get(), newRootShadowNode.get());
230+
231+
auto newRootShadowNode2 = builder.build(element);
232+
233+
shadowTreeRegistry_.visit(
234+
0, [newRootShadowNode2](const ShadowTree& shadowTree) {
235+
shadowTree.commit(
236+
[&](const RootShadowNode& /*oldRootShadowNode*/) {
237+
return newRootShadowNode2;
238+
},
239+
{});
240+
});
241+
242+
// Not updated
243+
EXPECT_EQ(
244+
consistencyManager_.getCurrentRevision(0).get(), newRootShadowNode.get());
245+
246+
consistencyManager_.updateCurrentRevision(0, newRootShadowNode2);
247+
248+
// Updated
249+
EXPECT_EQ(
250+
consistencyManager_.getCurrentRevision(0).get(),
251+
newRootShadowNode2.get());
252+
253+
consistencyManager_.unlockRevisions();
254+
}
255+
256+
TEST_F(LazyShadowTreeRevisionConsistencyManagerTest, testLockAfterUnlock) {
257+
shadowTreeRegistry_.add(createShadowTree(0));
258+
259+
auto element = Element<RootShadowNode>();
260+
auto builder = simpleComponentBuilder();
261+
auto newRootShadowNode = builder.build(element);
262+
263+
shadowTreeRegistry_.visit(
264+
0, [newRootShadowNode](const ShadowTree& shadowTree) {
265+
shadowTree.commit(
266+
[&](const RootShadowNode& /*oldRootShadowNode*/) {
267+
return newRootShadowNode;
268+
},
269+
{});
270+
});
271+
272+
consistencyManager_.lockRevisions();
273+
274+
EXPECT_EQ(
275+
consistencyManager_.getCurrentRevision(0).get(), newRootShadowNode.get());
276+
277+
auto newRootShadowNode2 = builder.build(element);
278+
279+
shadowTreeRegistry_.visit(
280+
0, [newRootShadowNode2](const ShadowTree& shadowTree) {
281+
shadowTree.commit(
282+
[&](const RootShadowNode& /*oldRootShadowNode*/) {
283+
return newRootShadowNode2;
284+
},
285+
{});
286+
});
287+
288+
// Not updated
289+
EXPECT_EQ(
290+
consistencyManager_.getCurrentRevision(0).get(), newRootShadowNode.get());
291+
292+
consistencyManager_.unlockRevisions();
293+
294+
consistencyManager_.lockRevisions();
295+
296+
// Updated
297+
EXPECT_EQ(
298+
consistencyManager_.getCurrentRevision(0).get(),
299+
newRootShadowNode2.get());
300+
301+
consistencyManager_.unlockRevisions();
302+
}
303+
304+
} // namespace facebook::react

0 commit comments

Comments
 (0)