Files
react-native/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp
Valentin Shergin dd3a6eda70 Fabric: Devirtualizing of props parsing infra
Summary:
This diff contains several tight to each other changes (which can/should not be split into several diffs):
 * The props parsing/conversion process was de-virtualized: we don't use virtual `apply` method to parse props anymore. Instead, we use old-fashioned constructors.
 * All fields of Props classes which represent props values were marked as `const` which make impossible to modify them after the objects were created (even if we have non-const value-of/pointer-to the whole Props object). Those fields are also `public` now.
 * All custom handwritten getters were removed (because we don't need them anymore).

So, now we don't need all those custom getters which makes code much more compact, performant and codegen-friendly.

Reviewed By: fkgozali

Differential Revision: D7901245

fbshipit-source-id: 9f4b1fd2da64bf963b63215ed3bd74b9d3c58dd5
2018-05-14 16:03:49 -07:00

181 lines
6.2 KiB
C++

/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* 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 <fabric/core/ConcreteShadowNode.h>
#include <fabric/core/ShadowNode.h>
#include <gtest/gtest.h>
#include "TestComponent.h"
using namespace facebook::react;
TEST(ShadowNodeTest, handleProps) {
RawProps raw;
raw["nativeID"] = "abc";
auto props = std::make_shared<Props>(Props(), raw);
// Props are not sealed after applying raw props.
ASSERT_FALSE(props->getSealed());
ASSERT_STREQ(props->nativeId.c_str(), "abc");
}
TEST(ShadowNodeTest, handleShadowNodeCreation) {
auto node = std::make_shared<TestShadowNode>(9, 1, (void *)NULL);
ASSERT_FALSE(node->getSealed());
ASSERT_STREQ(node->getComponentName().c_str(), "Test");
ASSERT_EQ(node->getTag(), 9);
ASSERT_EQ(node->getRootTag(), 1);
ASSERT_EQ(node->getInstanceHandle(), (void *)NULL);
TestShadowNode *nodePtr = node.get();
ASSERT_EQ(node->getComponentHandle(), typeid(*nodePtr).hash_code());
ASSERT_EQ(node->getSourceNode(), nullptr);
ASSERT_EQ(node->getChildren()->size(), 0);
ASSERT_STREQ(node->getProps()->nativeId.c_str(), "testNativeID");
node->sealRecursive();
ASSERT_TRUE(node->getSealed());
ASSERT_TRUE(node->getProps()->getSealed());
}
TEST(ShadowNodeTest, handleShadowNodeSimpleCloning) {
auto node = std::make_shared<TestShadowNode>(9, 1, (void *)NULL);
auto node2 = std::make_shared<TestShadowNode>(node);
ASSERT_STREQ(node->getComponentName().c_str(), "Test");
ASSERT_EQ(node->getTag(), 9);
ASSERT_EQ(node->getRootTag(), 1);
ASSERT_EQ(node->getInstanceHandle(), (void *)NULL);
ASSERT_EQ(node2->getSourceNode(), node);
}
TEST(ShadowNodeTest, handleShadowNodeMutation) {
auto node1 = std::make_shared<TestShadowNode>(1, 1, (void *)NULL);
auto node2 = std::make_shared<TestShadowNode>(2, 1, (void *)NULL);
auto node3 = std::make_shared<TestShadowNode>(3, 1, (void *)NULL);
node1->appendChild(node2);
node1->appendChild(node3);
SharedShadowNodeSharedList node1Children = node1->getChildren();
ASSERT_EQ(node1Children->size(), 2);
ASSERT_EQ(node1Children->at(0), node2);
ASSERT_EQ(node1Children->at(1), node3);
auto node4 = std::make_shared<TestShadowNode>(node2);
node1->replaceChild(node2, node4);
node1Children = node1->getChildren();
ASSERT_EQ(node1Children->size(), 2);
ASSERT_EQ(node1Children->at(0), node4);
ASSERT_EQ(node1Children->at(1), node3);
// Seal the entire tree.
node1->sealRecursive();
ASSERT_TRUE(node1->getSealed());
ASSERT_TRUE(node3->getSealed());
ASSERT_TRUE(node4->getSealed());
// No more mutation after sealing.
EXPECT_THROW(node4->clearSourceNode(), std::runtime_error);
auto node5 = std::make_shared<TestShadowNode>(node4);
node5->clearSourceNode();
ASSERT_EQ(node5->getSourceNode(), nullptr);
}
TEST(ShadowNodeTest, handleSourceNode) {
auto nodeFirstGeneration = std::make_shared<TestShadowNode>(9, 1, (void *)NULL);
auto nodeSecondGeneration = std::make_shared<TestShadowNode>(nodeFirstGeneration);
auto nodeThirdGeneration = std::make_shared<TestShadowNode>(nodeSecondGeneration);
auto nodeForthGeneration = std::make_shared<TestShadowNode>(nodeThirdGeneration);
// Ensure established shource nodes structure.
ASSERT_EQ(nodeForthGeneration->getSourceNode(), nodeThirdGeneration);
ASSERT_EQ(nodeThirdGeneration->getSourceNode(), nodeSecondGeneration);
ASSERT_EQ(nodeSecondGeneration->getSourceNode(), nodeFirstGeneration);
// Shallow source node for the forth generation node.
nodeForthGeneration->shallowSourceNode();
ASSERT_EQ(nodeForthGeneration->getSourceNode(), nodeSecondGeneration);
// Shallow it one more time.
nodeForthGeneration->shallowSourceNode();
ASSERT_EQ(nodeForthGeneration->getSourceNode(), nodeFirstGeneration);
// Ensure that 3th and 2nd were not affected.
ASSERT_EQ(nodeThirdGeneration->getSourceNode(), nodeSecondGeneration);
ASSERT_EQ(nodeSecondGeneration->getSourceNode(), nodeFirstGeneration);
}
TEST(ShadowNodeTest, handleCloneFunction) {
auto firstNode = std::make_shared<TestShadowNode>(9, 1, (void *)NULL);
// The shadow node is not clonable if `cloneFunction` is not provided,
ASSERT_DEATH_IF_SUPPORTED(firstNode->clone(), "cloneFunction_");
auto secondNode = std::make_shared<TestShadowNode>(
9,
1,
(void *)NULL,
std::make_shared<const TestProps>(),
ShadowNode::emptySharedShadowNodeSharedList(),
[](const SharedShadowNode &shadowNode, const SharedProps &props, const SharedShadowNodeSharedList &children) {
return std::make_shared<const TestShadowNode>(
std::static_pointer_cast<const TestShadowNode>(shadowNode),
props,
children
);
}
);
auto secondNodeClone = secondNode->clone();
// Those two nodes are *not* same.
ASSERT_NE(secondNode, secondNodeClone);
// `secondNodeClone` is an instance of `TestShadowNode`.
ASSERT_NE(std::dynamic_pointer_cast<const TestShadowNode>(secondNodeClone), nullptr);
// Both nodes have same content.
ASSERT_EQ(secondNode->getTag(), secondNodeClone->getTag());
ASSERT_EQ(secondNode->getRootTag(), secondNodeClone->getRootTag());
ASSERT_EQ(secondNode->getProps(), secondNodeClone->getProps());
}
TEST(ShadowNodeTest, handleLocalData) {
auto localData42 = std::make_shared<TestLocalData>();
localData42->setNumber(42);
auto anotherLocalData42 = std::make_shared<TestLocalData>();
anotherLocalData42->setNumber(42);
auto localDataOver9000 = std::make_shared<TestLocalData>();
localDataOver9000->setNumber(9001);
auto firstNode = std::make_shared<TestShadowNode>(9, 1, (void *)NULL);
auto secondNode = std::make_shared<TestShadowNode>(9, 1, (void *)NULL);
auto thirdNode = std::make_shared<TestShadowNode>(9, 1, (void *)NULL);
firstNode->setLocalData(localData42);
secondNode->setLocalData(localData42);
thirdNode->setLocalData(localDataOver9000);
// LocalData object are compared by pointer, not by value.
ASSERT_EQ(*firstNode, *secondNode);
ASSERT_NE(*firstNode, *thirdNode);
secondNode->setLocalData(anotherLocalData42);
ASSERT_NE(*firstNode, *secondNode);
// LocalData cannot be changed for sealed shadow node.
secondNode->sealRecursive();
ASSERT_ANY_THROW(secondNode->setLocalData(localDataOver9000));
}