Moving more unit tests to open source
Reviewed By: foghina, mkonicek Differential Revision: D2865561 fb-gh-sync-id: 7aab67d205b94d657a6ec7bf81a4ecee644eabc2
This commit is contained in:
parent
fff5dc3943
commit
83fd314e37
|
@ -17,9 +17,6 @@ android_library(
|
|||
react_native_dep('third-party/java/asm:asm'),
|
||||
react_native_dep('third-party/java/sqlite:sqlite'),
|
||||
],
|
||||
deps = [
|
||||
# ':locate_android-all',
|
||||
],
|
||||
visibility = ['//ReactAndroid/...',],
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
include_defs('//ReactAndroid/DEFS')
|
||||
|
||||
robolectric3_test(
|
||||
name = 'uimanager',
|
||||
# Please change the contact to the oncall of your team
|
||||
contacts = ['oncall+fbandroid_sheriff@xmail.facebook.com'],
|
||||
srcs = glob(['**/*.java']),
|
||||
deps = [
|
||||
react_native_target('java/com/facebook/csslayout:csslayout'),
|
||||
react_native_target('java/com/facebook/react:react'),
|
||||
react_native_target('java/com/facebook/react/animation:animation'),
|
||||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||
react_native_target('java/com/facebook/react/common:common'),
|
||||
react_native_target('java/com/facebook/react/touch:touch'),
|
||||
react_native_target('java/com/facebook/react/uimanager:uimanager'),
|
||||
react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
|
||||
react_native_target('java/com/facebook/react/views/text:text'),
|
||||
react_native_target('java/com/facebook/react/views/view:view'),
|
||||
|
||||
react_native_tests_target('java/com/facebook/react/bridge:testhelpers'),
|
||||
react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'),
|
||||
react_native_dep('third-party/java/robolectric3/robolectric:robolectric'),
|
||||
react_native_dep('third-party/java/fest:fest'),
|
||||
react_native_dep('third-party/java/junit:junit'),
|
||||
react_native_dep('third-party/java/okio:okio'),
|
||||
react_native_dep('third-party/java/mockito:mockito'),
|
||||
react_native_dep('third-party/java/okhttp:okhttp'),
|
||||
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
||||
],
|
||||
visibility = [
|
||||
'PUBLIC'
|
||||
],
|
||||
)
|
||||
|
||||
project_config(
|
||||
test_target = ':uimanager',
|
||||
)
|
|
@ -0,0 +1,449 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import com.facebook.csslayout.CSSAlign;
|
||||
import com.facebook.csslayout.CSSConstants;
|
||||
import com.facebook.csslayout.CSSFlexDirection;
|
||||
import com.facebook.csslayout.CSSJustify;
|
||||
import com.facebook.csslayout.CSSPositionType;
|
||||
import com.facebook.csslayout.Spacing;
|
||||
import com.facebook.react.bridge.SimpleMap;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.modules.junit4.rule.PowerMockRule;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyFloat;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.powermock.api.mockito.PowerMockito.mockStatic;
|
||||
|
||||
@PrepareForTest({PixelUtil.class})
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
|
||||
public class LayoutPropertyApplicatorTest {
|
||||
|
||||
@Rule
|
||||
public PowerMockRule rule = new PowerMockRule();
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics());
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() {
|
||||
DisplayMetricsHolder.setDisplayMetrics(null);
|
||||
}
|
||||
|
||||
public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
|
||||
return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDimensions() {
|
||||
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
|
||||
ReactStylesDiffMap map = spy(
|
||||
buildStyles(
|
||||
"width", 10.0,
|
||||
"height", 10.0,
|
||||
"left", 10.0,
|
||||
"top", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setStyleWidth(anyFloat());
|
||||
verify(map).getFloat(eq("width"), anyFloat());
|
||||
verify(reactShadowNode).setStyleHeight(anyFloat());
|
||||
verify(map).getFloat(eq("height"), anyFloat());
|
||||
verify(reactShadowNode).setPositionLeft(anyFloat());
|
||||
verify(map).getFloat(eq("left"), anyFloat());
|
||||
verify(reactShadowNode).setPositionTop(anyFloat());
|
||||
verify(map).getFloat(eq("top"), anyFloat());
|
||||
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles());
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode, never()).setStyleWidth(anyFloat());
|
||||
verify(map, never()).getFloat(eq("width"), anyFloat());
|
||||
verify(reactShadowNode, never()).setStyleHeight(anyFloat());
|
||||
verify(map, never()).getFloat(eq("height"), anyFloat());
|
||||
verify(reactShadowNode, never()).setPositionLeft(anyFloat());
|
||||
verify(map, never()).getFloat(eq("left"), anyFloat());
|
||||
verify(reactShadowNode, never()).setPositionTop(anyFloat());
|
||||
verify(map, never()).getFloat(eq("top"), anyFloat());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlex() {
|
||||
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
|
||||
ReactStylesDiffMap map = spy(buildStyles("flex", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setFlex(anyFloat());
|
||||
verify(map).getFloat("flex", 0.f);
|
||||
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles());
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode, never()).setFlex(anyFloat());
|
||||
verify(map, never()).getFloat("flex", 0.f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPosition() {
|
||||
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
|
||||
ReactStylesDiffMap map = spy(buildStyles(
|
||||
"position", "absolute",
|
||||
"bottom", 10.0,
|
||||
"right", 5.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setPositionBottom(anyFloat());
|
||||
verify(reactShadowNode).setPositionRight(anyFloat());
|
||||
verify(reactShadowNode).setPositionType(any(CSSPositionType.class));
|
||||
verify(map).getFloat("bottom", Float.NaN);
|
||||
verify(map).getFloat("right", Float.NaN);
|
||||
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles());
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode, never()).setPositionBottom(anyFloat());
|
||||
verify(reactShadowNode, never()).setPositionRight(anyFloat());
|
||||
verify(reactShadowNode, never()).setPositionType(any(CSSPositionType.class));
|
||||
verify(map, never()).getFloat("bottom", Float.NaN);
|
||||
verify(map, never()).getFloat("right", Float.NaN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMargin() {
|
||||
// margin
|
||||
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
|
||||
ReactStylesDiffMap map = spy(buildStyles("margin", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setMargin(eq(Spacing.ALL), anyFloat());
|
||||
verify(map).getFloat("margin", CSSConstants.UNDEFINED);
|
||||
|
||||
// marginVertical
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles("marginVertical", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setMargin(eq(Spacing.VERTICAL), anyFloat());
|
||||
verify(map).getFloat("marginVertical", CSSConstants.UNDEFINED);
|
||||
|
||||
// marginHorizontal
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles("marginHorizontal", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setMargin(eq(Spacing.HORIZONTAL), anyFloat());
|
||||
verify(map).getFloat("marginHorizontal", CSSConstants.UNDEFINED);
|
||||
|
||||
// marginTop
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles("marginTop", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setMargin(eq(Spacing.TOP), anyFloat());
|
||||
verify(map).getFloat("marginTop", CSSConstants.UNDEFINED);
|
||||
|
||||
// marginBottom
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles("marginBottom", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setMargin(eq(Spacing.BOTTOM), anyFloat());
|
||||
verify(map).getFloat("marginBottom", CSSConstants.UNDEFINED);
|
||||
|
||||
// marginLeft
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles("marginLeft", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setMargin(eq(Spacing.LEFT), anyFloat());
|
||||
verify(map).getFloat("marginLeft", CSSConstants.UNDEFINED);
|
||||
|
||||
// marginRight
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles("marginRight", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setMargin(eq(Spacing.RIGHT), anyFloat());
|
||||
verify(map).getFloat("marginRight", CSSConstants.UNDEFINED);
|
||||
|
||||
// no margin
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles());
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode, never()).setMargin(anyInt(), anyFloat());
|
||||
verify(map, never()).getFloat("margin", CSSConstants.UNDEFINED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPadding() {
|
||||
// padding
|
||||
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
|
||||
ReactStylesDiffMap map = spy(buildStyles("padding", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setPadding(eq(Spacing.ALL), anyFloat());
|
||||
verify(map).getFloat("padding", CSSConstants.UNDEFINED);
|
||||
|
||||
// paddingVertical
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles("paddingVertical", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setPadding(eq(Spacing.VERTICAL), anyFloat());
|
||||
verify(map).getFloat("paddingVertical", CSSConstants.UNDEFINED);
|
||||
|
||||
// paddingHorizontal
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles("paddingHorizontal", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setPadding(eq(Spacing.HORIZONTAL), anyFloat());
|
||||
verify(map).getFloat("paddingHorizontal", CSSConstants.UNDEFINED);
|
||||
|
||||
// paddingTop
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles("paddingTop", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setPadding(eq(Spacing.TOP), anyFloat());
|
||||
verify(map).getFloat("paddingTop", CSSConstants.UNDEFINED);
|
||||
|
||||
// paddingBottom
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles("paddingBottom", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setPadding(eq(Spacing.BOTTOM), anyFloat());
|
||||
verify(map).getFloat("paddingBottom", CSSConstants.UNDEFINED);
|
||||
|
||||
// paddingLeft
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles("paddingLeft", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setPadding(eq(Spacing.LEFT), anyFloat());
|
||||
verify(map).getFloat("paddingLeft", CSSConstants.UNDEFINED);
|
||||
|
||||
// paddingRight
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles("paddingRight", 10.0));
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setPadding(eq(Spacing.RIGHT), anyFloat());
|
||||
verify(map).getFloat("paddingRight", CSSConstants.UNDEFINED);
|
||||
|
||||
// no padding
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = spy(buildStyles());
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode, never()).setPadding(anyInt(), anyFloat());
|
||||
verify(map, never()).getFloat("padding", CSSConstants.UNDEFINED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnumerations() {
|
||||
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
|
||||
ReactStylesDiffMap map = buildStyles(
|
||||
"flexDirection", "column",
|
||||
"alignSelf", "stretch",
|
||||
"alignItems", "center",
|
||||
"justifyContent", "space_between",
|
||||
"position", "relative");
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setFlexDirection(CSSFlexDirection.COLUMN);
|
||||
verify(reactShadowNode).setAlignSelf(CSSAlign.STRETCH);
|
||||
verify(reactShadowNode).setAlignItems(CSSAlign.CENTER);
|
||||
verify(reactShadowNode).setJustifyContent(CSSJustify.SPACE_BETWEEN);
|
||||
verify(reactShadowNode).setPositionType(CSSPositionType.RELATIVE);
|
||||
|
||||
reactShadowNode = spy(new LayoutShadowNode());
|
||||
map = buildStyles();
|
||||
reactShadowNode.updateProperties(map);
|
||||
|
||||
verify(reactShadowNode, never()).setFlexDirection(any(CSSFlexDirection.class));
|
||||
verify(reactShadowNode, never()).setAlignSelf(any(CSSAlign.class));
|
||||
verify(reactShadowNode, never()).setAlignItems(any(CSSAlign.class));
|
||||
verify(reactShadowNode, never()).setJustifyContent(any(CSSJustify.class));
|
||||
verify(reactShadowNode, never()).setPositionType(any(CSSPositionType.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPropertiesResetToDefault() {
|
||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||
displayMetrics.density = 1.0f;
|
||||
DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
|
||||
|
||||
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
|
||||
ReactStylesDiffMap map = buildStyles(
|
||||
"width", 10.0,
|
||||
"height", 10.0,
|
||||
"left", 10.0,
|
||||
"top", 10.0,
|
||||
"flex", 1.0,
|
||||
"padding", 10.0,
|
||||
"marginLeft", 10.0,
|
||||
"borderTopWidth", 10.0,
|
||||
"flexDirection", "row",
|
||||
"alignSelf", "stretch",
|
||||
"alignItems", "center",
|
||||
"justifyContent", "space_between",
|
||||
"position", "absolute");
|
||||
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setStyleWidth(10.f);
|
||||
verify(reactShadowNode).setStyleHeight(10.f);
|
||||
verify(reactShadowNode).setPositionLeft(10.f);
|
||||
verify(reactShadowNode).setPositionTop(10.f);
|
||||
verify(reactShadowNode).setFlex(1.0f);
|
||||
verify(reactShadowNode).setPadding(Spacing.ALL, 10.f);
|
||||
verify(reactShadowNode).setMargin(Spacing.LEFT, 10.f);
|
||||
verify(reactShadowNode).setBorder(Spacing.TOP, 10.f);
|
||||
verify(reactShadowNode).setFlexDirection(CSSFlexDirection.ROW);
|
||||
verify(reactShadowNode).setAlignSelf(CSSAlign.STRETCH);
|
||||
verify(reactShadowNode).setAlignItems(CSSAlign.CENTER);
|
||||
verify(reactShadowNode).setJustifyContent(CSSJustify.SPACE_BETWEEN);
|
||||
verify(reactShadowNode).setPositionType(CSSPositionType.ABSOLUTE);
|
||||
|
||||
map = buildStyles(
|
||||
"width", null,
|
||||
"height", null,
|
||||
"left", null,
|
||||
"top", null,
|
||||
"flex", null,
|
||||
"padding", null,
|
||||
"marginLeft", null,
|
||||
"borderTopWidth", null,
|
||||
"flexDirection", null,
|
||||
"alignSelf", null,
|
||||
"alignItems", null,
|
||||
"justifyContent", null,
|
||||
"position", null);
|
||||
|
||||
reset(reactShadowNode);
|
||||
reactShadowNode.updateProperties(map);
|
||||
verify(reactShadowNode).setStyleWidth(CSSConstants.UNDEFINED);
|
||||
verify(reactShadowNode).setStyleHeight(CSSConstants.UNDEFINED);
|
||||
verify(reactShadowNode).setPositionLeft(CSSConstants.UNDEFINED);
|
||||
verify(reactShadowNode).setPositionTop(CSSConstants.UNDEFINED);
|
||||
verify(reactShadowNode).setFlex(0.f);
|
||||
verify(reactShadowNode).setPadding(Spacing.ALL, CSSConstants.UNDEFINED);
|
||||
verify(reactShadowNode).setMargin(Spacing.LEFT, CSSConstants.UNDEFINED);
|
||||
verify(reactShadowNode).setBorder(Spacing.TOP, CSSConstants.UNDEFINED);
|
||||
verify(reactShadowNode).setFlexDirection(CSSFlexDirection.COLUMN);
|
||||
verify(reactShadowNode).setAlignSelf(CSSAlign.AUTO);
|
||||
verify(reactShadowNode).setAlignItems(CSSAlign.STRETCH);
|
||||
verify(reactShadowNode).setJustifyContent(CSSJustify.FLEX_START);
|
||||
verify(reactShadowNode).setPositionType(CSSPositionType.RELATIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSettingDefaultStyleValues() {
|
||||
mockStatic(PixelUtil.class);
|
||||
when(PixelUtil.toPixelFromDIP(anyFloat())).thenAnswer(
|
||||
new Answer() {
|
||||
@Override
|
||||
public Float answer(InvocationOnMock invocation) throws Throwable {
|
||||
Object[] args = invocation.getArguments();
|
||||
return (Float) args[0];
|
||||
}
|
||||
});
|
||||
|
||||
LayoutShadowNode[] nodes = new LayoutShadowNode[7];
|
||||
for (int idx = 0; idx < nodes.length; idx++) {
|
||||
nodes[idx] = new LayoutShadowNode();
|
||||
nodes[idx].setDefaultPadding(Spacing.LEFT, 15);
|
||||
nodes[idx].setDefaultPadding(Spacing.TOP, 25);
|
||||
nodes[idx].setDefaultPadding(Spacing.RIGHT, 35);
|
||||
nodes[idx].setDefaultPadding(Spacing.BOTTOM, 45);
|
||||
}
|
||||
|
||||
ReactStylesDiffMap[] mapNodes = new ReactStylesDiffMap[7];
|
||||
mapNodes[0] = buildStyles("paddingLeft", 10.0, "paddingHorizontal", 5.0);
|
||||
mapNodes[1] = buildStyles("padding", 10.0, "paddingTop", 5.0);
|
||||
mapNodes[2] = buildStyles("paddingLeft", 10.0, "paddingVertical", 5.0);
|
||||
mapNodes[3] = buildStyles("paddingBottom", 10.0, "paddingHorizontal", 5.0);
|
||||
mapNodes[4] = buildStyles("padding", null, "paddingTop", 5.0);
|
||||
mapNodes[5] = buildStyles(
|
||||
"paddingRight", 10.0,
|
||||
"paddingHorizontal", null,
|
||||
"paddingVertical", 7.0);
|
||||
mapNodes[6] = buildStyles("margin", 5.0);
|
||||
|
||||
for (int idx = 0; idx < nodes.length; idx++) {
|
||||
nodes[idx].updateProperties(mapNodes[idx]);
|
||||
}
|
||||
|
||||
assertEquals(10.0, nodes[0].getPadding().get(Spacing.LEFT), .0001);
|
||||
assertEquals(25.0, nodes[0].getPadding().get(Spacing.TOP), .0001);
|
||||
assertEquals(5.0, nodes[0].getPadding().get(Spacing.RIGHT), .0001);
|
||||
assertEquals(45.0, nodes[0].getPadding().get(Spacing.BOTTOM), .0001);
|
||||
|
||||
assertEquals(10.0, nodes[1].getPadding().get(Spacing.LEFT), .0001);
|
||||
assertEquals(5.0, nodes[1].getPadding().get(Spacing.TOP), .0001);
|
||||
assertEquals(10.0, nodes[1].getPadding().get(Spacing.RIGHT), .0001);
|
||||
assertEquals(10.0, nodes[1].getPadding().get(Spacing.BOTTOM), .0001);
|
||||
|
||||
assertEquals(10.0, nodes[2].getPadding().get(Spacing.LEFT), .0001);
|
||||
assertEquals(5.0, nodes[2].getPadding().get(Spacing.TOP), .0001);
|
||||
assertEquals(35.0, nodes[2].getPadding().get(Spacing.RIGHT), .0001);
|
||||
assertEquals(5.0, nodes[2].getPadding().get(Spacing.BOTTOM), .0001);
|
||||
|
||||
assertEquals(5.0, nodes[3].getPadding().get(Spacing.LEFT), .0001);
|
||||
assertEquals(25.0, nodes[3].getPadding().get(Spacing.TOP), .0001);
|
||||
assertEquals(5.0, nodes[3].getPadding().get(Spacing.RIGHT), .0001);
|
||||
assertEquals(10.0, nodes[3].getPadding().get(Spacing.BOTTOM), .0001);
|
||||
|
||||
assertEquals(15.0, nodes[4].getPadding().get(Spacing.LEFT), .0001);
|
||||
assertEquals(5.0, nodes[4].getPadding().get(Spacing.TOP), .0001);
|
||||
assertEquals(35.0, nodes[4].getPadding().get(Spacing.RIGHT), .0001);
|
||||
assertEquals(45.0, nodes[4].getPadding().get(Spacing.BOTTOM), .0001);
|
||||
|
||||
assertEquals(15.0, nodes[5].getPadding().get(Spacing.LEFT), .0001);
|
||||
assertEquals(7.0, nodes[5].getPadding().get(Spacing.TOP), .0001);
|
||||
assertEquals(10.0, nodes[5].getPadding().get(Spacing.RIGHT), .0001);
|
||||
assertEquals(7.0, nodes[5].getPadding().get(Spacing.BOTTOM), .0001);
|
||||
|
||||
assertEquals(15.0, nodes[6].getPadding().get(Spacing.LEFT), .0001);
|
||||
assertEquals(25.0, nodes[6].getPadding().get(Spacing.TOP), .0001);
|
||||
assertEquals(35.0, nodes[6].getPadding().get(Spacing.RIGHT), .0001);
|
||||
assertEquals(45.0, nodes[6].getPadding().get(Spacing.BOTTOM), .0001);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.modules.junit4.rule.PowerMockRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
/**
|
||||
* Test that verifies that spec of methods annotated with @ReactProp is correct
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
|
||||
public class ReactPropAnnotationSetterSpecTest {
|
||||
|
||||
@Rule
|
||||
public PowerMockRule rule = new PowerMockRule();
|
||||
|
||||
private abstract class BaseViewManager extends ViewManager<View, ReactShadowNode> {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "IgnoredName";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactShadowNode createShadowNodeInstance() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ReactShadowNode> getShadowNodeClass() {
|
||||
return ReactShadowNode.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View createViewInstance(ThemedReactContext reactContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateExtraData(View root, Object extraData) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testMethodWithWongNumberOfParams() {
|
||||
new BaseViewManager() {
|
||||
@ReactProp(name = "prop")
|
||||
public void setterWithIncorrectNumberOfArgs(View v, boolean value, boolean otherValue) {
|
||||
}
|
||||
}.getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testMethodWithTooFewParams() {
|
||||
new BaseViewManager() {
|
||||
@ReactProp(name = "prop")
|
||||
public void setterWithTooFewParams(View v) {
|
||||
}
|
||||
}.getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testUnsupportedPropValueType() {
|
||||
new BaseViewManager() {
|
||||
@ReactProp(name = "prop")
|
||||
public void setterWithUnsupportedValueType(View v, Date value) {
|
||||
}
|
||||
}.getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testSetterWIthNonViewParam() {
|
||||
new BaseViewManager() {
|
||||
@ReactProp(name = "prop")
|
||||
public void setterWithNonViewParam(Object v, boolean value) {
|
||||
}
|
||||
}.getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testGroupInvalidNumberOfParams() {
|
||||
new BaseViewManager() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWIthInvalidNumberOfParams(View v, int index, float value, float other) {
|
||||
}
|
||||
}.getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testGroupTooFewParams() {
|
||||
new BaseViewManager() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWIthTooFewParams(View v, int index) {
|
||||
}
|
||||
}.getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testGroupNoIndexParam() {
|
||||
new BaseViewManager() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWithoutIndexParam(View v, float value, float sth) {
|
||||
}
|
||||
}.getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testGroupNoViewParam() {
|
||||
new BaseViewManager() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWithoutViewParam(Object v, int index, float value) {
|
||||
}
|
||||
}.getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testGroupUnsupportedPropType() {
|
||||
new BaseViewManager() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWithUnsupportedPropType(View v, int index, long value) {
|
||||
}
|
||||
}.getNativeProps();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,493 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.SimpleArray;
|
||||
import com.facebook.react.bridge.SimpleMap;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.modules.junit4.rule.PowerMockRule;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
/**
|
||||
* Test updating view through {@link ViewManager} with {@link ReactProp} and {@link ReactPropGroup}
|
||||
* annotations.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
|
||||
public class ReactPropAnnotationSetterTest {
|
||||
|
||||
@Rule
|
||||
public PowerMockRule rule = new PowerMockRule();
|
||||
|
||||
public interface ViewManagerUpdatesReceiver {
|
||||
void onBooleanSetterCalled(boolean value);
|
||||
void onIntSetterCalled(int value);
|
||||
void onDoubleSetterCalled(double value);
|
||||
void onFloatSetterCalled(float value);
|
||||
void onStringSetterCalled(String value);
|
||||
void onBoxedBooleanSetterCalled(Boolean value);
|
||||
void onBoxedIntSetterCalled(Integer value);
|
||||
void onArraySetterCalled(ReadableArray value);
|
||||
void onMapSetterCalled(ReadableMap value);
|
||||
void onFloatGroupPropSetterCalled(int index, float value);
|
||||
void onIntGroupPropSetterCalled(int index, int value);
|
||||
void onBoxedIntGroupPropSetterCalled(int index, Integer value);
|
||||
}
|
||||
|
||||
private class ViewManagerUnderTest extends ViewManager<View, ReactShadowNode> {
|
||||
|
||||
final ViewManagerUpdatesReceiver mViewManagerUpdatesReceiver;
|
||||
|
||||
private ViewManagerUnderTest(ViewManagerUpdatesReceiver viewManagerUpdatesReceiver) {
|
||||
mViewManagerUpdatesReceiver = viewManagerUpdatesReceiver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "RedpandasLivestreamVideoView";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactShadowNode createShadowNodeInstance() {
|
||||
fail("This method should not be executed as a part of this test");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ReactShadowNode> getShadowNodeClass() {
|
||||
return ReactShadowNode.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View createViewInstance(ThemedReactContext reactContext) {
|
||||
fail("This method should not be executed as a part of this test");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateExtraData(View root, Object extraData) {
|
||||
fail("This method should not be executed as a part of this test");
|
||||
}
|
||||
|
||||
@ReactProp(name = "boolProp")
|
||||
public void setBoolProp(View v, boolean value) {
|
||||
mViewManagerUpdatesReceiver.onBooleanSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "boolPropWithDefault", defaultBoolean = true)
|
||||
public void setBoolPropWithDefault(View v, boolean value) {
|
||||
mViewManagerUpdatesReceiver.onBooleanSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "intProp")
|
||||
public void setIntProp(View v, int value) {
|
||||
mViewManagerUpdatesReceiver.onIntSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "intPropWithDefault", defaultInt = 7168)
|
||||
public void setIntPropWithDefault(View v, int value) {
|
||||
mViewManagerUpdatesReceiver.onIntSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "floatProp")
|
||||
public void setFloatProp(View v, float value) {
|
||||
mViewManagerUpdatesReceiver.onFloatSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "floatPropWithDefault", defaultFloat = 14.0f)
|
||||
public void setFloatPropWithDefault(View v, float value) {
|
||||
mViewManagerUpdatesReceiver.onFloatSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "doubleProp")
|
||||
public void setDoubleProp(View v, double value) {
|
||||
mViewManagerUpdatesReceiver.onDoubleSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "doublePropWithDefault", defaultDouble = -88.0)
|
||||
public void setDoublePropWithDefault(View v, double value) {
|
||||
mViewManagerUpdatesReceiver.onDoubleSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "stringProp")
|
||||
public void setStringProp(View v, String value) {
|
||||
mViewManagerUpdatesReceiver.onStringSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "boxedBoolProp")
|
||||
public void setBoxedBoolProp(View v, Boolean value) {
|
||||
mViewManagerUpdatesReceiver.onBoxedBooleanSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "boxedIntProp")
|
||||
public void setBoxedIntProp(View v, Integer value) {
|
||||
mViewManagerUpdatesReceiver.onBoxedIntSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "arrayProp")
|
||||
public void setArrayProp(View v, ReadableArray value) {
|
||||
mViewManagerUpdatesReceiver.onArraySetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "mapProp")
|
||||
public void setMapProp(View v, ReadableMap value) {
|
||||
mViewManagerUpdatesReceiver.onMapSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactPropGroup(names = {
|
||||
"floatGroupPropFirst",
|
||||
"floatGroupPropSecond",
|
||||
})
|
||||
public void setFloatGroupProp(View v, int index, float value) {
|
||||
mViewManagerUpdatesReceiver.onFloatGroupPropSetterCalled(index, value);
|
||||
}
|
||||
|
||||
@ReactPropGroup(names = {
|
||||
"floatGroupPropWithDefaultFirst",
|
||||
"floatGroupPropWithDefaultSecond",
|
||||
}, defaultFloat = -100.0f)
|
||||
public void setFloatGroupPropWithDefault(View v, int index, float value) {
|
||||
mViewManagerUpdatesReceiver.onFloatGroupPropSetterCalled(index, value);
|
||||
}
|
||||
|
||||
@ReactPropGroup(names = {
|
||||
"intGroupPropFirst",
|
||||
"intGroupPropSecond"
|
||||
})
|
||||
public void setIntGroupProp(View v, int index, int value) {
|
||||
mViewManagerUpdatesReceiver.onIntGroupPropSetterCalled(index, value);
|
||||
}
|
||||
|
||||
@ReactPropGroup(names = {
|
||||
"intGroupPropWithDefaultFirst",
|
||||
"intGroupPropWithDefaultSecond"
|
||||
}, defaultInt = 555)
|
||||
public void setIntGroupPropWithDefault(View v, int index, int value) {
|
||||
mViewManagerUpdatesReceiver.onIntGroupPropSetterCalled(index, value);
|
||||
}
|
||||
|
||||
@ReactPropGroup(names = {
|
||||
"boxedIntGroupPropFirst",
|
||||
"boxedIntGroupPropSecond",
|
||||
})
|
||||
public void setBoxedIntGroupProp(View v, int index, Integer value) {
|
||||
mViewManagerUpdatesReceiver.onBoxedIntGroupPropSetterCalled(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static ReactStylesDiffMap buildStyles(Object... keysAndValues) {
|
||||
return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
|
||||
}
|
||||
|
||||
private ViewManagerUnderTest mViewManager;
|
||||
private ViewManagerUpdatesReceiver mUpdatesReceiverMock;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mUpdatesReceiverMock = mock(ViewManagerUpdatesReceiver.class);
|
||||
mViewManager = new ViewManagerUnderTest(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBooleanSetter() {
|
||||
mViewManager.updateProperties(null, buildStyles("boolProp", true));
|
||||
verify(mUpdatesReceiverMock).onBooleanSetterCalled(true);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("boolProp", false));
|
||||
verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("boolProp", null));
|
||||
verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("boolPropWithDefault", false));
|
||||
verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("boolPropWithDefault", null));
|
||||
verify(mUpdatesReceiverMock).onBooleanSetterCalled(true);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntSetter() {
|
||||
mViewManager.updateProperties(null, buildStyles("intProp", 13));
|
||||
verify(mUpdatesReceiverMock).onIntSetterCalled(13);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("intProp", null));
|
||||
verify(mUpdatesReceiverMock).onIntSetterCalled(0);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("intPropWithDefault", -1));
|
||||
verify(mUpdatesReceiverMock).onIntSetterCalled(-1);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("intPropWithDefault", null));
|
||||
verify(mUpdatesReceiverMock).onIntSetterCalled(7168);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleSetter() {
|
||||
mViewManager.updateProperties(null, buildStyles("doubleProp", 13.0));
|
||||
verify(mUpdatesReceiverMock).onDoubleSetterCalled(13.0);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("doubleProp", null));
|
||||
verify(mUpdatesReceiverMock).onDoubleSetterCalled(0.0);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("doublePropWithDefault", -1.0));
|
||||
verify(mUpdatesReceiverMock).onDoubleSetterCalled(-1.0);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("doublePropWithDefault", null));
|
||||
verify(mUpdatesReceiverMock).onDoubleSetterCalled(-88.0);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloatSetter() {
|
||||
mViewManager.updateProperties(null, buildStyles("floatProp", 13.0));
|
||||
verify(mUpdatesReceiverMock).onFloatSetterCalled(13.0f);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("floatProp", null));
|
||||
verify(mUpdatesReceiverMock).onFloatSetterCalled(0.0f);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("floatPropWithDefault", -1.0));
|
||||
verify(mUpdatesReceiverMock).onFloatSetterCalled(-1.0f);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("floatPropWithDefault", null));
|
||||
verify(mUpdatesReceiverMock).onFloatSetterCalled(14.0f);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringSetter() {
|
||||
mViewManager.updateProperties(null, buildStyles("stringProp", "someRandomString"));
|
||||
verify(mUpdatesReceiverMock).onStringSetterCalled("someRandomString");
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("stringProp", null));
|
||||
verify(mUpdatesReceiverMock).onStringSetterCalled(null);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoxedBooleanSetter() {
|
||||
mViewManager.updateProperties(null, buildStyles("boxedBoolProp", true));
|
||||
verify(mUpdatesReceiverMock).onBoxedBooleanSetterCalled(Boolean.TRUE);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("boxedBoolProp", false));
|
||||
verify(mUpdatesReceiverMock).onBoxedBooleanSetterCalled(Boolean.FALSE);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("boxedBoolProp", null));
|
||||
verify(mUpdatesReceiverMock).onBoxedBooleanSetterCalled(null);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoxedIntSetter() {
|
||||
mViewManager.updateProperties(null, buildStyles("boxedIntProp", 55));
|
||||
verify(mUpdatesReceiverMock).onBoxedIntSetterCalled(Integer.valueOf(55));
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("boxedIntProp", null));
|
||||
verify(mUpdatesReceiverMock).onBoxedIntSetterCalled(null);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArraySetter() {
|
||||
ReadableArray array = new SimpleArray();
|
||||
mViewManager.updateProperties(null, buildStyles("arrayProp", array));
|
||||
verify(mUpdatesReceiverMock).onArraySetterCalled(array);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("arrayProp", null));
|
||||
verify(mUpdatesReceiverMock).onArraySetterCalled(null);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSetter() {
|
||||
ReadableMap map = new SimpleMap();
|
||||
mViewManager.updateProperties(null, buildStyles("mapProp", map));
|
||||
verify(mUpdatesReceiverMock).onMapSetterCalled(map);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("mapProp", null));
|
||||
verify(mUpdatesReceiverMock).onMapSetterCalled(null);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloatGroupSetter() {
|
||||
mViewManager.updateProperties(null, buildStyles("floatGroupPropFirst", 11.0));
|
||||
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(0, 11.0f);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("floatGroupPropSecond", -111.0));
|
||||
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(1, -111.0f);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("floatGroupPropSecond", null));
|
||||
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(1, 0.0f);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("floatGroupPropWithDefaultFirst", null));
|
||||
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(0, -100.0f);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntGroupSetter() {
|
||||
mViewManager.updateProperties(null, buildStyles("intGroupPropFirst", -7));
|
||||
verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(0, -7);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("intGroupPropSecond", -77));
|
||||
verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(1, -77);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("intGroupPropSecond", null));
|
||||
verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(1, 0);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("intGroupPropWithDefaultFirst", 5));
|
||||
verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(0, 5);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("intGroupPropWithDefaultFirst", null));
|
||||
verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(0, 555);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("intGroupPropWithDefaultSecond", null));
|
||||
verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(1, 555);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringGroupSetter() {
|
||||
mViewManager.updateProperties(null, buildStyles("boxedIntGroupPropFirst", -7));
|
||||
verify(mUpdatesReceiverMock).onBoxedIntGroupPropSetterCalled(0, -7);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("boxedIntGroupPropSecond", 12345));
|
||||
verify(mUpdatesReceiverMock).onBoxedIntGroupPropSetterCalled(1, 12345);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mViewManager.updateProperties(null, buildStyles("boxedIntGroupPropSecond", null));
|
||||
verify(mUpdatesReceiverMock).onBoxedIntGroupPropSetterCalled(1, null);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test(expected = JSApplicationIllegalArgumentException.class)
|
||||
public void testFailToUpdateBoolPropWithMap() {
|
||||
mViewManager.updateProperties(null, buildStyles("boolProp", new SimpleMap()));
|
||||
}
|
||||
|
||||
@Test(expected = JSApplicationIllegalArgumentException.class)
|
||||
public void testFailToUpdateStringPropWithDouble() {
|
||||
mViewManager.updateProperties(null, buildStyles("stringProp", 14.5));
|
||||
}
|
||||
|
||||
@Test(expected = JSApplicationIllegalArgumentException.class)
|
||||
public void testFailToUpdateDoublePropWithString() {
|
||||
mViewManager.updateProperties(null, buildStyles("doubleProp", "hello"));
|
||||
}
|
||||
|
||||
@Test(expected = JSApplicationIllegalArgumentException.class)
|
||||
public void testFailToUpdateIntPropWithDouble() {
|
||||
mViewManager.updateProperties(null, buildStyles("intProp", -7.4));
|
||||
}
|
||||
|
||||
@Test(expected = JSApplicationIllegalArgumentException.class)
|
||||
public void testFailToUpdateArrayPropWithBool() {
|
||||
mViewManager.updateProperties(null, buildStyles("arrayProp", false));
|
||||
}
|
||||
|
||||
@Test(expected = JSApplicationIllegalArgumentException.class)
|
||||
public void testFailToUpdateMapPropWithArray() {
|
||||
mViewManager.updateProperties(null, buildStyles("mapProp", new SimpleArray()));
|
||||
}
|
||||
|
||||
@Test(expected = JSApplicationIllegalArgumentException.class)
|
||||
public void testFailToUpdateBoxedIntPropWithBoxedDouble() {
|
||||
mViewManager.updateProperties(null, buildStyles("boxedIntProp", Double.valueOf(1)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.modules.junit4.rule.PowerMockRule;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.fest.assertions.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* Verifies that prop constants are generated properly based on {@code ReactProp} annotation.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
|
||||
public class ReactPropConstantsTest {
|
||||
|
||||
@Rule
|
||||
public PowerMockRule rule = new PowerMockRule();
|
||||
|
||||
private class ViewManagerUnderTest extends ViewManager<View, ReactShadowNode> {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "SomeView";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactShadowNode createShadowNodeInstance() {
|
||||
fail("This method should not be executed as a part of this test");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View createViewInstance(ThemedReactContext reactContext) {
|
||||
fail("This method should not be executed as a part of this test");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ReactShadowNode> getShadowNodeClass() {
|
||||
return ReactShadowNode.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateExtraData(View root, Object extraData) {
|
||||
fail("This method should not be executed as a part of this test");
|
||||
}
|
||||
|
||||
@ReactProp(name = "boolProp")
|
||||
public void setBoolProp(View v, boolean value) {
|
||||
}
|
||||
|
||||
@ReactProp(name = "intProp")
|
||||
public void setIntProp(View v, int value) {
|
||||
}
|
||||
|
||||
@ReactProp(name = "floatProp")
|
||||
public void setFloatProp(View v, float value) {
|
||||
}
|
||||
|
||||
@ReactProp(name = "doubleProp")
|
||||
public void setDoubleProp(View v, double value) {
|
||||
}
|
||||
|
||||
@ReactProp(name = "stringProp")
|
||||
public void setStringProp(View v, String value) {
|
||||
}
|
||||
|
||||
@ReactProp(name = "boxedBoolProp")
|
||||
public void setBoxedBoolProp(View v, Boolean value) {
|
||||
}
|
||||
|
||||
@ReactProp(name = "boxedIntProp")
|
||||
public void setBoxedIntProp(View v, Integer value) {
|
||||
}
|
||||
|
||||
@ReactProp(name = "arrayProp")
|
||||
public void setArrayProp(View v, ReadableArray value) {
|
||||
}
|
||||
|
||||
@ReactProp(name = "mapProp")
|
||||
public void setMapProp(View v, ReadableMap value) {
|
||||
}
|
||||
|
||||
@ReactPropGroup(names = {
|
||||
"floatGroupPropFirst",
|
||||
"floatGroupPropSecond",
|
||||
})
|
||||
public void setFloatGroupProp(View v, int index, float value) {
|
||||
}
|
||||
|
||||
@ReactPropGroup(names = {
|
||||
"intGroupPropFirst",
|
||||
"intGroupPropSecond"
|
||||
})
|
||||
public void setIntGroupProp(View v, int index, int value) {
|
||||
}
|
||||
|
||||
@ReactPropGroup(names = {
|
||||
"boxedIntGroupPropFirst",
|
||||
"boxedIntGroupPropSecond",
|
||||
})
|
||||
public void setBoxedIntGroupProp(View v, int index, Integer value) {
|
||||
}
|
||||
|
||||
@ReactProp(name = "customIntProp", customType = "date")
|
||||
public void customIntProp(View v, int value) {
|
||||
}
|
||||
|
||||
@ReactPropGroup(names = {
|
||||
"customBoxedIntGroupPropFirst",
|
||||
"customBoxedIntGroupPropSecond"
|
||||
}, customType = "color")
|
||||
public void customIntGroupProp(View v, int index, Integer value) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNativePropsIncludeCorrectTypes() {
|
||||
List<ViewManager> viewManagers = Arrays.<ViewManager>asList(new ViewManagerUnderTest());
|
||||
ReactApplicationContext reactContext = new ReactApplicationContext(RuntimeEnvironment.application);
|
||||
UIManagerModule uiManagerModule = new UIManagerModule(
|
||||
reactContext,
|
||||
viewManagers,
|
||||
new UIImplementation(reactContext, viewManagers));
|
||||
Map<String, String> constants =
|
||||
(Map) valueAtPath(uiManagerModule.getConstants(), "SomeView", "NativeProps");
|
||||
assertThat(constants).isEqualTo(
|
||||
MapBuilder.<String, String>builder()
|
||||
.put("boolProp", "boolean")
|
||||
.put("intProp", "number")
|
||||
.put("doubleProp", "number")
|
||||
.put("floatProp", "number")
|
||||
.put("stringProp", "String")
|
||||
.put("boxedBoolProp", "boolean")
|
||||
.put("boxedIntProp", "number")
|
||||
.put("arrayProp", "Array")
|
||||
.put("mapProp", "Map")
|
||||
.put("floatGroupPropFirst", "number")
|
||||
.put("floatGroupPropSecond", "number")
|
||||
.put("intGroupPropFirst", "number")
|
||||
.put("intGroupPropSecond", "number")
|
||||
.put("boxedIntGroupPropFirst", "number")
|
||||
.put("boxedIntGroupPropSecond", "number")
|
||||
.put("customIntProp", "date")
|
||||
.put("customBoxedIntGroupPropFirst", "color")
|
||||
.put("customBoxedIntGroupPropSecond", "color")
|
||||
.build());
|
||||
}
|
||||
|
||||
private static Object valueAtPath(Map nestedMap, String... keyPath) {
|
||||
assertThat(keyPath).isNotEmpty();
|
||||
Object value = nestedMap;
|
||||
for (String key : keyPath) {
|
||||
assertThat(value).isInstanceOf(Map.class);
|
||||
nestedMap = (Map) value;
|
||||
assertThat(nestedMap).containsKey(key);
|
||||
value = nestedMap.get(key);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.modules.junit4.rule.PowerMockRule;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
import static com.facebook.react.uimanager.ReactPropAnnotationSetterTest.ViewManagerUpdatesReceiver;
|
||||
import static com.facebook.react.uimanager.ReactPropAnnotationSetterTest.buildStyles;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
/**
|
||||
* Test {@link ReactProp} annotation for {@link ReactShadowNode}. More comprahensive test of this
|
||||
* annotation can be found in {@link ReactPropAnnotationSetterTest} where we test all possible types
|
||||
* of properties to be updated.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
|
||||
public class ReactPropForShadowNodeSetterTest {
|
||||
|
||||
@Rule
|
||||
public PowerMockRule rule = new PowerMockRule();
|
||||
|
||||
private class ShadowViewUnderTest extends ReactShadowNode {
|
||||
|
||||
private ViewManagerUpdatesReceiver mViewManagerUpdatesReceiver;
|
||||
|
||||
private ShadowViewUnderTest(ViewManagerUpdatesReceiver viewManagerUpdatesReceiver) {
|
||||
mViewManagerUpdatesReceiver = viewManagerUpdatesReceiver;
|
||||
}
|
||||
|
||||
@ReactProp(name = "boolProp")
|
||||
public void setBoolProp(boolean value) {
|
||||
mViewManagerUpdatesReceiver.onBooleanSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "stringProp")
|
||||
public void setStringProp(@Nullable String value) {
|
||||
mViewManagerUpdatesReceiver.onStringSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "boxedIntProp")
|
||||
public void setBoxedIntProp(@Nullable Integer value) {
|
||||
mViewManagerUpdatesReceiver.onBoxedIntSetterCalled(value);
|
||||
}
|
||||
|
||||
@ReactPropGroup(names = {
|
||||
"floatGroupPropFirst",
|
||||
"floatGroupPropSecond",
|
||||
})
|
||||
public void setFloatGroupProp(int index, float value) {
|
||||
mViewManagerUpdatesReceiver.onFloatGroupPropSetterCalled(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
private ViewManagerUpdatesReceiver mUpdatesReceiverMock;
|
||||
private ShadowViewUnderTest mShadowView;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mUpdatesReceiverMock = mock(ViewManagerUpdatesReceiver.class);
|
||||
mShadowView = new ShadowViewUnderTest(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBooleanSetter() {
|
||||
mShadowView.updateProperties(buildStyles("boolProp", true));
|
||||
verify(mUpdatesReceiverMock).onBooleanSetterCalled(true);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mShadowView.updateProperties(buildStyles("boolProp", false));
|
||||
verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mShadowView.updateProperties(buildStyles("boolProp", null));
|
||||
verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringSetter() {
|
||||
mShadowView.updateProperties(buildStyles("stringProp", "someRandomString"));
|
||||
verify(mUpdatesReceiverMock).onStringSetterCalled("someRandomString");
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mShadowView.updateProperties(buildStyles("stringProp", null));
|
||||
verify(mUpdatesReceiverMock).onStringSetterCalled(null);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloatGroupSetter() {
|
||||
mShadowView.updateProperties(buildStyles("floatGroupPropFirst", 11.0));
|
||||
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(0, 11.0f);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mShadowView.updateProperties(buildStyles("floatGroupPropSecond", -111.0));
|
||||
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(1, -111.0f);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
|
||||
mShadowView.updateProperties(buildStyles("floatGroupPropSecond", null));
|
||||
verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(1, 0.0f);
|
||||
verifyNoMoreInteractions(mUpdatesReceiverMock);
|
||||
reset(mUpdatesReceiverMock);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.annotations.ReactPropGroup;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.modules.junit4.rule.PowerMockRule;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
/**
|
||||
* Test that verifies that spec of methods annotated with @ReactProp in {@link ReactShadowNode} is
|
||||
* correct
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
|
||||
public class ReactPropForShadowNodeSpecTest {
|
||||
|
||||
@Rule
|
||||
public PowerMockRule rule = new PowerMockRule();
|
||||
|
||||
private static class BaseViewManager extends ViewManager {
|
||||
|
||||
private final Class<? extends ReactShadowNode> mShadowNodeClass;
|
||||
|
||||
private BaseViewManager(Class<? extends ReactShadowNode> shadowNodeClass) {
|
||||
mShadowNodeClass = shadowNodeClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "IgnoredName";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactShadowNode createShadowNodeInstance() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getShadowNodeClass() {
|
||||
return mShadowNodeClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View createViewInstance(ThemedReactContext reactContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateExtraData(View root, Object extraData) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testMethodWithWrongNumberOfParams() {
|
||||
new BaseViewManager(new ReactShadowNode() {
|
||||
@ReactProp(name = "prop")
|
||||
public void setterWithIncorrectNumberOfArgs(boolean value, int anotherValue) {
|
||||
}
|
||||
}.getClass()).getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testMethodWithTooFewParams() {
|
||||
new BaseViewManager(new ReactShadowNode() {
|
||||
@ReactProp(name = "prop")
|
||||
public void setterWithNoArgs() {
|
||||
}
|
||||
}.getClass()).getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testUnsupportedValueType() {
|
||||
new BaseViewManager(new ReactShadowNode() {
|
||||
@ReactProp(name = "prop")
|
||||
public void setterWithMap(Map value) {
|
||||
}
|
||||
}.getClass()).getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testGroupInvalidNumberOfParams() {
|
||||
new BaseViewManager(new ReactShadowNode() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWithTooManyParams(int index, float value, boolean bool) {
|
||||
}
|
||||
}.getClass()).getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testGroupTooFewParams() {
|
||||
new BaseViewManager(new ReactShadowNode() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWithTooManyParams(int index) {
|
||||
}
|
||||
}.getClass()).getNativeProps();
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testGroupNoIndexParam() {
|
||||
new BaseViewManager(new ReactShadowNode() {
|
||||
@ReactPropGroup(names = {"prop1", "prop2"})
|
||||
public void setterWithTooManyParams(float value, boolean bool) {
|
||||
}
|
||||
}.getClass()).getNativeProps();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.touch.JSResponderHandler;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactTestHelper;
|
||||
import com.facebook.react.bridge.SimpleMap;
|
||||
import com.facebook.react.bridge.CatalystInstance;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.modules.junit4.rule.PowerMockRule;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.fest.assertions.api.Assertions.offset;
|
||||
|
||||
/**
|
||||
* Verify {@link View} view property being applied properly by {@link SimpleViewManager}
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
|
||||
public class SimpleViewPropertyTest {
|
||||
|
||||
@Rule
|
||||
public PowerMockRule rule = new PowerMockRule();
|
||||
|
||||
private static class ConcreteViewManager extends SimpleViewManager<View> {
|
||||
|
||||
@ReactProp(name = "foo")
|
||||
public void setFoo(View view, boolean foo) {
|
||||
}
|
||||
|
||||
@ReactProp(name = "bar")
|
||||
public void setBar(View view, ReadableMap bar) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View createViewInstance(ThemedReactContext reactContext) {
|
||||
return new View(reactContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "View";
|
||||
}
|
||||
}
|
||||
|
||||
private ReactApplicationContext mContext;
|
||||
private CatalystInstance mCatalystInstanceMock;
|
||||
private ThemedReactContext mThemedContext;
|
||||
private ConcreteViewManager mManager;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mContext = new ReactApplicationContext(RuntimeEnvironment.application);
|
||||
mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance();
|
||||
mContext.initializeWithInstance(mCatalystInstanceMock);
|
||||
mThemedContext = new ThemedReactContext(mContext, mContext);
|
||||
mManager = new ConcreteViewManager();
|
||||
}
|
||||
|
||||
public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
|
||||
return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpacity() {
|
||||
View view = mManager.createView(mThemedContext, new JSResponderHandler());
|
||||
|
||||
mManager.updateProperties(view, buildStyles());
|
||||
assertThat(view.getAlpha()).isEqualTo(1.0f);
|
||||
|
||||
mManager.updateProperties(view, buildStyles("opacity", 0.31));
|
||||
assertThat(view.getAlpha()).isEqualTo(0.31f, offset(1e-5f));
|
||||
|
||||
mManager.updateProperties(view, buildStyles("opacity", null));
|
||||
assertThat(view.getAlpha()).isEqualTo(1.0f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNativeProps() {
|
||||
Map<String, String> nativeProps = mManager.getNativeProps();
|
||||
assertThat(nativeProps.get("foo")).isEqualTo("boolean");
|
||||
assertThat(nativeProps.get("bar")).isEqualTo("Map");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
|
||||
import org.fest.assertions.data.MapEntry;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.modules.junit4.rule.PowerMockRule;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
|
||||
public class UIManagerModuleConstantsTest {
|
||||
|
||||
@Rule
|
||||
public PowerMockRule rule = new PowerMockRule();
|
||||
|
||||
private static final String CUSTOM_BUBBLING_EVENT_TYPES = "customBubblingEventTypes";
|
||||
private static final String CUSTOM_DIRECT_EVENT_TYPES = "customDirectEventTypes";
|
||||
|
||||
private static final Map TWIRL_BUBBLING_EVENT_MAP = MapBuilder.of(
|
||||
"phasedRegistrationNames",
|
||||
MapBuilder.of(
|
||||
"bubbled",
|
||||
"onTwirl",
|
||||
"captured",
|
||||
"onTwirlCaptured"));
|
||||
private static final Map TWIRL_DIRECT_EVENT_MAP = MapBuilder.of("registrationName", "onTwirl");
|
||||
|
||||
private ReactApplicationContext mReactContext;
|
||||
private UIImplementation mUIImplementation;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
|
||||
mUIImplementation = mock(UIImplementation.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoCustomConstants() {
|
||||
List<ViewManager> viewManagers = Arrays.asList(mock(ViewManager.class));
|
||||
UIManagerModule uiManagerModule = new UIManagerModule(
|
||||
mReactContext,
|
||||
viewManagers,
|
||||
mUIImplementation);
|
||||
Map<String, Object> constants = uiManagerModule.getConstants();
|
||||
assertThat(constants)
|
||||
.containsKey(CUSTOM_BUBBLING_EVENT_TYPES)
|
||||
.containsKey(CUSTOM_DIRECT_EVENT_TYPES)
|
||||
.containsKey("Dimensions");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomBubblingEvents() {
|
||||
ViewManager mockViewManager = mock(ViewManager.class);
|
||||
List<ViewManager> viewManagers = Arrays.asList(mockViewManager);
|
||||
when(mockViewManager.getExportedCustomBubblingEventTypeConstants())
|
||||
.thenReturn(MapBuilder.of("onTwirl", TWIRL_BUBBLING_EVENT_MAP));
|
||||
UIManagerModule uiManagerModule = new UIManagerModule(
|
||||
mReactContext,
|
||||
viewManagers,
|
||||
mUIImplementation);
|
||||
Map<String, Object> constants = uiManagerModule.getConstants();
|
||||
assertThat((Map) constants.get(CUSTOM_BUBBLING_EVENT_TYPES))
|
||||
.contains(MapEntry.entry("onTwirl", TWIRL_BUBBLING_EVENT_MAP))
|
||||
.containsKey("topChange");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomDirectEvents() {
|
||||
ViewManager mockViewManager = mock(ViewManager.class);
|
||||
List<ViewManager> viewManagers = Arrays.asList(mockViewManager);
|
||||
when(mockViewManager.getExportedCustomDirectEventTypeConstants())
|
||||
.thenReturn(MapBuilder.of("onTwirl", TWIRL_DIRECT_EVENT_MAP));
|
||||
UIManagerModule uiManagerModule = new UIManagerModule(
|
||||
mReactContext,
|
||||
viewManagers,
|
||||
mUIImplementation);
|
||||
Map<String, Object> constants = uiManagerModule.getConstants();
|
||||
assertThat((Map) constants.get(CUSTOM_DIRECT_EVENT_TYPES))
|
||||
.contains(MapEntry.entry("onTwirl", TWIRL_DIRECT_EVENT_MAP))
|
||||
.containsKey("topLoadingStart");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomViewConstants() {
|
||||
ViewManager mockViewManager = mock(ViewManager.class);
|
||||
List<ViewManager> viewManagers = Arrays.asList(mockViewManager);
|
||||
when(mockViewManager.getName()).thenReturn("RedPandaPhotoOfTheDayView");
|
||||
when(mockViewManager.getExportedViewConstants())
|
||||
.thenReturn(MapBuilder.of("PhotoSizeType", MapBuilder.of("Small", 1, "Large", 2)));
|
||||
UIManagerModule uiManagerModule = new UIManagerModule(
|
||||
mReactContext,
|
||||
viewManagers,
|
||||
mUIImplementation);
|
||||
Map<String, Object> constants = uiManagerModule.getConstants();
|
||||
assertThat(constants).containsKey("RedPandaPhotoOfTheDayView");
|
||||
assertThat((Map) constants.get("RedPandaPhotoOfTheDayView")).containsKey("Constants");
|
||||
assertThat((Map) valueAtPath(constants, "RedPandaPhotoOfTheDayView", "Constants"))
|
||||
.containsKey("PhotoSizeType");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNativeProps() {
|
||||
ViewManager mockViewManager = mock(ViewManager.class);
|
||||
List<ViewManager> viewManagers = Arrays.asList(mockViewManager);
|
||||
when(mockViewManager.getName()).thenReturn("SomeView");
|
||||
when(mockViewManager.getNativeProps())
|
||||
.thenReturn(MapBuilder.of("fooProp", "number"));
|
||||
UIManagerModule uiManagerModule = new UIManagerModule(
|
||||
mReactContext,
|
||||
viewManagers,
|
||||
mUIImplementation);
|
||||
Map<String, Object> constants = uiManagerModule.getConstants();
|
||||
assertThat((String) valueAtPath(constants, "SomeView", "NativeProps", "fooProp"))
|
||||
.isEqualTo("number");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeConstants() {
|
||||
ViewManager managerX = mock(ViewManager.class);
|
||||
when(managerX.getExportedCustomDirectEventTypeConstants()).thenReturn(MapBuilder.of(
|
||||
"onTwirl",
|
||||
MapBuilder.of(
|
||||
"registrationName",
|
||||
"onTwirl",
|
||||
"keyToOverride",
|
||||
"valueX",
|
||||
"mapToMerge",
|
||||
MapBuilder.of("keyToOverride", "innerValueX", "anotherKey", "valueX"))));
|
||||
|
||||
ViewManager managerY = mock(ViewManager.class);
|
||||
when(managerY.getExportedCustomDirectEventTypeConstants()).thenReturn(MapBuilder.of(
|
||||
"onTwirl",
|
||||
MapBuilder.of(
|
||||
"extraKey",
|
||||
"extraValue",
|
||||
"keyToOverride",
|
||||
"valueY",
|
||||
"mapToMerge",
|
||||
MapBuilder.of("keyToOverride", "innerValueY", "extraKey", "valueY"))));
|
||||
|
||||
List<ViewManager> viewManagers = Arrays.asList(managerX, managerY);
|
||||
UIManagerModule uiManagerModule = new UIManagerModule(
|
||||
mReactContext,
|
||||
viewManagers,
|
||||
mUIImplementation);
|
||||
Map<String, Object> constants = uiManagerModule.getConstants();
|
||||
assertThat((Map) constants.get(CUSTOM_DIRECT_EVENT_TYPES)).containsKey("onTwirl");
|
||||
|
||||
Map twirlMap = (Map) valueAtPath(constants, CUSTOM_DIRECT_EVENT_TYPES, "onTwirl");
|
||||
assertThat(twirlMap)
|
||||
.contains(MapEntry.entry("registrationName", "onTwirl"))
|
||||
.contains(MapEntry.entry("keyToOverride", "valueY"))
|
||||
.contains(MapEntry.entry("extraKey", "extraValue"))
|
||||
.containsKey("mapToMerge");
|
||||
|
||||
Map mapToMerge = (Map) valueAtPath(twirlMap, "mapToMerge");
|
||||
assertThat(mapToMerge)
|
||||
.contains(MapEntry.entry("keyToOverride", "innerValueY"))
|
||||
.contains(MapEntry.entry("anotherKey", "valueX"))
|
||||
.contains(MapEntry.entry("extraKey", "valueY"));
|
||||
}
|
||||
|
||||
private static Object valueAtPath(Map nestedMap, String... keyPath) {
|
||||
assertThat(keyPath).isNotEmpty();
|
||||
Object value = nestedMap;
|
||||
for (String key : keyPath) {
|
||||
assertThat(value).isInstanceOf(Map.class);
|
||||
nestedMap = (Map) value;
|
||||
assertThat(nestedMap).containsKey(key);
|
||||
value = nestedMap.get(key);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,827 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.view.Choreographer;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.react.ReactRootView;
|
||||
import com.facebook.react.animation.Animation;
|
||||
import com.facebook.react.animation.AnimationPropertyUpdater;
|
||||
import com.facebook.react.bridge.Callback;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.CatalystInstance;
|
||||
import com.facebook.react.bridge.SimpleArray;
|
||||
import com.facebook.react.bridge.SimpleMap;
|
||||
import com.facebook.react.views.text.ReactRawTextManager;
|
||||
import com.facebook.react.views.text.ReactTextShadowNode;
|
||||
import com.facebook.react.views.text.ReactTextViewManager;
|
||||
import com.facebook.react.views.view.ReactViewGroup;
|
||||
import com.facebook.react.views.view.ReactViewManager;
|
||||
import com.facebook.react.bridge.ReactTestHelper;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.modules.junit4.rule.PowerMockRule;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Tests for {@link UIManagerModule}.
|
||||
*/
|
||||
@PrepareForTest({Arguments.class, ReactChoreographer.class})
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
|
||||
public class UIManagerModuleTest {
|
||||
|
||||
@Rule
|
||||
public PowerMockRule rule = new PowerMockRule();
|
||||
|
||||
private ReactApplicationContext mReactContext;
|
||||
private CatalystInstance mCatalystInstanceMock;
|
||||
private ArrayList<Choreographer.FrameCallback> mPendingChoreographerCallbacks;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
PowerMockito.mockStatic(Arguments.class, ReactChoreographer.class);
|
||||
|
||||
ReactChoreographer choreographerMock = mock(ReactChoreographer.class);
|
||||
PowerMockito.when(Arguments.createArray()).thenAnswer(new Answer<Object>() {
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
return new SimpleArray();
|
||||
}
|
||||
});
|
||||
PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer<Object>() {
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
return new SimpleMap();
|
||||
}
|
||||
});
|
||||
PowerMockito.when(ReactChoreographer.getInstance()).thenReturn(choreographerMock);
|
||||
|
||||
mPendingChoreographerCallbacks = new ArrayList<>();
|
||||
doAnswer(new Answer() {
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
mPendingChoreographerCallbacks
|
||||
.add((Choreographer.FrameCallback) invocation.getArguments()[1]);
|
||||
return null;
|
||||
}
|
||||
}).when(choreographerMock).postFrameCallback(
|
||||
any(ReactChoreographer.CallbackType.class),
|
||||
any(Choreographer.FrameCallback.class));
|
||||
|
||||
mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance();
|
||||
mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
|
||||
mReactContext.initializeWithInstance(mCatalystInstanceMock);
|
||||
|
||||
UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class);
|
||||
when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class))
|
||||
.thenReturn(uiManagerModuleMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSimpleHierarchy() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
|
||||
ViewGroup rootView = createSimpleTextHierarchy(uiManager, "Some text");
|
||||
|
||||
assertThat(rootView.getChildCount()).isEqualTo(1);
|
||||
|
||||
View firstChild = rootView.getChildAt(0);
|
||||
assertThat(firstChild).isInstanceOf(TextView.class);
|
||||
assertThat(((TextView) firstChild).getText().toString()).isEqualTo("Some text");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateSimpleHierarchy() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
|
||||
ViewGroup rootView = createSimpleTextHierarchy(uiManager, "Some text");
|
||||
TextView textView = (TextView) rootView.getChildAt(0);
|
||||
|
||||
int rawTextTag = 3;
|
||||
uiManager.updateView(
|
||||
rawTextTag,
|
||||
ReactRawTextManager.REACT_CLASS,
|
||||
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "New text"));
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
assertThat(textView.getText().toString()).isEqualTo("New text");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHierarchyWithView() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
|
||||
ReactRootView rootView =
|
||||
new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
|
||||
int rootTag = uiManager.addMeasuredRootView(rootView);
|
||||
int viewTag = rootTag + 1;
|
||||
int subViewTag = viewTag + 1;
|
||||
|
||||
uiManager.createView(
|
||||
viewTag,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
uiManager.createView(
|
||||
subViewTag,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
|
||||
uiManager.manageChildren(
|
||||
viewTag,
|
||||
null,
|
||||
null,
|
||||
SimpleArray.of(subViewTag),
|
||||
SimpleArray.of(0),
|
||||
null);
|
||||
|
||||
uiManager.manageChildren(
|
||||
rootTag,
|
||||
null,
|
||||
null,
|
||||
SimpleArray.of(viewTag),
|
||||
SimpleArray.of(0),
|
||||
null);
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
assertThat(rootView.getChildCount()).isEqualTo(1);
|
||||
|
||||
ViewGroup child = (ViewGroup) rootView.getChildAt(0);
|
||||
assertThat(child.getChildCount()).isEqualTo(1);
|
||||
|
||||
ViewGroup grandchild = (ViewGroup) child.getChildAt(0);
|
||||
assertThat(grandchild).isInstanceOf(ViewGroup.class);
|
||||
assertThat(grandchild.getChildCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveViews() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
|
||||
|
||||
View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(1);
|
||||
View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2);
|
||||
View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(0);
|
||||
View expectedViewAt3 = hierarchy.nativeRootView.getChildAt(3);
|
||||
|
||||
uiManager.manageChildren(
|
||||
hierarchy.rootView,
|
||||
SimpleArray.of(1, 0, 2),
|
||||
SimpleArray.of(0, 2, 1),
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
assertChildrenAreExactly(
|
||||
hierarchy.nativeRootView,
|
||||
expectedViewAt0,
|
||||
expectedViewAt1,
|
||||
expectedViewAt2,
|
||||
expectedViewAt3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteViews() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
|
||||
|
||||
View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(1);
|
||||
View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2);
|
||||
|
||||
uiManager.manageChildren(
|
||||
hierarchy.rootView,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
SimpleArray.of(0, 3));
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
assertChildrenAreExactly(
|
||||
hierarchy.nativeRootView,
|
||||
expectedViewAt0,
|
||||
expectedViewAt1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveAndDeleteViews() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
|
||||
|
||||
View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0);
|
||||
View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(3);
|
||||
View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(2);
|
||||
|
||||
uiManager.manageChildren(
|
||||
hierarchy.rootView,
|
||||
SimpleArray.of(3),
|
||||
SimpleArray.of(1),
|
||||
null,
|
||||
null,
|
||||
SimpleArray.of(1));
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
assertChildrenAreExactly(
|
||||
hierarchy.nativeRootView,
|
||||
expectedViewAt0,
|
||||
expectedViewAt1,
|
||||
expectedViewAt2);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalViewOperationException.class)
|
||||
public void testMoveAndDeleteRemoveViewsDuplicateRemove() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
|
||||
|
||||
uiManager.manageChildren(
|
||||
hierarchy.rootView,
|
||||
SimpleArray.of(3),
|
||||
SimpleArray.of(1),
|
||||
null,
|
||||
null,
|
||||
SimpleArray.of(3));
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalViewOperationException.class)
|
||||
public void testDuplicateRemove() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
|
||||
|
||||
uiManager.manageChildren(
|
||||
hierarchy.rootView,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
SimpleArray.of(3, 3));
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveAndAddViews() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
|
||||
|
||||
int textViewTag = 1000;
|
||||
uiManager.createView(
|
||||
textViewTag,
|
||||
ReactTextViewManager.REACT_CLASS,
|
||||
hierarchy.rootView,
|
||||
SimpleMap.of("collapsable", false));
|
||||
|
||||
View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0);
|
||||
View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(3);
|
||||
View expectedViewAt3 = hierarchy.nativeRootView.getChildAt(1);
|
||||
View expectedViewAt4 = hierarchy.nativeRootView.getChildAt(2);
|
||||
|
||||
uiManager.manageChildren(
|
||||
hierarchy.rootView,
|
||||
SimpleArray.of(1, 2, 3),
|
||||
SimpleArray.of(3, 4, 1),
|
||||
SimpleArray.of(textViewTag),
|
||||
SimpleArray.of(2),
|
||||
null);
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(5);
|
||||
assertThat(hierarchy.nativeRootView.getChildAt(0)).isEqualTo(expectedViewAt0);
|
||||
assertThat(hierarchy.nativeRootView.getChildAt(1)).isEqualTo(expectedViewAt1);
|
||||
assertThat(hierarchy.nativeRootView.getChildAt(3)).isEqualTo(expectedViewAt3);
|
||||
assertThat(hierarchy.nativeRootView.getChildAt(4)).isEqualTo(expectedViewAt4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveViewsWithChildren() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
|
||||
|
||||
View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0);
|
||||
View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2);
|
||||
View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(1);
|
||||
View expectedViewAt3 = hierarchy.nativeRootView.getChildAt(3);
|
||||
|
||||
uiManager.manageChildren(
|
||||
hierarchy.rootView,
|
||||
SimpleArray.of(1, 2),
|
||||
SimpleArray.of(2, 1),
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
assertChildrenAreExactly(
|
||||
hierarchy.nativeRootView,
|
||||
expectedViewAt0,
|
||||
expectedViewAt1,
|
||||
expectedViewAt2,
|
||||
expectedViewAt3);
|
||||
assertThat(((ViewGroup) hierarchy.nativeRootView.getChildAt(2)).getChildCount()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteViewsWithChildren() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
|
||||
|
||||
View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0);
|
||||
View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2);
|
||||
View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(3);
|
||||
|
||||
uiManager.manageChildren(
|
||||
hierarchy.rootView,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
SimpleArray.of(1));
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
assertChildrenAreExactly(
|
||||
hierarchy.nativeRootView,
|
||||
expectedViewAt0,
|
||||
expectedViewAt1,
|
||||
expectedViewAt2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLayoutAppliedToNodes() throws Exception {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
|
||||
|
||||
int newViewTag = 10000;
|
||||
uiManager.createView(
|
||||
newViewTag,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
hierarchy.rootView,
|
||||
SimpleMap
|
||||
.of("left", 10.0, "top", 20.0, "width", 30.0, "height", 40.0, "collapsable", false));
|
||||
|
||||
uiManager.manageChildren(
|
||||
hierarchy.rootView,
|
||||
null,
|
||||
null,
|
||||
SimpleArray.of(newViewTag),
|
||||
SimpleArray.of(4),
|
||||
null);
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
View newView = hierarchy.nativeRootView.getChildAt(4);
|
||||
assertThat(newView.getLeft()).isEqualTo(10);
|
||||
assertThat(newView.getTop()).isEqualTo(20);
|
||||
|
||||
assertThat(newView.getWidth()).isEqualTo(30);
|
||||
assertThat(newView.getHeight()).isEqualTo(40);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is to make sure we execute enqueued operations in the order given by JS.
|
||||
*/
|
||||
@Test
|
||||
public void testAddUpdateRemoveInSingleBatch() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
|
||||
|
||||
int newViewTag = 10000;
|
||||
uiManager.createView(
|
||||
newViewTag,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
hierarchy.rootView,
|
||||
SimpleMap.of("collapsable", false));
|
||||
|
||||
uiManager.manageChildren(
|
||||
hierarchy.rootView,
|
||||
null,
|
||||
null,
|
||||
SimpleArray.of(newViewTag),
|
||||
SimpleArray.of(4),
|
||||
null);
|
||||
|
||||
uiManager.updateView(
|
||||
newViewTag,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
SimpleMap.of("backgroundColor", Color.RED));
|
||||
|
||||
uiManager.manageChildren(
|
||||
hierarchy.rootView,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
SimpleArray.of(4));
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTagsAssignment() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
|
||||
|
||||
View view0 = hierarchy.nativeRootView.getChildAt(0);
|
||||
assertThat(view0.getId()).isEqualTo(hierarchy.view0);
|
||||
|
||||
View viewWithChildren1 = hierarchy.nativeRootView.getChildAt(1);
|
||||
assertThat(viewWithChildren1.getId()).isEqualTo(hierarchy.viewWithChildren1);
|
||||
|
||||
View childView0 = ((ViewGroup) viewWithChildren1).getChildAt(0);
|
||||
assertThat(childView0.getId()).isEqualTo(hierarchy.childView0);
|
||||
|
||||
View childView1 = ((ViewGroup) viewWithChildren1).getChildAt(1);
|
||||
assertThat(childView1.getId()).isEqualTo(hierarchy.childView1);
|
||||
|
||||
View view2 = hierarchy.nativeRootView.getChildAt(2);
|
||||
assertThat(view2.getId()).isEqualTo(hierarchy.view2);
|
||||
|
||||
View view3 = hierarchy.nativeRootView.getChildAt(3);
|
||||
assertThat(view3.getId()).isEqualTo(hierarchy.view3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLayoutPropertyUpdatingOnlyOnLayoutChange() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
|
||||
|
||||
// Update layout to some values, this way we can verify it hasn't been updated, because the
|
||||
// update process would normally reset it back to some non-negative value
|
||||
View view0 = hierarchy.nativeRootView.getChildAt(0);
|
||||
view0.layout(1, 2, 3, 4);
|
||||
|
||||
// verify that X get updated when we update layout properties
|
||||
uiManager.updateView(
|
||||
hierarchy.view0,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
SimpleMap.of("left", 10.0, "top", 20.0, "width", 30.0, "height", 40.0));
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
assertThat(view0.getLeft()).isGreaterThan(2);
|
||||
|
||||
// verify that the layout doesn't get updated when we update style property not affecting the
|
||||
// position (e.g., background-color)
|
||||
view0.layout(1, 2, 3, 4);
|
||||
uiManager.updateView(
|
||||
hierarchy.view0,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
SimpleMap.of("backgroundColor", Color.RED));
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
assertThat(view0.getLeft()).isEqualTo(1);
|
||||
}
|
||||
|
||||
private static class AnimationStub extends Animation {
|
||||
|
||||
public AnimationStub(int animationID, AnimationPropertyUpdater propertyUpdater) {
|
||||
super(animationID, propertyUpdater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAndRemoveAnimation() {
|
||||
UIManagerModule uiManagerModule = getUIManagerModule();
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManagerModule);
|
||||
|
||||
AnimationPropertyUpdater mockPropertyUpdater = mock(AnimationPropertyUpdater.class);
|
||||
Animation mockAnimation = spy(new AnimationStub(1000, mockPropertyUpdater));
|
||||
Callback callbackMock = mock(Callback.class);
|
||||
|
||||
int rootTag = hierarchy.rootView;
|
||||
uiManagerModule.createView(
|
||||
hierarchy.rootView,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
|
||||
uiManagerModule.registerAnimation(mockAnimation);
|
||||
uiManagerModule.addAnimation(hierarchy.rootView, 1000, callbackMock);
|
||||
uiManagerModule.removeAnimation(hierarchy.rootView, 1000);
|
||||
|
||||
uiManagerModule.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
verify(callbackMock, times(1)).invoke(false);
|
||||
verify(mockAnimation).run();
|
||||
verify(mockAnimation).cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure replaceExistingNonRootView by replacing a view with a new view that has a background
|
||||
* color set.
|
||||
*/
|
||||
@Test
|
||||
public void testReplaceExistingNonRootView() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
|
||||
|
||||
int newViewTag = 1234;
|
||||
uiManager.createView(
|
||||
newViewTag,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
hierarchy.rootView,
|
||||
SimpleMap.of("backgroundColor", Color.RED));
|
||||
|
||||
uiManager.replaceExistingNonRootView(hierarchy.view2, newViewTag);
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(4);
|
||||
assertThat(hierarchy.nativeRootView.getChildAt(2)).isInstanceOf(ReactViewGroup.class);
|
||||
ReactViewGroup view = (ReactViewGroup) hierarchy.nativeRootView.getChildAt(2);
|
||||
assertThat(view.getBackgroundColor()).isEqualTo(Color.RED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies removeSubviewsFromContainerWithID works by adding subviews, removing them, and
|
||||
* checking that the final number of children is correct.
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveSubviewsFromContainerWithID() {
|
||||
UIManagerModule uiManager = getUIManagerModule();
|
||||
ReactRootView rootView =
|
||||
new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
|
||||
int rootTag = uiManager.addMeasuredRootView(rootView);
|
||||
|
||||
final int containerTag = rootTag + 1;
|
||||
final int containerSiblingTag = containerTag + 1;
|
||||
|
||||
uiManager.createView(
|
||||
containerTag,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
uiManager.createView(
|
||||
containerSiblingTag,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
addChild(uiManager, rootTag, containerTag, 0);
|
||||
addChild(uiManager, rootTag, containerSiblingTag, 1);
|
||||
|
||||
uiManager.createView(
|
||||
containerTag + 2,
|
||||
ReactTextViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
uiManager.createView(
|
||||
containerTag + 3,
|
||||
ReactTextViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
addChild(uiManager, containerTag, containerTag + 2, 0);
|
||||
addChild(uiManager, containerTag, containerTag + 3, 1);
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
assertThat(rootView.getChildCount()).isEqualTo(2);
|
||||
assertThat(((ViewGroup)rootView.getChildAt(0)).getChildCount()).isEqualTo(2);
|
||||
|
||||
uiManager.removeSubviewsFromContainerWithID(containerTag);
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
assertThat(rootView.getChildCount()).isEqualTo(2);
|
||||
assertThat(((ViewGroup)rootView.getChildAt(0)).getChildCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assuming no other views have been created, the root view will have tag 1, Text tag 2, and
|
||||
* RawText tag 3.
|
||||
*/
|
||||
private ViewGroup createSimpleTextHierarchy(UIManagerModule uiManager, String text) {
|
||||
ReactRootView rootView =
|
||||
new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
|
||||
int rootTag = uiManager.addMeasuredRootView(rootView);
|
||||
int textTag = rootTag + 1;
|
||||
int rawTextTag = textTag + 1;
|
||||
|
||||
uiManager.createView(
|
||||
textTag,
|
||||
ReactTextViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
uiManager.createView(
|
||||
rawTextTag,
|
||||
ReactRawTextManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of(ReactTextShadowNode.PROP_TEXT, text, "collapsable", false));
|
||||
|
||||
uiManager.manageChildren(
|
||||
textTag,
|
||||
null,
|
||||
null,
|
||||
SimpleArray.of(rawTextTag),
|
||||
SimpleArray.of(0),
|
||||
null);
|
||||
|
||||
uiManager.manageChildren(
|
||||
rootTag,
|
||||
null,
|
||||
null,
|
||||
SimpleArray.of(textTag),
|
||||
SimpleArray.of(0),
|
||||
null);
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
private TestMoveDeleteHierarchy createMoveDeleteHierarchy(UIManagerModule uiManager) {
|
||||
ReactRootView rootView = new ReactRootView(mReactContext);
|
||||
int rootTag = uiManager.addMeasuredRootView(rootView);
|
||||
|
||||
TestMoveDeleteHierarchy hierarchy = new TestMoveDeleteHierarchy(rootView, rootTag);
|
||||
|
||||
uiManager.createView(
|
||||
hierarchy.view0,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
uiManager.createView(
|
||||
hierarchy.viewWithChildren1,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
uiManager.createView(
|
||||
hierarchy.view2,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
uiManager.createView(
|
||||
hierarchy.view3,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
uiManager.createView(
|
||||
hierarchy.childView0,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
uiManager.createView(
|
||||
hierarchy.childView1,
|
||||
ReactViewManager.REACT_CLASS,
|
||||
rootTag,
|
||||
SimpleMap.of("collapsable", false));
|
||||
|
||||
addChild(uiManager, rootTag, hierarchy.view0, 0);
|
||||
addChild(uiManager, rootTag, hierarchy.viewWithChildren1, 1);
|
||||
addChild(uiManager, rootTag, hierarchy.view2, 2);
|
||||
addChild(uiManager, rootTag, hierarchy.view3, 3);
|
||||
|
||||
addChild(uiManager, hierarchy.viewWithChildren1, hierarchy.childView0, 0);
|
||||
addChild(uiManager, hierarchy.viewWithChildren1, hierarchy.childView1, 1);
|
||||
|
||||
uiManager.onBatchComplete();
|
||||
executePendingChoreographerCallbacks();
|
||||
|
||||
return hierarchy;
|
||||
}
|
||||
|
||||
private void addChild(UIManagerModule uiManager, int parentTag, int childTag, int index) {
|
||||
uiManager.manageChildren(
|
||||
parentTag,
|
||||
null,
|
||||
null,
|
||||
SimpleArray.of(childTag),
|
||||
SimpleArray.of(index),
|
||||
null);
|
||||
}
|
||||
|
||||
private void assertChildrenAreExactly(ViewGroup parent, View... views) {
|
||||
assertThat(parent.getChildCount()).isEqualTo(views.length);
|
||||
for (int i = 0; i < views.length; i++) {
|
||||
assertThat(parent.getChildAt(i))
|
||||
.describedAs("View at " + i)
|
||||
.isEqualTo(views[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holder for the tags that represent that represent views in the following hierarchy:
|
||||
* - View rootView
|
||||
* - View view0
|
||||
* - View viewWithChildren1
|
||||
* - View childView0
|
||||
* - View childView1
|
||||
* - View view2
|
||||
* - View view3
|
||||
*
|
||||
* This hierarchy is used to test move/delete functionality in manageChildren.
|
||||
*/
|
||||
private static class TestMoveDeleteHierarchy {
|
||||
|
||||
public ReactRootView nativeRootView;
|
||||
public int rootView;
|
||||
public int view0;
|
||||
public int viewWithChildren1;
|
||||
public int view2;
|
||||
public int view3;
|
||||
public int childView0;
|
||||
public int childView1;
|
||||
|
||||
public TestMoveDeleteHierarchy(ReactRootView nativeRootView, int rootViewTag) {
|
||||
this.nativeRootView = nativeRootView;
|
||||
rootView = rootViewTag;
|
||||
view0 = rootView + 1;
|
||||
viewWithChildren1 = rootView + 2;
|
||||
view2 = rootView + 3;
|
||||
view3 = rootView + 4;
|
||||
childView0 = rootView + 5;
|
||||
childView1 = rootView + 6;
|
||||
}
|
||||
}
|
||||
|
||||
private void executePendingChoreographerCallbacks() {
|
||||
ArrayList<Choreographer.FrameCallback> callbacks =
|
||||
new ArrayList<>(mPendingChoreographerCallbacks);
|
||||
mPendingChoreographerCallbacks.clear();
|
||||
for (Choreographer.FrameCallback frameCallback : callbacks) {
|
||||
frameCallback.doFrame(0);
|
||||
}
|
||||
}
|
||||
|
||||
private UIManagerModule getUIManagerModule() {
|
||||
List<ViewManager> viewManagers = Arrays.<ViewManager>asList(
|
||||
new ReactViewManager(),
|
||||
new ReactTextViewManager(),
|
||||
new ReactRawTextManager());
|
||||
UIManagerModule uiManagerModule = new UIManagerModule(
|
||||
mReactContext,
|
||||
viewManagers,
|
||||
new UIImplementation(mReactContext, viewManagers));
|
||||
uiManagerModule.onHostResume();
|
||||
return uiManagerModule;
|
||||
}
|
||||
}
|
12
circle.yml
12
circle.yml
|
@ -17,17 +17,17 @@ dependencies:
|
|||
- if [[ ! -e buck ]]; then git clone https://github.com/facebook/buck.git; fi
|
||||
- cd buck && ant
|
||||
- buck/bin/buck --version
|
||||
- buck/bin/buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
|
||||
- buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react
|
||||
- buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
|
||||
- buck/bin/buck fetch ReactAndroid/src/androidTest/java/com/facebook/react/tests
|
||||
- buck/bin/buck fetch ReactAndroid/src/main/...
|
||||
- buck/bin/buck fetch ReactAndroid/src/test/...
|
||||
- buck/bin/buck fetch ReactAndroid/src/androidTest/...
|
||||
# using npm@3 because of problems with shrink-wrapped optional deps installs on linux
|
||||
- npm install -g npm@3.2
|
||||
- source scripts/circle-ci-android-setup.sh && getAndroidSDK
|
||||
- ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
|
||||
cache_directories:
|
||||
- "ReactAndroid/build/downloads"
|
||||
- "buck-out"
|
||||
- "buck"
|
||||
- "buck-out/bin"
|
||||
test:
|
||||
pre:
|
||||
# starting emulator in advance because it takes very long to boot
|
||||
|
@ -39,7 +39,7 @@ test:
|
|||
- source scripts/circle-ci-android-setup.sh && waitForAVD
|
||||
override:
|
||||
# buck tests
|
||||
- buck/bin/buck test ReactAndroid/src/test/java/com/facebook/react/modules
|
||||
- buck/bin/buck test ReactAndroid/src/test/...
|
||||
- buck/bin/buck build ReactAndroid/src/main/java/com/facebook/react
|
||||
- buck/bin/buck build ReactAndroid/src/main/java/com/facebook/react/shell
|
||||
# temp, we can't run instrumentation tests yet
|
||||
|
|
Loading…
Reference in New Issue