/**
* Copyright (c) 2017-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.litho;
import android.content.Context;
import com.facebook.litho.testing.TestDrawableComponent;
import com.facebook.litho.testing.testrunner.ComponentsTestRunner;
import com.facebook.litho.testing.util.InlineLayoutSpec;
import com.facebook.yoga.YogaAlign;
import com.facebook.yoga.YogaEdge;
import com.facebook.yoga.YogaPositionType;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
@RunWith(ComponentsTestRunner.class)
public class LayoutStateCalculateTopsAndBottomsTest {
@Test
public void testCalculateTopsAndBottoms() {
final Component component = new InlineLayoutSpec() {
@Override
protected ComponentLayout onCreateLayout(ComponentContext c) {
return Column.create(c)
.child(
Column.create(c)
.child(
TestDrawableComponent.create(c)
.withLayout()
.wrapInView()
.heightPx(50)))
.child(
TestDrawableComponent.create(c)
.withLayout()
.heightPx(20))
.child(
TestDrawableComponent.create(c)
.withLayout()
.positionType(YogaPositionType.ABSOLUTE)
.positionPx(YogaEdge.TOP, 10)
.positionPx(YogaEdge.BOTTOM, 30))
.build();
}
};
LayoutState layoutState = calculateLayoutState(
RuntimeEnvironment.application,
component,
-1,
SizeSpec.makeSizeSpec(100, SizeSpec.EXACTLY),
SizeSpec.makeSizeSpec(100, SizeSpec.AT_MOST));
assertEquals(5, layoutState.getMountableOutputCount());
assertEquals(0, layoutState.getMountableOutputTops().get(0).getBounds().top);
assertEquals(0, layoutState.getMountableOutputTops().get(1).getBounds().top);
assertEquals(0, layoutState.getMountableOutputTops().get(2).getBounds().top);
assertEquals(10, layoutState.getMountableOutputTops().get(3).getBounds().top);
assertEquals(50, layoutState.getMountableOutputTops().get(4).getBounds().top);
assertEquals(40, layoutState.getMountableOutputBottoms().get(0).getBounds().bottom);
assertEquals(50, layoutState.getMountableOutputBottoms().get(1).getBounds().bottom);
assertEquals(50, layoutState.getMountableOutputBottoms().get(2).getBounds().bottom);
assertEquals(70, layoutState.getMountableOutputBottoms().get(3).getBounds().bottom);
assertEquals(70, layoutState.getMountableOutputBottoms().get(4).getBounds().bottom);
assertSame(layoutState.getMountableOutputAt(2), layoutState.getMountableOutputTops().get(2));
assertSame(layoutState.getMountableOutputAt(4), layoutState.getMountableOutputTops().get(3));
assertSame(layoutState.getMountableOutputAt(3), layoutState.getMountableOutputTops().get(4));
assertSame(layoutState.getMountableOutputAt(4), layoutState.getMountableOutputBottoms().get(0));
assertSame(layoutState.getMountableOutputAt(2), layoutState.getMountableOutputBottoms().get(1));
assertSame(layoutState.getMountableOutputAt(1), layoutState.getMountableOutputBottoms().get(2));
assertSame(layoutState.getMountableOutputAt(3), layoutState.getMountableOutputBottoms().get(3));
assertSame(layoutState.getMountableOutputAt(0), layoutState.getMountableOutputBottoms().get(4));
}
@Test
public void testTopsComparatorIsEquivalenceRelation() {
LayoutOutput[] layoutOutputs = new LayoutOutput[4];
layoutOutputs[0] = createLayoutOutput(0, 20, false);
layoutOutputs[1] = createLayoutOutput(0, 20, true);
layoutOutputs[2] = createLayoutOutput(10, 20, false);
layoutOutputs[3] = createLayoutOutput(10, 20, true);
// reflexive
for (LayoutOutput layoutOutput : layoutOutputs) {
assertEquals(0, LayoutState.sTopsComparator.compare(layoutOutput, layoutOutput));
}
// symmetric
for (int i = 0; i < 4; i++) {
for (int j = i + 1; j < 4; j++) {
assertEquals(
LayoutState.sTopsComparator.compare(layoutOutputs[i], layoutOutputs[j]),
-1 * LayoutState.sTopsComparator.compare(layoutOutputs[j], layoutOutputs[i]));
}
}
// transitivity
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
for (int k = 0; k < 4; k++) {
if (i != j && j != k && i != k) {
if (LayoutState.sTopsComparator.compare(layoutOutputs[i], layoutOutputs[j]) ==
LayoutState.sTopsComparator.compare(layoutOutputs[j], layoutOutputs[k])) {
assertEquals(
LayoutState.sTopsComparator.compare(layoutOutputs[i], layoutOutputs[j]),
LayoutState.sTopsComparator.compare(layoutOutputs[j], layoutOutputs[k]));
}
}
}
}
}
}
@Test
public void testBottomsComparatorIsEquivalenceRelation() {
LayoutOutput[] layoutOutputs = new LayoutOutput[4];
layoutOutputs[0] = createLayoutOutput(0, 10, false);
layoutOutputs[1] = createLayoutOutput(0, 10, true);
layoutOutputs[2] = createLayoutOutput(0, 20, false);
layoutOutputs[3] = createLayoutOutput(0, 20, true);
// reflexive
for (LayoutOutput layoutOutput : layoutOutputs) {
assertEquals(0, LayoutState.sBottomsComparator.compare(layoutOutput, layoutOutput));
}
// symmetric
for (int i = 0; i < 4; i++) {
for (int j = i + 1; j < 4; j++) {
assertEquals(
LayoutState.sBottomsComparator.compare(layoutOutputs[i], layoutOutputs[j]),
-1 * LayoutState.sBottomsComparator.compare(layoutOutputs[j], layoutOutputs[i]));
}
}
// transitivity
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
for (int k = 0; k < 4; k++) {
if (i != j && j != k && i != k) {
if (LayoutState.sBottomsComparator.compare(layoutOutputs[i], layoutOutputs[j]) ==
LayoutState.sBottomsComparator.compare(layoutOutputs[j], layoutOutputs[k])) {
assertEquals(
LayoutState.sBottomsComparator.compare(layoutOutputs[i], layoutOutputs[j]),
LayoutState.sBottomsComparator.compare(layoutOutputs[j], layoutOutputs[k]));
}
}
}
}
}
}
private static LayoutState calculateLayoutState(
Context context,
Component<?> component,
int componentTreeId,
int widthSpec,
int heightSpec) {
return LayoutState.calculate(
new ComponentContext(context),
component,
componentTreeId,
widthSpec,
heightSpec,
false,
false,
null,
false);
}
private static LayoutOutput createLayoutOutput(int top, int bottom, boolean isHostSpec) {
LayoutOutput layoutOutput = new LayoutOutput();
layoutOutput.setBounds(0, top, 10, bottom);
if (isHostSpec) {
layoutOutput.setComponent(HostComponent.create());
}
return layoutOutput;
}
}