diff --git a/tests/InstrumentationTest.cpp b/tests/InstrumentationTest.cpp new file mode 100644 index 00000000..167e782e --- /dev/null +++ b/tests/InstrumentationTest.cpp @@ -0,0 +1,124 @@ +/** + * 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 +#include +#include + +namespace facebook { +namespace yoga { +namespace marker { +namespace test { + +template +using uniquePtr = std::unique_ptr>; + +struct MarkerTest : public ::testing::Test { + struct Data { + YGMarker marker; + YGNodeRef node; + YGMarkerData markerData; + }; + + struct EndData { + Data data; + void* cookie; + }; + + static struct { + Data start; + EndData end; + } markerCookie; + + static void* startMarker(YGMarker, YGNodeRef, YGMarkerData); + static void endMarker(YGMarker, YGNodeRef, YGMarkerData, void*); + static uniquePtr makeConfig(); + static uniquePtr makeNode(uniquePtr&); + + void SetUp() override; +}; + +TEST_F(MarkerTest, marker_start_works) { + auto config = makeConfig(); + auto root = makeNode(config); + + decltype(MarkerSection::data)* dataAddress; + { + MarkerSection marker{root.get()}; + dataAddress = &marker.data; + } + + ASSERT_EQ(markerCookie.start.marker, YGMarkerLayout) + << "wrong marker type passed to `startMarker`"; + ASSERT_EQ(markerCookie.start.node, root.get()) + << "wrong node pointer passed to `startMarker`"; + ASSERT_EQ(markerCookie.start.markerData.layout, dataAddress) + << "wrong pointer to marker data passed to `startMarker`"; +} + +TEST_F(MarkerTest, marker_end_works) { + auto config = makeConfig(); + auto root = makeNode(config); + + { MarkerSection marker{root.get()}; } + + ASSERT_EQ(markerCookie.end.data.marker, markerCookie.start.marker) + << "marker type passed to `endMarker` differs from type passed to " + "`startMarker`"; + ASSERT_EQ(markerCookie.end.data.node, markerCookie.start.node) + << "node passed to `endMarker` differs from node passed to `startMarker`"; + ASSERT_EQ( + markerCookie.end.data.markerData.layout, + markerCookie.start.markerData.layout) + << "marker data pointer passed to `endMarker` differs from pointer " + "passed to `startMarker`"; + ASSERT_EQ(markerCookie.end.cookie, &markerCookie) + << "pointer returned by `startMarker` was not passed to `endMarker`"; +} + +void* MarkerTest::startMarker( + YGMarker marker, + YGNodeRef node, + YGMarkerData data) { + markerCookie.start = {marker, node, data}; + return &markerCookie; +} + +void MarkerTest::endMarker( + YGMarker marker, + YGNodeRef node, + YGMarkerData data, + void* id) { + markerCookie.end = {{marker, node, data}, id}; +} + +uniquePtr MarkerTest::makeConfig() { + auto c = uniquePtr{YGConfigNew(), &YGConfigFree}; + YGConfigSetMarkerCallbacks(c.get(), {startMarker, endMarker}); + return c; +} + +uniquePtr MarkerTest::makeNode(uniquePtr& config) { + auto n = uniquePtr{YGNodeNewWithConfig(config.get()), &YGNodeFree}; + return n; +} + +void MarkerTest::SetUp() { + markerCookie = {}; +} + +decltype(MarkerTest::markerCookie) MarkerTest::markerCookie = {}; + +} // namespace test +} // namespace marker +} // namespace yoga +} // namespace facebook diff --git a/yoga/YGMarker.h b/yoga/YGMarker.h index 28fc3fff..f7da1b58 100644 --- a/yoga/YGMarker.h +++ b/yoga/YGMarker.h @@ -37,3 +37,25 @@ typedef struct { void YGConfigSetMarkerCallbacks(YGConfigRef, YGMarkerCallbacks); YG_EXTERN_C_END + +#ifdef __cplusplus + +namespace facebook { +namespace yoga { +namespace marker { +namespace detail { + +template +struct MarkerData; + +template <> +struct MarkerData { + using type = YGMarkerLayoutData; +}; + +} // namespace detail +} // namespace marker +} // namespace yoga +} // namespace facebook + +#endif // __cplusplus diff --git a/yoga/instrumentation.h b/yoga/instrumentation.h new file mode 100644 index 00000000..670fc2bd --- /dev/null +++ b/yoga/instrumentation.h @@ -0,0 +1,44 @@ +/** + * 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 "YGConfig.h" +#include "YGMarker.h" +#include "YGNode.h" + +namespace facebook { +namespace yoga { +namespace marker { + +template +class MarkerSection { +public: + MarkerSection(YGNodeRef node) : MarkerSection{node, node->getConfig()} {} + ~MarkerSection() { + if (endMarker_) { + endMarker_(MarkerType, node_, {&data}, userData_); + } + } + + typename detail::MarkerData::type data = {}; + +private: + decltype(YGMarkerCallbacks{}.endMarker) endMarker_; + YGNodeRef node_; + void* userData_; + + MarkerSection(YGNodeRef node, YGConfigRef config) + : MarkerSection{node, config ? &config->markerCallbacks : nullptr} {} + MarkerSection(YGNodeRef node, YGMarkerCallbacks* callbacks) + : endMarker_{callbacks ? callbacks->endMarker : nullptr}, + node_{node}, + userData_{callbacks && callbacks->startMarker + ? callbacks->startMarker(MarkerType, node, {&data}) + : nullptr} {} +}; + +} // namespace marker +} // namespace yoga +} // namespace facebook