Use real YogaNodes in FabricUIManagerTest

Reviewed By: mdvacca

Differential Revision: D7663769

fbshipit-source-id: 78cdde975037c4e8d97d4bd21ddd7927cc105dd0
This commit is contained in:
Andrew Chen (Eng) 2018-04-17 18:11:28 -07:00 committed by Facebook Github Bot
parent ff9b3c6517
commit 864cc00a61
1 changed files with 8 additions and 95 deletions

View File

@ -16,20 +16,15 @@ import com.facebook.react.common.ClearableSynchronizedPool;
import com.facebook.react.fabric.FabricUIManager; import com.facebook.react.fabric.FabricUIManager;
import com.facebook.react.uimanager.ReactShadowNode; import com.facebook.react.uimanager.ReactShadowNode;
import com.facebook.react.uimanager.ReactShadowNodeImpl; import com.facebook.react.uimanager.ReactShadowNodeImpl;
import com.facebook.react.uimanager.ReactYogaConfigProvider;
import com.facebook.react.uimanager.Spacing; import com.facebook.react.uimanager.Spacing;
import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewManager; import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.uimanager.ViewManagerRegistry; import com.facebook.react.uimanager.ViewManagerRegistry;
import com.facebook.react.uimanager.YogaNodePool;
import com.facebook.react.views.text.ReactRawTextManager; import com.facebook.react.views.text.ReactRawTextManager;
import com.facebook.react.views.text.ReactRawTextShadowNode; import com.facebook.react.views.text.ReactRawTextShadowNode;
import com.facebook.react.views.text.ReactTextViewManager; import com.facebook.react.views.text.ReactTextViewManager;
import com.facebook.react.views.view.ReactViewManager; import com.facebook.react.views.view.ReactViewManager;
import com.facebook.testing.robolectric.v3.WithTestDefaultsRunner; import com.facebook.testing.robolectric.v3.WithTestDefaultsRunner;
import com.facebook.yoga.YogaConfig;
import com.facebook.yoga.YogaMeasureFunction;
import com.facebook.yoga.YogaNode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -45,16 +40,12 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
/** Tests {@link FabricUIManager} */ /** Tests {@link FabricUIManager} */
@PrepareForTest({YogaNodePool.class, ReactYogaConfigProvider.class})
@RunWith(WithTestDefaultsRunner.class) @RunWith(WithTestDefaultsRunner.class)
public class FabricUIManagerTest { public class FabricUIManagerTest {
private FabricUIManager mFabricUIManager; private FabricUIManager mFabricUIManager;
private ThemedReactContext mThemedReactContext; private ThemedReactContext mThemedReactContext;
private int mNextReactTag; private int mNextReactTag;
private MockYogaNodePool mMockYogaNodePool;
private YogaMeasureFunction mLastYogaMeasureFunction;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@ -70,19 +61,6 @@ public class FabricUIManagerTest {
ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers); ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers);
mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry); mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry);
// Hack around Yoga until the UnsatisfiedLinkErrors are fixed t14964130
PowerMockito.mockStatic(YogaNodePool.class, ReactYogaConfigProvider.class);
mMockYogaNodePool = new MockYogaNodePool();
PowerMockito.when(YogaNodePool.get()).thenReturn(mMockYogaNodePool);
PowerMockito.when(ReactYogaConfigProvider.get())
.thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) {
return mock(YogaConfig.class);
}
});
} }
@Test @Test
@ -222,13 +200,7 @@ public class FabricUIManagerTest {
} }
/** /**
* Tests that cloned text nodes will reassign their yoga nodes' measure functions. * Tests that cloned text nodes will not share measure functions
*
* <p>TODO(T26729515): Currently this tests the wrong implementation. It assumes that yoga nodes
* are reused across clones and simply checks the most recently assigned measure functions of the
* shared yoga node. When yoga node cloning is implemented, this needs to be changed to mock each
* cloned shadow nodes' yoga nodes and make the same assertions on each of their measure
* functions.
*/ */
@Test @Test
public void testTextMutableClone() { public void testTextMutableClone() {
@ -236,39 +208,20 @@ public class FabricUIManagerTest {
new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
int rootTag = mFabricUIManager.addRootView(rootView); int rootTag = mFabricUIManager.addRootView(rootView);
final YogaNode yogaNode = mock(YogaNode.class);
doAnswer(
new Answer() {
@Override
public Object answer(InvocationOnMock invocation) {
when(yogaNode.isMeasureDefined()).thenReturn(true);
when(yogaNode.clone()).thenReturn(yogaNode);
when(yogaNode.cloneWithNewChildren()).thenReturn(yogaNode);
mLastYogaMeasureFunction = (YogaMeasureFunction) invocation.getArguments()[0];
return null;
}
})
.when(yogaNode)
.setMeasureFunction(any(YogaMeasureFunction.class));
mMockYogaNodePool.add(yogaNode);
ReactShadowNode text = ReactShadowNode text =
mFabricUIManager.createNode(0, ReactTextViewManager.REACT_CLASS, rootTag, null); mFabricUIManager.createNode(0, ReactTextViewManager.REACT_CLASS, rootTag, null);
YogaMeasureFunction textMeasureFunction = mLastYogaMeasureFunction;
assertThat(text.isMeasureDefined()).isTrue(); assertThat(text.isMeasureDefined()).isTrue();
ReactShadowNode textCopy = text.mutableCopy(); ReactShadowNode textCopy = text.mutableCopy();
YogaMeasureFunction textCopyMeasureFunction = mLastYogaMeasureFunction;
assertThat(textCopy.isMeasureDefined()).isTrue(); assertThat(textCopy.isMeasureDefined()).isTrue();
assertThat(textCopyMeasureFunction).isNotSameAs(textMeasureFunction);
ReactShadowNode textCopyWithNewChildren = text.mutableCopyWithNewChildren(); textCopy.setStyleWidth(200);
YogaMeasureFunction textCopyWithNewChildrenMeasureFunction = mLastYogaMeasureFunction; text.onBeforeLayout();
assertThat(textCopyWithNewChildren.isMeasureDefined()).isTrue(); text.calculateLayout();
assertThat(textCopyWithNewChildrenMeasureFunction).isNotSameAs(textMeasureFunction); textCopy.onBeforeLayout();
assertThat(textCopyWithNewChildrenMeasureFunction).isNotSameAs(textCopyMeasureFunction); textCopy.calculateLayout();
assertThat(text.getLayoutWidth()).isNotEqualTo(textCopy.getLayoutWidth());
} }
/** /**
@ -332,7 +285,6 @@ public class FabricUIManagerTest {
assertThat(node1.getLayoutX()).isEqualTo(node2.getLayoutX()); assertThat(node1.getLayoutX()).isEqualTo(node2.getLayoutX());
assertThat(node1.getLayoutY()).isEqualTo(node2.getLayoutY()); assertThat(node1.getLayoutY()).isEqualTo(node2.getLayoutY());
for (int spacingType = Spacing.LEFT; spacingType <= Spacing.ALL; spacingType++) { for (int spacingType = Spacing.LEFT; spacingType <= Spacing.ALL; spacingType++) {
assertThat(node1.getPadding(spacingType)).isEqualTo(node2.getPadding(spacingType));
assertThat(node1.getStylePadding(spacingType)).isEqualTo(node2.getStylePadding(spacingType)); assertThat(node1.getStylePadding(spacingType)).isEqualTo(node2.getStylePadding(spacingType));
} }
assertThat(node1.getStyleWidth()).isEqualTo(node2.getStyleWidth()); assertThat(node1.getStyleWidth()).isEqualTo(node2.getStyleWidth());
@ -345,43 +297,4 @@ public class FabricUIManagerTest {
node.setThemedContext(mThemedReactContext); node.setThemedContext(mThemedReactContext);
return node; return node;
} }
private static class MockYogaNodePool extends ClearableSynchronizedPool<YogaNode> {
private List<YogaNode> mMockYogaNodes;
public MockYogaNodePool() {
super(1024);
mMockYogaNodes = new LinkedList<>();
}
public void add(YogaNode... nodes) {
Collections.addAll(mMockYogaNodes, nodes);
}
@Override
public synchronized YogaNode acquire() {
if (!mMockYogaNodes.isEmpty()) {
return mMockYogaNodes.remove(0);
}
return createMockYogaNode();
}
private static YogaNode createMockYogaNode() {
final YogaNode yogaNode = mock(YogaNode.class);
when(yogaNode.clone()).thenReturn(yogaNode);
when(yogaNode.cloneWithNewChildren()).thenReturn(yogaNode);
doAnswer(
new Answer() {
@Override
public Object answer(InvocationOnMock invocation) {
when(yogaNode.isMeasureDefined()).thenReturn(true);
return null;
}
})
.when(yogaNode)
.setMeasureFunction(any(YogaMeasureFunction.class));
return yogaNode;
}
}
} }