Summary: This does some preprataion for the Yoga CMake Build. The main change is removing the dedicated testutil top-level-directory and static library. This contains a method to count nodes using the event functions exposed to C++, along with a Java binding for the test utility (since the events don't have a Java binding). It is only used in a single place in a way that isn't very useful, so it simplifies things to treat is as source in the existing C++ test library. This also separates the hand-written and generated UTs, like we are doing in the JS directory in D42207782. Reviewed By: christophpurrer Differential Revision: D42247762 fbshipit-source-id: f8a270e99d0315ba7fc608f2471333e7a7be9d79
290 lines
10 KiB
C++
290 lines
10 KiB
C++
/*
|
|
* 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 <yoga/Yoga.h>
|
|
#include <yoga/YGNode.h>
|
|
|
|
#include "util/TestUtil.h"
|
|
|
|
using facebook::yoga::test::TestUtil;
|
|
|
|
TEST(YogaTest, cloning_shared_root) {
|
|
const YGConfigRef config = YGConfigNew();
|
|
|
|
const YGNodeRef root = YGNodeNewWithConfig(config);
|
|
YGNodeStyleSetWidth(root, 100);
|
|
YGNodeStyleSetHeight(root, 100);
|
|
|
|
const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
|
|
YGNodeStyleSetFlexGrow(root_child0, 1);
|
|
YGNodeStyleSetFlexBasis(root_child0, 50);
|
|
YGNodeInsertChild(root, root_child0, 0);
|
|
|
|
const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
|
|
YGNodeStyleSetFlexGrow(root_child1, 1);
|
|
YGNodeInsertChild(root, root_child1, 1);
|
|
YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
|
|
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
|
|
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
|
|
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
|
|
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
|
|
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
|
|
ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root_child0));
|
|
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
|
|
ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child1));
|
|
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
|
|
ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
|
|
|
|
const YGNodeRef root2 = YGNodeClone(root);
|
|
YGNodeStyleSetWidth(root2, 100);
|
|
|
|
ASSERT_EQ(2u, YGNodeGetChildCount(root2));
|
|
// The children should have referential equality at this point.
|
|
ASSERT_EQ(root_child0, YGNodeGetChild(root2, 0));
|
|
ASSERT_EQ(root_child1, YGNodeGetChild(root2, 1));
|
|
|
|
YGNodeCalculateLayout(root2, YGUndefined, YGUndefined, YGDirectionLTR);
|
|
|
|
ASSERT_EQ(2u, YGNodeGetChildCount(root2));
|
|
// Relayout with no changed input should result in referential equality.
|
|
ASSERT_EQ(root_child0, YGNodeGetChild(root2, 0));
|
|
ASSERT_EQ(root_child1, YGNodeGetChild(root2, 1));
|
|
|
|
YGNodeStyleSetWidth(root2, 150);
|
|
YGNodeStyleSetHeight(root2, 200);
|
|
YGNodeCalculateLayout(root2, YGUndefined, YGUndefined, YGDirectionLTR);
|
|
|
|
ASSERT_EQ(2u, YGNodeGetChildCount(root2));
|
|
// Relayout with changed input should result in cloned children.
|
|
const YGNodeRef root2_child0 = YGNodeGetChild(root2, 0);
|
|
const YGNodeRef root2_child1 = YGNodeGetChild(root2, 1);
|
|
ASSERT_NE(root_child0, root2_child0);
|
|
ASSERT_NE(root_child1, root2_child1);
|
|
|
|
// Everything in the root should remain unchanged.
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
|
|
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
|
|
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
|
|
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
|
|
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
|
|
ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root_child0));
|
|
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
|
|
ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child1));
|
|
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
|
|
ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
|
|
|
|
// The new root now has new layout.
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root2));
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root2));
|
|
ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root2));
|
|
ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root2));
|
|
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root2_child0));
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root2_child0));
|
|
ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root2_child0));
|
|
ASSERT_FLOAT_EQ(125, YGNodeLayoutGetHeight(root2_child0));
|
|
|
|
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root2_child1));
|
|
ASSERT_FLOAT_EQ(125, YGNodeLayoutGetTop(root2_child1));
|
|
ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root2_child1));
|
|
ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root2_child1));
|
|
|
|
YGNodeFreeRecursive(root2);
|
|
|
|
YGNodeFreeRecursive(root);
|
|
|
|
YGConfigFree(config);
|
|
}
|
|
|
|
TEST(YogaTest, mutating_children_of_a_clone_clones_only_after_layout) {
|
|
const YGConfigRef config = YGConfigNew();
|
|
|
|
const YGNodeRef root = YGNodeNewWithConfig(config);
|
|
ASSERT_EQ(0u, YGNodeGetChildCount(root));
|
|
|
|
const YGNodeRef root2 = YGNodeClone(root);
|
|
ASSERT_EQ(0u, YGNodeGetChildCount(root2));
|
|
|
|
const YGNodeRef root2_child0 = YGNodeNewWithConfig(config);
|
|
YGNodeInsertChild(root2, root2_child0, 0);
|
|
|
|
ASSERT_EQ(0u, YGNodeGetChildCount(root));
|
|
ASSERT_EQ(1u, YGNodeGetChildCount(root2));
|
|
|
|
const YGNodeRef root3 = YGNodeClone(root2);
|
|
ASSERT_EQ(1u, YGNodeGetChildCount(root2));
|
|
ASSERT_EQ(1u, YGNodeGetChildCount(root3));
|
|
ASSERT_EQ(YGNodeGetChild(root2, 0), YGNodeGetChild(root3, 0));
|
|
|
|
const YGNodeRef root3_child1 = YGNodeNewWithConfig(config);
|
|
YGNodeInsertChild(root3, root3_child1, 1);
|
|
ASSERT_EQ(1u, YGNodeGetChildCount(root2));
|
|
ASSERT_EQ(2u, YGNodeGetChildCount(root3));
|
|
ASSERT_EQ(root3_child1, YGNodeGetChild(root3, 1));
|
|
ASSERT_EQ(YGNodeGetChild(root2, 0), YGNodeGetChild(root3, 0));
|
|
|
|
const YGNodeRef root4 = YGNodeClone(root3);
|
|
ASSERT_EQ(root3_child1, YGNodeGetChild(root4, 1));
|
|
|
|
YGNodeRemoveChild(root4, root3_child1);
|
|
ASSERT_EQ(2u, YGNodeGetChildCount(root3));
|
|
ASSERT_EQ(1u, YGNodeGetChildCount(root4));
|
|
ASSERT_EQ(YGNodeGetChild(root3, 0), YGNodeGetChild(root4, 0));
|
|
|
|
YGNodeCalculateLayout(root4, YGUndefined, YGUndefined, YGDirectionLTR);
|
|
ASSERT_NE(YGNodeGetChild(root3, 0), YGNodeGetChild(root4, 0));
|
|
YGNodeCalculateLayout(root3, YGUndefined, YGUndefined, YGDirectionLTR);
|
|
ASSERT_NE(YGNodeGetChild(root2, 0), YGNodeGetChild(root3, 0));
|
|
|
|
YGNodeFreeRecursive(root4);
|
|
YGNodeFreeRecursive(root3);
|
|
YGNodeFreeRecursive(root2);
|
|
YGNodeFreeRecursive(root);
|
|
|
|
YGConfigFree(config);
|
|
}
|
|
|
|
TEST(YogaTest, cloning_two_levels) {
|
|
const YGConfigRef config = YGConfigNew();
|
|
|
|
const YGNodeRef root = YGNodeNewWithConfig(config);
|
|
YGNodeStyleSetWidth(root, 100);
|
|
YGNodeStyleSetHeight(root, 100);
|
|
|
|
const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
|
|
YGNodeStyleSetFlexGrow(root_child0, 1);
|
|
YGNodeStyleSetFlexBasis(root_child0, 15);
|
|
YGNodeInsertChild(root, root_child0, 0);
|
|
|
|
const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
|
|
YGNodeStyleSetFlexGrow(root_child1, 1);
|
|
YGNodeInsertChild(root, root_child1, 1);
|
|
|
|
const YGNodeRef root_child1_0 = YGNodeNewWithConfig(config);
|
|
YGNodeStyleSetFlexBasis(root_child1_0, 10);
|
|
YGNodeStyleSetFlexGrow(root_child1_0, 1);
|
|
YGNodeInsertChild(root_child1, root_child1_0, 0);
|
|
|
|
const YGNodeRef root_child1_1 = YGNodeNewWithConfig(config);
|
|
YGNodeStyleSetFlexBasis(root_child1_1, 25);
|
|
YGNodeInsertChild(root_child1, root_child1_1, 1);
|
|
|
|
YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
|
|
|
|
ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
|
|
ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child1));
|
|
ASSERT_FLOAT_EQ(35, YGNodeLayoutGetHeight(root_child1_0));
|
|
ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1_1));
|
|
|
|
const YGNodeRef root2_child0 = YGNodeClone(root_child0);
|
|
const YGNodeRef root2_child1 = YGNodeClone(root_child1);
|
|
const YGNodeRef root2 = YGNodeClone(root);
|
|
|
|
YGNodeStyleSetFlexGrow(root2_child0, 0);
|
|
YGNodeStyleSetFlexBasis(root2_child0, 40);
|
|
|
|
YGNodeRemoveAllChildren(root2);
|
|
YGNodeInsertChild(root2, root2_child0, 0);
|
|
YGNodeInsertChild(root2, root2_child1, 1);
|
|
ASSERT_EQ(2u, YGNodeGetChildCount(root2));
|
|
|
|
YGNodeCalculateLayout(root2, YGUndefined, YGUndefined, YGDirectionLTR);
|
|
|
|
// Original root is unchanged
|
|
ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
|
|
ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child1));
|
|
ASSERT_FLOAT_EQ(35, YGNodeLayoutGetHeight(root_child1_0));
|
|
ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1_1));
|
|
|
|
// New root has new layout at the top
|
|
ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root2_child0));
|
|
ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root2_child1));
|
|
|
|
// The deeper children are untouched.
|
|
ASSERT_EQ(YGNodeGetChild(root2_child1, 0), root_child1_0);
|
|
ASSERT_EQ(YGNodeGetChild(root2_child1, 1), root_child1_1);
|
|
|
|
YGNodeFreeRecursive(root2);
|
|
YGNodeFreeRecursive(root);
|
|
|
|
YGConfigFree(config);
|
|
}
|
|
|
|
TEST(YogaTest, cloning_and_freeing) {
|
|
TestUtil::startCountingNodes();
|
|
|
|
const YGConfigRef config = YGConfigNew();
|
|
|
|
const YGNodeRef root = YGNodeNewWithConfig(config);
|
|
YGNodeStyleSetWidth(root, 100);
|
|
YGNodeStyleSetHeight(root, 100);
|
|
const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
|
|
YGNodeInsertChild(root, root_child0, 0);
|
|
const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
|
|
YGNodeInsertChild(root, root_child1, 1);
|
|
|
|
YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
|
|
|
|
const YGNodeRef root2 = YGNodeClone(root);
|
|
|
|
// Freeing the original root should be safe as long as we don't free its
|
|
// children.
|
|
YGNodeFree(root);
|
|
|
|
YGNodeCalculateLayout(root2, YGUndefined, YGUndefined, YGDirectionLTR);
|
|
|
|
YGNodeFreeRecursive(root2);
|
|
|
|
YGNodeFree(root_child0);
|
|
YGNodeFree(root_child1);
|
|
|
|
YGConfigFree(config);
|
|
|
|
ASSERT_EQ(0, TestUtil::stopCountingNodes());
|
|
}
|
|
|
|
TEST(YogaTest, mixed_shared_and_owned_children) {
|
|
// Don't try this at home!
|
|
|
|
YGNodeRef root0 = YGNodeNew();
|
|
YGNodeRef root1 = YGNodeNew();
|
|
|
|
YGNodeRef root0_child0 = YGNodeNew();
|
|
YGNodeRef root0_child0_0 = YGNodeNew();
|
|
YGNodeInsertChild(root0, root0_child0, 0);
|
|
YGNodeInsertChild(root0_child0, root0_child0_0, 0);
|
|
|
|
YGNodeRef root1_child0 = YGNodeNew();
|
|
YGNodeRef root1_child2 = YGNodeNew();
|
|
YGNodeInsertChild(root1, root1_child0, 0);
|
|
YGNodeInsertChild(root1, root1_child2, 1);
|
|
|
|
auto children = root1->getChildren();
|
|
children.insert(children.begin() + 1, root0_child0);
|
|
root1->setChildren(children);
|
|
auto secondChild = YGNodeGetChild(root1, 1);
|
|
ASSERT_EQ(secondChild, YGNodeGetChild(root0, 0));
|
|
ASSERT_EQ(YGNodeGetChild(secondChild, 0), YGNodeGetChild(root0_child0, 0));
|
|
|
|
YGNodeCalculateLayout(root1, YGUndefined, YGUndefined, YGDirectionLTR);
|
|
secondChild = YGNodeGetChild(root1, 1);
|
|
ASSERT_NE(secondChild, YGNodeGetChild(root0, 0));
|
|
ASSERT_EQ(YGNodeGetOwner(secondChild), root1);
|
|
ASSERT_NE(YGNodeGetChild(secondChild, 0), YGNodeGetChild(root0_child0, 0));
|
|
ASSERT_EQ(YGNodeGetOwner(YGNodeGetChild(secondChild, 0)), secondChild);
|
|
}
|