Files
react-native/ReactCommon/react/renderer/mounting/tests/StateReconciliationTest.cpp
T
Joshua Gross 39b8233c93 Copy Differ implementation to new file, feature-flag-gate new differ
Summary:
Changes in following diffs will be gated by this feature flag.

The differ in the new file is copied from the current stable implementation and will not be modified until it's deleted.

Changelog: [Internal]

Reviewed By: sammy-SC, mdvacca

Differential Revision: D27775698

fbshipit-source-id: 03d9518ffd2b1f25712386c56a38bd2b4d839fc2
2021-04-14 19:50:09 -07:00

178 lines
5.8 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <memory>
#include <gtest/gtest.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/components/view/ViewComponentDescriptor.h>
#include <react/renderer/element/ComponentBuilder.h>
#include <react/renderer/element/Element.h>
#include <react/renderer/element/testUtils.h>
#include <react/renderer/mounting/MountingCoordinator.h>
#include <react/renderer/mounting/ShadowTree.h>
#include <react/renderer/mounting/ShadowTreeDelegate.h>
using namespace facebook::react;
class DummyShadowTreeDelegate : public ShadowTreeDelegate {
public:
virtual RootShadowNode::Unshared shadowTreeWillCommit(
ShadowTree const &shadowTree,
RootShadowNode::Shared const &oldRootShadowNode,
RootShadowNode::Unshared const &newRootShadowNode) const override {
return newRootShadowNode;
};
virtual void shadowTreeDidFinishTransaction(
ShadowTree const &shadowTree,
MountingCoordinator::Shared const &mountingCoordinator) const override{};
};
inline ShadowNode const *findDescendantNode(
ShadowNode const &shadowNode,
ShadowNodeFamily const &family) {
ShadowNode const *result = nullptr;
shadowNode.cloneTree(family, [&](ShadowNode const &oldShadowNode) {
result = &oldShadowNode;
return oldShadowNode.clone({});
});
return result;
}
inline ShadowNode const *findDescendantNode(
ShadowTree const &shadowTree,
ShadowNodeFamily const &family) {
return findDescendantNode(
*shadowTree.getCurrentRevision().rootShadowNode, family);
}
TEST(StateReconciliationTest, testStateReconciliation) {
auto builder = simpleComponentBuilder();
auto shadowNodeA = std::shared_ptr<RootShadowNode>{};
auto shadowNodeAA = std::shared_ptr<ViewShadowNode>{};
auto shadowNodeAB = std::shared_ptr<ScrollViewShadowNode>{};
auto shadowNodeABA = std::shared_ptr<ViewShadowNode>{};
auto shadowNodeABB = std::shared_ptr<ViewShadowNode>{};
auto shadowNodeABC = std::shared_ptr<ViewShadowNode>{};
// clang-format off
auto element =
Element<RootShadowNode>()
.reference(shadowNodeA)
.finalize([](RootShadowNode &shadowNode){
shadowNode.sealRecursive();
})
.children({
Element<ViewShadowNode>()
.reference(shadowNodeAA),
Element<ScrollViewShadowNode>()
.reference(shadowNodeAB)
.children({
Element<ViewShadowNode>()
.children({
Element<ViewShadowNode>()
.reference(shadowNodeABA),
Element<ViewShadowNode>()
.reference(shadowNodeABB),
Element<ViewShadowNode>()
.reference(shadowNodeABC)
})
})
});
// clang-format on
auto shadowNode = builder.build(element);
auto rootShadowNodeState1 = shadowNode->ShadowNode::clone({});
auto &scrollViewComponentDescriptor = shadowNodeAB->getComponentDescriptor();
auto &family = shadowNodeAB->getFamily();
auto state1 = shadowNodeAB->getState();
auto shadowTreeDelegate = DummyShadowTreeDelegate{};
ShadowTree shadowTree{
SurfaceId{11},
LayoutConstraints{},
LayoutContext{},
shadowTreeDelegate,
true};
shadowTree.commit(
[&](RootShadowNode const &oldRootShadowNode) {
return std::static_pointer_cast<RootShadowNode>(rootShadowNodeState1);
},
{true});
EXPECT_EQ(state1->getMostRecentState(), state1);
EXPECT_EQ(
findDescendantNode(*rootShadowNodeState1, family)->getState(), state1);
auto state2 = scrollViewComponentDescriptor.createState(
family, std::make_shared<ScrollViewState const>());
auto rootShadowNodeState2 =
shadowNode->cloneTree(family, [&](ShadowNode const &oldShadowNode) {
return oldShadowNode.clone(
{ShadowNodeFragment::propsPlaceholder(),
ShadowNodeFragment::childrenPlaceholder(),
state2});
});
EXPECT_EQ(
findDescendantNode(*rootShadowNodeState2, family)->getState(), state2);
shadowTree.commit(
[&](RootShadowNode const &oldRootShadowNode) {
return std::static_pointer_cast<RootShadowNode>(rootShadowNodeState2);
},
{true});
EXPECT_EQ(state1->getMostRecentState(), state2);
EXPECT_EQ(state2->getMostRecentState(), state2);
auto state3 = scrollViewComponentDescriptor.createState(
family, std::make_shared<ScrollViewState const>());
auto rootShadowNodeState3 = rootShadowNodeState2->cloneTree(
family, [&](ShadowNode const &oldShadowNode) {
return oldShadowNode.clone(
{ShadowNodeFragment::propsPlaceholder(),
ShadowNodeFragment::childrenPlaceholder(),
state3});
});
EXPECT_EQ(
findDescendantNode(*rootShadowNodeState3, family)->getState(), state3);
shadowTree.commit(
[&](RootShadowNode const &oldRootShadowNode) {
return std::static_pointer_cast<RootShadowNode>(rootShadowNodeState3);
},
{true});
EXPECT_EQ(findDescendantNode(shadowTree, family)->getState(), state3);
EXPECT_EQ(state1->getMostRecentState(), state3);
EXPECT_EQ(state2->getMostRecentState(), state3);
EXPECT_EQ(state3->getMostRecentState(), state3);
// This is the core part of the whole test.
// Here we commit the old tree but we expect that the state associated with
// the node will stay the same (newer that the old tree has).
shadowTree.commit(
[&](RootShadowNode const &oldRootShadowNode) {
return std::static_pointer_cast<RootShadowNode>(rootShadowNodeState2);
},
{true});
EXPECT_EQ(findDescendantNode(shadowTree, family)->getState(), state3);
}