From 1212d313e44900ec7b434aa948b4f2cd2b1bcad1 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Tue, 5 Dec 2023 03:41:14 -0800 Subject: [PATCH] Re-enabled disabled tests ReactPropForShadowNodeSpecTest and ReactPropForShadowNodeSetterTest (#41788) Summary: X-link: https://github.com/facebook/yoga/pull/1494 Those tests are currently disabled due to Yoga attempting to do JNI calls. I've added infra to bypass .so loading during tests, and we should be good to re-enable those tests by now. Changelog: [Internal] [Changed] - Re-enabled disabled tests ReactPropForShadowNodeSpecTest and ReactPropForShadowNodeSetterTest Reviewed By: NickGerleman Differential Revision: D51814491 --- .../java/com/facebook/yoga/YogaConfig.java | 2 +- .../com/facebook/yoga/YogaConfigJNIBase.java | 2 +- .../ReactPropForShadowNodeSetterTest.java | 15 +- .../ReactPropForShadowNodeSpecTest.kt | 9 +- .../testutils/fakes/FakeYogaConfig.kt | 57 ++++ .../facebook/testutils/fakes/FakeYogaNode.kt | 251 ++++++++++++++++++ .../shadows/ShadowYogaConfigProvider.kt | 22 ++ .../shadows/ShadowYogaNodeFactory.kt | 26 ++ 8 files changed, 377 insertions(+), 7 deletions(-) create mode 100644 packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeYogaConfig.kt create mode 100644 packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeYogaNode.kt create mode 100644 packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowYogaConfigProvider.kt create mode 100644 packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowYogaNodeFactory.kt diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java index bd7b2998ce3af2..0ca8571e959acd 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java @@ -27,5 +27,5 @@ public abstract class YogaConfig { public abstract YogaLogger getLogger(); - abstract long getNativePointer(); + protected abstract long getNativePointer(); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfigJNIBase.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfigJNIBase.java index 8e7c94921c9034..07263e6df3e531 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfigJNIBase.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfigJNIBase.java @@ -60,7 +60,7 @@ public YogaLogger getLogger() { return mLogger; } - long getNativePointer() { + protected long getNativePointer() { return mNativePointer; } } diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSetterTest.java b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSetterTest.java index a6062a221d2a5e..20a6ddb4d42d2e 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSetterTest.java +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSetterTest.java @@ -14,15 +14,20 @@ import androidx.annotation.Nullable; import com.facebook.react.bridge.JavaOnlyMap; +import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.annotations.ReactPropGroup; +import com.facebook.testutils.shadows.ShadowSoLoader; +import com.facebook.testutils.shadows.ShadowYogaConfigProvider; +import com.facebook.testutils.shadows.ShadowYogaNodeFactory; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; /** * Test {@link ReactProp} annotation for {@link ReactShadowNode}. More comprehensive test of this @@ -30,9 +35,9 @@ * of properties to be updated. */ @RunWith(RobolectricTestRunner.class) -@Ignore // TODO T14964130 +@Config( + shadows = {ShadowYogaConfigProvider.class, ShadowSoLoader.class, ShadowYogaNodeFactory.class}) public class ReactPropForShadowNodeSetterTest { - public interface ViewManagerUpdatesReceiver { void onBooleanSetterCalled(boolean value); @@ -69,6 +74,10 @@ private class ShadowViewUnderTest extends ReactShadowNodeImpl { private ShadowViewUnderTest(ViewManagerUpdatesReceiver viewManagerUpdatesReceiver) { mViewManagerUpdatesReceiver = viewManagerUpdatesReceiver; + setViewClassName("ShadowViewUnderTest"); + ReactApplicationContext context = + new ReactApplicationContext(RuntimeEnvironment.getApplication()); + setThemedContext(new ThemedReactContext(context, context, null, -1)); } @ReactProp(name = "boolProp") diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSpecTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSpecTest.kt index 74ce703c4dec09..1b7055efda8620 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSpecTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSpecTest.kt @@ -10,17 +10,22 @@ package com.facebook.react.uimanager import android.view.View import com.facebook.react.uimanager.annotations.ReactProp import com.facebook.react.uimanager.annotations.ReactPropGroup -import org.junit.Ignore +import com.facebook.testutils.shadows.ShadowSoLoader +import com.facebook.testutils.shadows.ShadowYogaConfigProvider +import com.facebook.testutils.shadows.ShadowYogaNodeFactory import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config /** * Test that verifies that spec of methods annotated with @ReactProp in {@link ReactShadowNode} is * correct */ @RunWith(RobolectricTestRunner::class) -@Ignore +@Config( + shadows = + [ShadowYogaConfigProvider::class, ShadowSoLoader::class, ShadowYogaNodeFactory::class]) class ReactPropForShadowNodeSpecTest { @Test(expected = RuntimeException::class) fun testMethodWithWrongNumberOfParams() { diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeYogaConfig.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeYogaConfig.kt new file mode 100644 index 00000000000000..579761f23ec413 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeYogaConfig.kt @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package com.facebook.testutils.fakes + +import com.facebook.yoga.YogaConfig +import com.facebook.yoga.YogaErrata +import com.facebook.yoga.YogaExperimentalFeature +import com.facebook.yoga.YogaLogger + +/** A fake [YogaConfig] that allows us to test Yoga without using the real JNI. */ +class FakeYogaConfig : YogaConfig() { + var fakeErrata: YogaErrata? = YogaErrata.NONE + var fakeLogger: YogaLogger? = YogaLogger { _, _ -> + // no-op + } + + override fun setExperimentalFeatureEnabled(feature: YogaExperimentalFeature?, enabled: Boolean) { + // no-op + } + + override fun setUseWebDefaults(useWebDefaults: Boolean) { + // no-op + } + + override fun setPrintTreeFlag(enable: Boolean) { + // no-op + } + + override fun setPointScaleFactor(pixelsInPoint: Float) { + // no-op + } + + override fun setErrata(errata: YogaErrata?) { + fakeErrata = errata + } + + override fun getErrata(): YogaErrata? { + return fakeErrata + } + + override fun setLogger(logger: YogaLogger?) { + fakeLogger = logger + } + + override fun getLogger(): YogaLogger? { + return fakeLogger + } + + override fun getNativePointer(): Long { + return 0L + } +} diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeYogaNode.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeYogaNode.kt new file mode 100644 index 00000000000000..d21efbe1582782 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeYogaNode.kt @@ -0,0 +1,251 @@ +/* + * 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. + */ + +package com.facebook.testutils.fakes + +import com.facebook.yoga.YogaAlign +import com.facebook.yoga.YogaBaselineFunction +import com.facebook.yoga.YogaConstants +import com.facebook.yoga.YogaDirection +import com.facebook.yoga.YogaDisplay +import com.facebook.yoga.YogaEdge +import com.facebook.yoga.YogaFlexDirection +import com.facebook.yoga.YogaGutter +import com.facebook.yoga.YogaJustify +import com.facebook.yoga.YogaMeasureFunction +import com.facebook.yoga.YogaNode +import com.facebook.yoga.YogaOverflow +import com.facebook.yoga.YogaPositionType +import com.facebook.yoga.YogaUnit +import com.facebook.yoga.YogaValue +import com.facebook.yoga.YogaWrap + +/** A fake [YogaNode] that allows us to test Yoga without using the real JNI. */ +class FakeYogaNode : YogaNode() { + override fun setWidth(width: Float) {} + + override fun setWidthPercent(percent: Float) {} + + override fun setMinWidth(minWidth: Float) {} + + override fun setMinWidthPercent(percent: Float) {} + + override fun setMaxWidth(maxWidth: Float) {} + + override fun setMaxWidthPercent(percent: Float) {} + + override fun setWidthAuto() {} + + override fun setHeight(height: Float) {} + + override fun setHeightPercent(percent: Float) {} + + override fun setMinHeight(minHeight: Float) {} + + override fun setMinHeightPercent(percent: Float) {} + + override fun setMaxHeight(maxheight: Float) {} + + override fun setMaxHeightPercent(percent: Float) {} + + override fun setHeightAuto() {} + + override fun setMargin(edge: YogaEdge?, margin: Float) {} + + override fun setMarginPercent(edge: YogaEdge?, percent: Float) {} + + override fun setMarginAuto(edge: YogaEdge?) {} + + override fun setPadding(edge: YogaEdge?, padding: Float) {} + + override fun setPaddingPercent(edge: YogaEdge?, percent: Float) {} + + override fun setPositionType(positionType: YogaPositionType?) {} + + override fun setPosition(edge: YogaEdge?, position: Float) {} + + override fun setPositionPercent(edge: YogaEdge?, percent: Float) {} + + override fun setAlignContent(alignContent: YogaAlign?) {} + + override fun setAlignItems(alignItems: YogaAlign?) {} + + override fun setAlignSelf(alignSelf: YogaAlign?) {} + + override fun setFlex(flex: Float) {} + + override fun setFlexBasisAuto() {} + + override fun setFlexBasisPercent(percent: Float) {} + + override fun setFlexBasis(flexBasis: Float) {} + + override fun setFlexDirection(flexDirection: YogaFlexDirection?) {} + + override fun setFlexGrow(flexGrow: Float) {} + + override fun setFlexShrink(flexShrink: Float) {} + + override fun setJustifyContent(justifyContent: YogaJustify?) {} + + override fun setDirection(direction: YogaDirection?) {} + + override fun setBorder(edge: YogaEdge?, border: Float) {} + + override fun setWrap(flexWrap: YogaWrap?) {} + + override fun setAspectRatio(aspectRatio: Float) {} + + override fun setIsReferenceBaseline(isReferenceBaseline: Boolean) {} + + override fun setMeasureFunction(measureFunction: YogaMeasureFunction?) {} + + override fun setBaselineFunction(baselineFunction: YogaBaselineFunction?) {} + + override fun getWidth(): YogaValue = YogaValue(YogaConstants.UNDEFINED, YogaUnit.UNDEFINED) + + override fun getMinWidth(): YogaValue = YogaValue(YogaConstants.UNDEFINED, YogaUnit.UNDEFINED) + + override fun getMaxWidth(): YogaValue = YogaValue(YogaConstants.UNDEFINED, YogaUnit.UNDEFINED) + + override fun getHeight(): YogaValue = YogaValue(YogaConstants.UNDEFINED, YogaUnit.UNDEFINED) + + override fun getMinHeight(): YogaValue = YogaValue(YogaConstants.UNDEFINED, YogaUnit.UNDEFINED) + + override fun getMaxHeight(): YogaValue = YogaValue(YogaConstants.UNDEFINED, YogaUnit.UNDEFINED) + + override fun getStyleDirection(): YogaDirection = YogaDirection.INHERIT + + override fun getFlexDirection(): YogaFlexDirection = YogaFlexDirection.COLUMN + + override fun getJustifyContent(): YogaJustify = YogaJustify.FLEX_START + + override fun getAlignItems(): YogaAlign = YogaAlign.FLEX_START + + override fun getAlignSelf(): YogaAlign = YogaAlign.FLEX_START + + override fun getAlignContent(): YogaAlign = YogaAlign.FLEX_START + + override fun getPositionType(): YogaPositionType = YogaPositionType.RELATIVE + + override fun getFlexGrow(): Float = 0f + + override fun getFlexShrink(): Float = 0f + + override fun getFlexBasis(): YogaValue = YogaValue(YogaConstants.UNDEFINED, YogaUnit.UNDEFINED) + + override fun getAspectRatio(): Float = 0f + + override fun getMargin(edge: YogaEdge?): YogaValue = + YogaValue(YogaConstants.UNDEFINED, YogaUnit.UNDEFINED) + + override fun getPadding(edge: YogaEdge?): YogaValue = + YogaValue(YogaConstants.UNDEFINED, YogaUnit.UNDEFINED) + + override fun getPosition(edge: YogaEdge?): YogaValue = + YogaValue(YogaConstants.UNDEFINED, YogaUnit.UNDEFINED) + + override fun getBorder(edge: YogaEdge?): Float = 0f + + override fun reset() { + // no-op + } + + override fun getChildCount(): Int = 0 + + override fun getChildAt(i: Int): YogaNode = FakeYogaNode() + + override fun addChildAt(child: YogaNode?, i: Int) { + // no-op + } + + override fun isReferenceBaseline(): Boolean = false + + override fun removeChildAt(i: Int): YogaNode = FakeYogaNode() + + override fun getOwner(): YogaNode? = null + + @Deprecated("Deprecated in Java") override fun getParent(): YogaNode? = null + + override fun indexOf(child: YogaNode?): Int = 0 + + override fun calculateLayout(width: Float, height: Float) { + // no-op + } + + override fun hasNewLayout(): Boolean = false + + override fun dirty() { + // no-op + } + + override fun isDirty(): Boolean = false + + override fun copyStyle(srcNode: YogaNode?) { + // no-op + } + + override fun markLayoutSeen() { + // no-op + } + + override fun getWrap(): YogaWrap = YogaWrap.WRAP + + override fun getOverflow(): YogaOverflow = YogaOverflow.HIDDEN + + override fun setOverflow(overflow: YogaOverflow?) { + // no-op + } + + override fun getDisplay(): YogaDisplay = YogaDisplay.NONE + + override fun setDisplay(display: YogaDisplay?) { + // no-op + } + + override fun getFlex(): Float = 0f + + override fun getGap(gutter: YogaGutter?): Float = 0f + + override fun setGap(gutter: YogaGutter?, gapLength: Float) { + // no-op + } + + override fun getLayoutX(): Float = 0f + + override fun getLayoutY(): Float = 0f + + override fun getLayoutWidth(): Float = 0f + + override fun getLayoutHeight(): Float = 0f + + override fun getLayoutMargin(edge: YogaEdge?): Float = 0f + + override fun getLayoutPadding(edge: YogaEdge?): Float = 0f + + override fun getLayoutBorder(edge: YogaEdge?): Float = 0f + + override fun getLayoutDirection(): YogaDirection = YogaDirection.INHERIT + + override fun isMeasureDefined(): Boolean = true + + override fun isBaselineDefined(): Boolean = true + + override fun setData(data: Any?) { + // no-op + } + + override fun getData(): Any? = null + + override fun print() { + // no-op + } + + override fun cloneWithoutChildren(): YogaNode = FakeYogaNode() + + override fun cloneWithChildren(): YogaNode = FakeYogaNode() +} diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowYogaConfigProvider.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowYogaConfigProvider.kt new file mode 100644 index 00000000000000..f895334d8d8738 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowYogaConfigProvider.kt @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package com.facebook.testutils.shadows + +import com.facebook.react.uimanager.ReactYogaConfigProvider +import com.facebook.testutils.fakes.FakeYogaConfig +import com.facebook.yoga.YogaConfig +import org.robolectric.annotation.Implementation +import org.robolectric.annotation.Implements + +@Suppress("UNUSED_PARAMETER") +@Implements(ReactYogaConfigProvider::class) +class ShadowYogaConfigProvider { + companion object { + @JvmStatic @Implementation fun get(): YogaConfig = FakeYogaConfig() + } +} diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowYogaNodeFactory.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowYogaNodeFactory.kt new file mode 100644 index 00000000000000..b1ccb04cd90a93 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowYogaNodeFactory.kt @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package com.facebook.testutils.shadows + +import com.facebook.testutils.fakes.FakeYogaNode +import com.facebook.yoga.YogaConfig +import com.facebook.yoga.YogaNode +import com.facebook.yoga.YogaNodeFactory +import org.robolectric.annotation.Implementation +import org.robolectric.annotation.Implements + +@Suppress("UNUSED_PARAMETER") +@Implements(YogaNodeFactory::class) +class ShadowYogaNodeFactory { + companion object { + + @JvmStatic @Implementation fun create(): YogaNode = FakeYogaNode() + + @JvmStatic @Implementation fun create(config: YogaConfig): YogaNode = FakeYogaNode() + } +}