Skip to content

Commit c10c6db

Browse files
ayc1facebook-github-bot
authored andcommitted
Move Fabric tests to OSS
Reviewed By: mdvacca Differential Revision: D7654802 fbshipit-source-id: a30c8cf062636243066a1fc73da0711442a29c76
1 parent 4469952 commit c10c6db

File tree

3 files changed

+652
-0
lines changed

3 files changed

+652
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
load("//ReactNative:DEFS.bzl", "rn_robolectric_test", "YOGA_TARGET", "react_native_dep", "react_native_target", "react_native_tests_target")
2+
3+
rn_robolectric_test(
4+
name = "fabric",
5+
srcs = glob(["**/*.java"]),
6+
contacts = ["[email protected]"],
7+
resources = glob([
8+
"**/*.txt",
9+
"**/*.json",
10+
]),
11+
visibility = [
12+
"PUBLIC",
13+
],
14+
deps = [
15+
"xplat//yoga/java:java",
16+
react_native_dep("java/com/facebook/common/executors:executors"),
17+
react_native_dep("java/com/facebook/testing/robolectric/v3:v3"),
18+
react_native_dep("third-party/java/assertj:assertj-core"),
19+
react_native_dep("third-party/java/fest:fest"),
20+
react_native_dep("third-party/java/fest:fest_android"),
21+
react_native_dep("third-party/java/guava:guava"),
22+
react_native_dep("third-party/java/jackson:jackson"),
23+
react_native_dep("third-party/java/jsr-305:jsr-305"),
24+
react_native_dep("third-party/java/jsr-330:jsr-330"),
25+
react_native_dep("third-party/java/junit:junit"),
26+
react_native_dep("third-party/java/mockito:mockito"),
27+
react_native_dep("third-party/java/robolectric3/robolectric:robolectric"),
28+
react_native_dep("libraries/fbcore/src/test/java/com/facebook/powermock:powermock"),
29+
react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"),
30+
react_native_dep("third-party/android/support/v4:lib-support-v4"),
31+
react_native_target("java/com/facebook/react:react"),
32+
react_native_target("java/com/facebook/react/bridge:bridge"),
33+
react_native_target("java/com/facebook/react/common:common"),
34+
react_native_target("java/com/facebook/react/fabric:fabric"),
35+
react_native_target("java/com/facebook/react/modules/core:core"),
36+
react_native_target("java/com/facebook/react/uimanager:uimanager"),
37+
react_native_target("java/com/facebook/react/views/text:text"),
38+
react_native_target("java/com/facebook/react/views/view:view"),
39+
react_native_tests_target("java/com/facebook/react/bridge:testhelpers"),
40+
],
41+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
// Copyright 2004-present Facebook. All Rights Reserved.
2+
package com.facebook.react.fabric;
3+
4+
import static org.fest.assertions.api.Assertions.assertThat;
5+
import static org.mockito.Mockito.mock;
6+
import static org.mockito.Mockito.when;
7+
import static org.powermock.api.mockito.PowerMockito.mockStatic;
8+
9+
import com.facebook.react.bridge.ReactApplicationContext;
10+
import com.facebook.react.common.ClearableSynchronizedPool;
11+
import com.facebook.react.fabric.FabricReconciler;
12+
import com.facebook.react.modules.core.ReactChoreographer;
13+
import com.facebook.react.uimanager.NativeViewHierarchyManager;
14+
import com.facebook.react.uimanager.ReactShadowNode;
15+
import com.facebook.react.uimanager.ReactShadowNodeImpl;
16+
import com.facebook.react.uimanager.ReactYogaConfigProvider;
17+
import com.facebook.react.uimanager.UIViewOperationQueue;
18+
import com.facebook.react.uimanager.ViewAtIndex;
19+
import com.facebook.react.uimanager.YogaNodePool;
20+
import com.facebook.testing.robolectric.v3.WithTestDefaultsRunner;
21+
import com.facebook.yoga.YogaConfig;
22+
import com.facebook.yoga.YogaNode;
23+
import java.util.ArrayList;
24+
import java.util.Arrays;
25+
import java.util.Collections;
26+
import java.util.List;
27+
import org.junit.Before;
28+
import org.junit.Test;
29+
import org.junit.runner.RunWith;
30+
import org.mockito.invocation.InvocationOnMock;
31+
import org.mockito.stubbing.Answer;
32+
import org.powermock.api.mockito.PowerMockito;
33+
import org.powermock.core.classloader.annotations.PowerMockIgnore;
34+
import org.powermock.core.classloader.annotations.PrepareForTest;
35+
import org.robolectric.RuntimeEnvironment;
36+
37+
/** Tests {@link FabricReconciler} */
38+
@PrepareForTest({
39+
ReactChoreographer.class,
40+
ReactYogaConfigProvider.class,
41+
YogaNodePool.class,
42+
})
43+
@RunWith(WithTestDefaultsRunner.class)
44+
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
45+
public class FabricReconcilerTest {
46+
47+
private FabricReconciler mFabricReconciler;
48+
private MockUIViewOperationQueue mMockUIViewOperationQueue;
49+
50+
@Before
51+
public void setUp() {
52+
ReactApplicationContext reactContext =
53+
new ReactApplicationContext(RuntimeEnvironment.application);
54+
mMockUIViewOperationQueue = new MockUIViewOperationQueue(reactContext);
55+
mFabricReconciler = new FabricReconciler(mMockUIViewOperationQueue);
56+
57+
setupHacks();
58+
}
59+
60+
@Test
61+
public void testSimpleHierarchy() {
62+
ReactShadowNode parent = createNode(0);
63+
ReactShadowNode child1 = createNode(1);
64+
ReactShadowNode child2 = createNode(2);
65+
addChildren(parent, child1, child2);
66+
67+
ReactShadowNode parentCloned = createNode(0);
68+
ReactShadowNode child3 = createNode(3);
69+
addChildren(parentCloned, child3, child2);
70+
71+
mFabricReconciler.manageChildren(parent, parentCloned);
72+
73+
List<ManageChildrenOperation> expectedOperations = new ArrayList<>();
74+
expectedOperations.add(
75+
new ManageChildrenOperation(
76+
0,
77+
new int[] {0, 1},
78+
new ViewAtIndex[] {new ViewAtIndex(3, 0), new ViewAtIndex(2, 1)},
79+
new int[] {1}));
80+
assertThat(mMockUIViewOperationQueue.getOperations()).isEqualTo(expectedOperations);
81+
}
82+
83+
@Test
84+
public void testVirtualNodes() {
85+
ReactShadowNode parent = createNode(0);
86+
ReactShadowNode child1 = createVirtualNode(1);
87+
ReactShadowNode child2 = createVirtualNode(2);
88+
ReactShadowNode child3 = createVirtualNode(3);
89+
addChildren(parent, child1, child2, child3);
90+
91+
ReactShadowNode parentCloned = createNode(0);
92+
ReactShadowNode child4 = createVirtualNode(4);
93+
addChildren(parentCloned, child1, child4, child3);
94+
95+
mFabricReconciler.manageChildren(parent, parentCloned);
96+
97+
List<ManageChildrenOperation> expectedOperations = new ArrayList<>();
98+
assertThat(mMockUIViewOperationQueue.getOperations()).isEqualTo(expectedOperations);
99+
}
100+
101+
private static ReactShadowNode createNode(int tag) {
102+
return createNode(tag, false);
103+
}
104+
105+
private static ReactShadowNode createVirtualNode(int tag) {
106+
return createNode(tag, true);
107+
}
108+
109+
private static ReactShadowNode createNode(int tag, boolean virtual) {
110+
ReactShadowNode node;
111+
if (virtual) {
112+
node = new VirtualReactShadowNode();
113+
} else {
114+
node = new ReactShadowNodeImpl();
115+
}
116+
node.setReactTag(tag);
117+
return node;
118+
}
119+
120+
private static class VirtualReactShadowNode extends ReactShadowNodeImpl {
121+
122+
@Override
123+
public boolean isVirtual() {
124+
return true;
125+
}
126+
}
127+
128+
private static void addChildren(ReactShadowNode parent, ReactShadowNode... children) {
129+
for (ReactShadowNode child : children) {
130+
parent.addChildAt(child, parent.getChildCount());
131+
}
132+
}
133+
134+
private static class ManageChildrenOperation {
135+
private int mTag;
136+
private int[] mIndicesToRemove;
137+
private ViewAtIndex[] mViewsToAdd;
138+
private int[] mTagsToRemove;
139+
140+
private ManageChildrenOperation(
141+
int tag, int[] indicesToRemove, ViewAtIndex[] viewsToAdd, int[] tagsToRemove) {
142+
mTag = tag;
143+
mIndicesToRemove = indicesToRemove;
144+
mViewsToAdd = viewsToAdd;
145+
mTagsToRemove = tagsToRemove;
146+
}
147+
148+
@Override
149+
public boolean equals(Object obj) {
150+
if (obj == null || obj.getClass() != getClass()) {
151+
return false;
152+
}
153+
ManageChildrenOperation op = (ManageChildrenOperation) obj;
154+
return mTag == op.mTag
155+
&& Arrays.equals(mIndicesToRemove, op.mIndicesToRemove)
156+
&& Arrays.equals(mViewsToAdd, op.mViewsToAdd)
157+
&& Arrays.equals(mTagsToRemove, op.mTagsToRemove);
158+
}
159+
160+
@Override
161+
public int hashCode() {
162+
return Arrays.deepHashCode(new Object[] {mTag, mIndicesToRemove, mViewsToAdd, mTagsToRemove});
163+
}
164+
165+
@Override
166+
public String toString() {
167+
return "ManageChildrenOperation \n\tindicesToRemove: "
168+
+ Arrays.toString(mIndicesToRemove)
169+
+ "\n\tviewsToAdd: "
170+
+ Arrays.toString(mViewsToAdd)
171+
+ "\n\ttagsToRemove: "
172+
+ Arrays.toString(mTagsToRemove);
173+
}
174+
}
175+
176+
private static class MockUIViewOperationQueue extends UIViewOperationQueue {
177+
178+
private List<ManageChildrenOperation> mOperations;
179+
180+
private MockUIViewOperationQueue(ReactApplicationContext context) {
181+
super(context, mock(NativeViewHierarchyManager.class), 0);
182+
mOperations = new ArrayList<>();
183+
}
184+
185+
@Override
186+
public void enqueueManageChildren(
187+
int reactTag, int[] indicesToRemove, ViewAtIndex[] viewsToAdd, int[] tagsToDelete) {
188+
mOperations.add(
189+
new ManageChildrenOperation(reactTag, indicesToRemove, viewsToAdd, tagsToDelete));
190+
}
191+
192+
public List<ManageChildrenOperation> getOperations() {
193+
return Collections.unmodifiableList(mOperations);
194+
}
195+
}
196+
197+
/** Hacks to get tests to start working end to end */
198+
private void setupHacks() {
199+
// Hack around Yoga by mocking it out until the UnsatisfiedLinkErrors are fixed t14964130
200+
mockStatic(YogaNodePool.class, ReactYogaConfigProvider.class);
201+
PowerMockito.when(YogaNodePool.get())
202+
.thenAnswer(
203+
new Answer<Object>() {
204+
@Override
205+
public Object answer(InvocationOnMock invocation) throws Exception {
206+
ClearableSynchronizedPool<YogaNode> yogaPool =
207+
mock(ClearableSynchronizedPool.class);
208+
YogaNode yogaNode = mock(YogaNode.class);
209+
when(yogaNode.clone()).thenReturn(mock(YogaNode.class));
210+
when(yogaNode.isMeasureDefined()).thenReturn(true);
211+
when(yogaPool.acquire()).thenReturn(yogaNode);
212+
return yogaPool;
213+
}
214+
});
215+
PowerMockito.when(ReactYogaConfigProvider.get())
216+
.thenAnswer(
217+
new Answer<Object>() {
218+
@Override
219+
public Object answer(InvocationOnMock invocation) {
220+
return mock(YogaConfig.class);
221+
}
222+
});
223+
}
224+
}

0 commit comments

Comments
 (0)