package com.beloo.widget.chipslayoutmanager;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.ViewInteraction;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import com.beloo.chipslayoutmanager.sample.R;
import com.beloo.chipslayoutmanager.sample.entity.ChipsEntity;
import com.beloo.chipslayoutmanager.sample.ui.FewChipsFacade;
import com.beloo.chipslayoutmanager.sample.ui.IItemsFacade;
import com.beloo.chipslayoutmanager.sample.ui.LayoutManagerFactory;
import com.beloo.chipslayoutmanager.sample.ui.TestActivity;
import com.beloo.widget.chipslayoutmanager.util.InstrumentalUtil;
import com.beloo.widget.chipslayoutmanager.util.testing.ISpy;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.List;
import java.util.Locale;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static com.beloo.test.util.RecyclerViewEspressoFactory.actionDelegate;
import static com.beloo.test.util.RecyclerViewEspressoFactory.notifyItemRemovedAction;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assume.assumeTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* test for {@link TestActivity}
*/
@RunWith(AndroidJUnit4.class)
public class FewChipsRowTest {
static {
TestActivity.isInitializeOutside = true;
}
@Rule
public ActivityTestRule<TestActivity> activityTestRule = new ActivityTestRule<>(TestActivity.class);
@Mock
ISpy spy;
@Mock
LayoutManagerFactory layoutManagerFactory;
private ChipsLayoutManager layoutManager;
private List<ChipsEntity> items;
private TestActivity activity;
@Before
public void setUp() throws Throwable {
MockitoAnnotations.initMocks(this);
activity = activityTestRule.getActivity();
RecyclerView rvTest = (RecyclerView) activityTestRule.getActivity().findViewById(R.id.rvTest);
//disable all animations
rvTest.setItemAnimator(null);
layoutManager = getLayoutManager();
doReturn(layoutManager).when(layoutManagerFactory).layoutManager(any());
IItemsFacade<ChipsEntity> chipsFacade = spy(new FewChipsFacade());
items = chipsFacade.getItems();
when(chipsFacade.getItems()).thenReturn(items);
TestActivity.setItemsFactory(chipsFacade);
TestActivity.setLmFactory(layoutManagerFactory);
}
protected ChipsLayoutManager getLayoutManager() {
return ChipsLayoutManager.newBuilder(activityTestRule.getActivity())
.setOrientation(ChipsLayoutManager.HORIZONTAL)
.build();
}
/**
* test, that {@link android.support.v7.widget.LinearLayoutManager#onLayoutChildren} isn't called infinitely
*/
@Test
public void onLayoutChildren_afterActivityStarted_onLayoutCallLimited() throws Exception {
//arrange
activity.runOnUiThread(() -> activity.initialize());
layoutManager.setSpy(spy);
//act
//we can't wait for idle, coz in case of error it won't be achieved. So just approximate time here.
Thread.sleep(700);
//assert
verify(spy, atMost(6)).onLayoutChildren(any(RecyclerView.Recycler.class), any(RecyclerView.State.class));
}
@Test
public void wrapContent_HeightIsWrapContent_DeletedLastItemInLastRowCauseHeightToDecrease() throws Exception {
//arrange
activity.runOnUiThread(() -> activity.initialize());
final RecyclerView[] rvTest = new RecyclerView[1];
ViewInteraction recyclerView = onView(withId(R.id.rvTest)).check(matches(isDisplayed()));
ViewAction viewAction = actionDelegate((uiController, view) -> {
rvTest[0] = view;
view.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
view.requestLayout();
});
recyclerView.perform(viewAction);
int startHeight = rvTest[0].getHeight();
//act
recyclerView.perform(
actionDelegate(((uiController, view) -> items.remove(9))),
notifyItemRemovedAction(9));
//assert
int endHeight = rvTest[0].getHeight();
System.out.println(String.format(Locale.getDefault(), "start height = %d, end height = %d", startHeight, endHeight));
assertTrue(endHeight < startHeight);
}
@Test
public void deleteItemInTheFirstLine_ItemHasMaximumHeight_SameStartPadding() throws Exception {
//arrange
//just adapt input items list to required start values
items.remove(1);
activity.runOnUiThread(() -> activity.initialize());
ViewInteraction recyclerView = onView(withId(R.id.rvTest)).check(matches(isDisplayed()));
InstrumentalUtil.waitForIdle();
View second = layoutManager.getChildAt(1);
int startHeight = second.getHeight();
double expectedY = second.getY();
//act
recyclerView.perform(
actionDelegate(((uiController, view) -> items.remove(1))),
notifyItemRemovedAction(1));
InstrumentalUtil.waitForIdle();
second = layoutManager.getChildAt(1);
int endHeight = second.getHeight();
double resultY = second.getY();
//assert
//check test behaviour
assumeTrue(startHeight > endHeight);
assertNotEquals(0, expectedY, 0.01);
assertNotEquals(0, resultY, 0.01);
assertEquals(resultY, expectedY, 0.01);
}
}