diff --git a/BUCK b/BUCK index d81f4daf..2f038b28 100644 --- a/BUCK +++ b/BUCK @@ -16,6 +16,7 @@ COMPILER_FLAGS = LIBRARY_COMPILER_FLAGS + [ TEST_COMPILER_FLAGS = BASE_COMPILER_FLAGS + GMOCK_OVERRIDE_FLAGS + [ "-std=c++1y", "-DDEBUG", + "-DYG_ENABLE_EVENTS", ] yoga_cxx_library( diff --git a/tests/EventsTest.cpp b/tests/EventsTest.cpp new file mode 100644 index 00000000..5d8d3bdf --- /dev/null +++ b/tests/EventsTest.cpp @@ -0,0 +1,118 @@ +/** + * 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 +#include +#include +#include + +#include +#include + +namespace facebook { +namespace yoga { +namespace test { + +struct EventArgs { + const YGNode* node; + Event::Type type; + std::unique_ptr> dataPtr; + + template + const Event::TypedData& data() { + return *static_cast*>(dataPtr.get()); + } +}; + +struct EventTest : public ::testing::Test { + static EventArgs lastEvent; + static void SetUpTestCase() noexcept; +}; + +TEST_F(EventTest, new_node_has_event) { + auto c = YGConfigGetDefault(); + auto n = YGNodeNew(); + + ASSERT_EQ(lastEvent.node, n); + ASSERT_EQ(lastEvent.type, Event::NodeAllocation); + ASSERT_EQ(lastEvent.data().config, c); + + YGNodeFree(n); +} + +TEST_F(EventTest, new_node_with_config_event) { + auto c = YGConfigNew(); + auto n = YGNodeNewWithConfig(c); + + ASSERT_EQ(lastEvent.node, n); + ASSERT_EQ(lastEvent.type, Event::NodeAllocation); + ASSERT_EQ(lastEvent.data().config, c); + + YGNodeFree(n); + YGConfigFree(c); +} + +TEST_F(EventTest, clone_node_event) { + auto c = YGConfigNew(); + auto n = YGNodeNewWithConfig(c); + auto clone = YGNodeClone(n); + + ASSERT_EQ(lastEvent.node, clone); + ASSERT_EQ(lastEvent.type, Event::NodeAllocation); + ASSERT_EQ(lastEvent.data().config, c); + + YGNodeFree(n); + YGNodeFree(clone); + YGConfigFree(c); +} + +TEST_F(EventTest, free_node_event) { + auto c = YGConfigNew(); + auto n = YGNodeNewWithConfig(c); + YGNodeFree(n); + + ASSERT_EQ(lastEvent.node, n); + ASSERT_EQ(lastEvent.type, Event::NodeDeallocation); + ASSERT_EQ(lastEvent.data().config, c); + + YGConfigFree(c); +} + +namespace { + +template +EventArgs createArgs(const YGNode& node, const Event::Data& data) { + using Data = Event::TypedData; + auto deleteData = [](void* x) { delete static_cast(x); }; + return {&node, E, {new Data{data.get()}, deleteData}}; +} + +} // namespace + +void EventTest::SetUpTestCase() noexcept { + static bool isSetup = false; + if (isSetup) { + return; + } + isSetup = true; + + Event::subscribe([](const YGNode& node, Event::Type type, Event::Data data) { + switch (type) { + case Event::NodeAllocation: + lastEvent = createArgs(node, data); + break; + case Event::NodeDeallocation: + lastEvent = createArgs(node, data); + break; + } + }); +} + +EventArgs EventTest::lastEvent{}; + +} // namespace test +} // namespace yoga +} // namespace facebook diff --git a/yoga/Yoga.cpp b/yoga/Yoga.cpp index f3f68fd0..72772366 100644 --- a/yoga/Yoga.cpp +++ b/yoga/Yoga.cpp @@ -13,6 +13,7 @@ #include "YGNode.h" #include "YGNodePrint.h" #include "Yoga-internal.h" +#include "events.h" #include "instrumentation.h" #ifdef _MSC_VER #include @@ -213,6 +214,9 @@ WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) { YGAssertWithConfig( config, node != nullptr, "Could not allocate memory for node"); gNodeInstanceCount++; +#ifdef YG_ENABLE_EVENTS + Event::publish(node, {config}); +#endif if (config->useWebDefaults) { node->getStyle().flexDirection() = YGFlexDirectionRow; @@ -238,6 +242,9 @@ YGNodeRef YGNodeClone(YGNodeRef oldNode) { node != nullptr, "Could not allocate memory for node"); gNodeInstanceCount++; +#ifdef YG_ENABLE_EVENTS + Event::publish(node, {node->getConfig()}); +#endif node->setOwner(nullptr); return node; } @@ -284,6 +291,9 @@ void YGNodeFree(const YGNodeRef node) { } node->clearChildren(); +#ifdef YG_ENABLE_EVENTS + Event::publish(node, {node->getConfig()}); +#endif delete node; gNodeInstanceCount--; } diff --git a/yoga/events.cpp b/yoga/events.cpp index 19092fc5..2548204a 100644 --- a/yoga/events.cpp +++ b/yoga/events.cpp @@ -8,6 +8,8 @@ #include #include +#include + namespace facebook { namespace yoga { diff --git a/yoga/events.h b/yoga/events.h index c48fab7b..bd8cdd4b 100644 --- a/yoga/events.h +++ b/yoga/events.h @@ -15,7 +15,7 @@ namespace facebook { namespace yoga { struct Event { - enum Type {}; + enum Type { NodeAllocation, NodeDeallocation }; class Data; using Subscriber = void(const YGNode&, Type, Data); @@ -51,5 +51,15 @@ private: static void publish(const YGNode&, Type, const Data&); }; +template <> +struct Event::TypedData { + YGConfig* config; +}; + +template <> +struct Event::TypedData { + YGConfig* config; +}; + } // namespace yoga } // namespace facebook