From 6e04631862c5e13aa9e6801a98b3901f6930a14c Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Thu, 9 May 2019 04:14:08 -0700 Subject: [PATCH] Add test utilities for C++ and Java Summary: @public Test utility on top of the new event system that maintains a counter of instantiated nodes. Meant to replace the global node counter. Reviewed By: SidharthGuglani Differential Revision: D15174855 fbshipit-source-id: 6998472f95a09b8da652257a26596164bdcf43d6 --- BUCK | 1 + java/BUCK | 10 ++++- tests/EventsTest.cpp | 32 +++++++-------- testutil/BUCK | 37 +++++++++++++++++ testutil/TestUtil.java | 19 +++++++++ testutil/jni.cpp | 38 +++++++++++++++++ testutil/testutil.cpp | 65 ++++++++++++++++++++++++++++++ testutil/testutil.h | 30 ++++++++++++++ tools/build_defs/oss/yoga_defs.bzl | 3 ++ yoga/events.cpp | 4 ++ yoga/events.h | 2 + 11 files changed, 221 insertions(+), 20 deletions(-) create mode 100644 testutil/BUCK create mode 100644 testutil/TestUtil.java create mode 100644 testutil/jni.cpp create mode 100644 testutil/testutil.cpp create mode 100644 testutil/testutil.h diff --git a/BUCK b/BUCK index 2f038b28..94175002 100644 --- a/BUCK +++ b/BUCK @@ -56,6 +56,7 @@ yoga_cxx_test( visibility = ["PUBLIC"], deps = [ ":yogaForDebug", + yoga_dep("testutil:testutil"), GTEST_TARGET, ], ) diff --git a/java/BUCK b/java/BUCK index 59a1613b..3f29b3c8 100644 --- a/java/BUCK +++ b/java/BUCK @@ -3,7 +3,12 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -load("//tools/build_defs/oss:yoga_defs.bzl", "ANDROID", "CXX_LIBRARY_WHITELIST", "FBJNI_JAVA_TARGET", "FBJNI_TARGET", "INFER_ANNOTATIONS_TARGET", "JNI_TARGET", "JSR_305_TARGET", "JUNIT_TARGET", "PROGRUARD_ANNOTATIONS_TARGET", "SOLOADER_TARGET", "yoga_cxx_library", "yoga_dep", "yoga_java_binary", "yoga_java_library", "yoga_java_test") +load("//tools/build_defs/oss:yoga_defs.bzl", "ANDROID", "CXX_LIBRARY_WHITELIST", "FBJNI_JAVA_TARGET", "FBJNI_TARGET", "INFER_ANNOTATIONS_TARGET", "JNI_TARGET", "JSR_305_TARGET", "JUNIT_TARGET", "PROGRUARD_ANNOTATIONS_TARGET", "SOLOADER_TARGET", "yoga_cxx_lib", "yoga_cxx_library", "yoga_dep", "yoga_java_binary", "yoga_java_library", "yoga_java_test") + +CXX_LIBRARY_WHITELIST_FOR_TESTS = CXX_LIBRARY_WHITELIST + [ + yoga_cxx_lib("testutil:jni"), + yoga_cxx_lib("testutil:testutil"), +] yoga_cxx_library( name = "jni", @@ -55,11 +60,12 @@ yoga_java_library( yoga_java_test( name = "tests", srcs = glob(["tests/**/*.java"]), - cxx_library_whitelist = CXX_LIBRARY_WHITELIST, + cxx_library_whitelist = CXX_LIBRARY_WHITELIST_FOR_TESTS, use_cxx_libraries = True, visibility = ["PUBLIC"], deps = [ ":java", + yoga_dep("testutil:java"), JUNIT_TARGET, ], ) diff --git a/tests/EventsTest.cpp b/tests/EventsTest.cpp index 5d8d3bdf..99adf8e8 100644 --- a/tests/EventsTest.cpp +++ b/tests/EventsTest.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -27,9 +28,12 @@ struct EventArgs { } }; -struct EventTest : public ::testing::Test { +class EventTest : public ::testing::Test { + ScopedEventSubscription subscription = {&EventTest::listen}; + static void listen(const YGNode&, Event::Type, Event::Data); + +public: static EventArgs lastEvent; - static void SetUpTestCase() noexcept; }; TEST_F(EventTest, new_node_has_event) { @@ -92,23 +96,15 @@ EventArgs createArgs(const YGNode& node, const Event::Data& data) { } // namespace -void EventTest::SetUpTestCase() noexcept { - static bool isSetup = false; - if (isSetup) { - return; +void EventTest::listen(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; } - 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{}; diff --git a/testutil/BUCK b/testutil/BUCK new file mode 100644 index 00000000..ba4c0e60 --- /dev/null +++ b/testutil/BUCK @@ -0,0 +1,37 @@ +load("//tools/build_defs/oss:yoga_defs.bzl", "ANDROID", "FBJNI_TARGET", "LIBRARY_COMPILER_FLAGS", "SOLOADER_TARGET", "yoga_cxx_library", "yoga_dep", "yoga_java_library") + +yoga_cxx_library( + name = "testutil", + srcs = ["testutil.cpp"], + header_namespace = "yoga/testutil", + exported_headers = ["testutil.h"], + compiler_flags = LIBRARY_COMPILER_FLAGS, + soname = "libyoga_testutil.$(ext)", + visibility = ["PUBLIC"], + deps = [yoga_dep(":yoga")], +) + +yoga_java_library( + name = "java", + srcs = ["TestUtil.java"], + source = "1.7", + target = "1.7", + visibility = ["PUBLIC"], + deps = [ + ":jni", + SOLOADER_TARGET, + ], +) + +yoga_cxx_library( + name = "jni", + srcs = ["jni.cpp"], + compiler_flags = LIBRARY_COMPILER_FLAGS, + platforms = ANDROID, + soname = "libyoga_testutil_jni.$(ext)", + visibility = ["PUBLIC"], + deps = [ + ":testutil", + FBJNI_TARGET, + ], +) diff --git a/testutil/TestUtil.java b/testutil/TestUtil.java new file mode 100644 index 00000000..bddde9ac --- /dev/null +++ b/testutil/TestUtil.java @@ -0,0 +1,19 @@ +/** + * 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. + */ +package com.facebook.yoga; + +import com.facebook.soloader.SoLoader; + +class TestUtil { + static { + SoLoader.loadLibrary("yoga_testutil_jni"); + } + + static native void startCountingNodes(); + static native int nodeCount(); + static native int stopCountingNodes(); +} diff --git a/testutil/jni.cpp b/testutil/jni.cpp new file mode 100644 index 00000000..18d7da90 --- /dev/null +++ b/testutil/jni.cpp @@ -0,0 +1,38 @@ +/** + * 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 + +using namespace facebook; + +namespace { + +void startCountingNodes(jni::alias_ref) { + yoga::test::TestUtil::startCountingNodes(); +} + +jint nodeCount(jni::alias_ref) { + return yoga::test::TestUtil::nodeCount(); +} + +jint stopCountingNodes(jni::alias_ref) { + return yoga::test::TestUtil::stopCountingNodes(); +} + +} // namespace + +jint JNI_OnLoad(JavaVM* vm, void*) { + return jni::initialize(vm, [] { + jni::registerNatives( + "com/facebook/yoga/TestUtil", + { + makeNativeMethod("startCountingNodes", startCountingNodes), + makeNativeMethod("nodeCount", nodeCount), + makeNativeMethod("stopCountingNodes", stopCountingNodes), + }); + }); +} diff --git a/testutil/testutil.cpp b/testutil/testutil.cpp new file mode 100644 index 00000000..f4174b40 --- /dev/null +++ b/testutil/testutil.cpp @@ -0,0 +1,65 @@ +/** + * 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 "testutil.h" + +#include +#include + +#include + +namespace facebook { +namespace yoga { +namespace test { + +int nodeInstanceCount = 0; + +namespace { + +void yogaEventSubscriber( + const YGNode& node, + Event::Type eventType, + const Event::Data& eventData) { + + switch (eventType) { + case Event::NodeAllocation: + nodeInstanceCount++; + break; + case Event::NodeDeallocation: + nodeInstanceCount--; + break; + default: + break; + } +} +} // namespace + +void TestUtil::startCountingNodes() { + nodeInstanceCount = 0; + Event::subscribe(yogaEventSubscriber); +} + +int TestUtil::nodeCount() { + return nodeInstanceCount; +} + +int TestUtil::stopCountingNodes() { + Event::reset(); + return std::exchange(nodeInstanceCount, 0); +} + +ScopedEventSubscription::ScopedEventSubscription( + std::function&& s) { + Event::subscribe(std::move(s)); +} + +ScopedEventSubscription::~ScopedEventSubscription() { + Event::reset(); +} + +} // namespace test +} // namespace yoga +} // namespace facebook diff --git a/testutil/testutil.h b/testutil/testutil.h new file mode 100644 index 00000000..e97bd025 --- /dev/null +++ b/testutil/testutil.h @@ -0,0 +1,30 @@ +/** + * 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. + */ +#pragma once + +#include + +#include + +namespace facebook { +namespace yoga { +namespace test { + +struct TestUtil { + static void startCountingNodes(); + static int nodeCount(); + static int stopCountingNodes(); +}; + +struct ScopedEventSubscription { + ScopedEventSubscription(std::function&&); + ~ScopedEventSubscription(); +}; + +} // namespace test +} // namespace yoga +} // namespace facebook diff --git a/tools/build_defs/oss/yoga_defs.bzl b/tools/build_defs/oss/yoga_defs.bzl index f6e04753..4a0dcd6a 100644 --- a/tools/build_defs/oss/yoga_defs.bzl +++ b/tools/build_defs/oss/yoga_defs.bzl @@ -148,6 +148,9 @@ def _single_subdir_glob(dirpath, glob_pattern, exclude = None, prefix = None): def yoga_dep(dep): return "//" + dep +def yoga_cxx_lib(lib): + return yoga_dep(lib) + def yoga_android_aar(*args, **kwargs): native.android_aar(*args, **kwargs) diff --git a/yoga/events.cpp b/yoga/events.cpp index 2548204a..41528e9c 100644 --- a/yoga/events.cpp +++ b/yoga/events.cpp @@ -24,6 +24,10 @@ std::function& globalEventSubscriber() { } // namespace +void Event::reset() { + globalEventSubscriber() = nullptr; +} + void Event::subscribe(std::function&& subscriber) { if (globalEventSubscriber() != nullptr) { throw std::logic_error( diff --git a/yoga/events.h b/yoga/events.h index bd8cdd4b..7b04060a 100644 --- a/yoga/events.h +++ b/yoga/events.h @@ -35,6 +35,8 @@ struct Event { }; }; + static void reset(); + static void subscribe(std::function&& subscriber); template