blob: 559bc6b3d4f2857bf730aad22471abb6da52d7cd [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.v7.widget;
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import android.view.View;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_PRE;
import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_POST;
import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR;
import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_DISAPPEARED;
import android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
import android.support.v7.widget.RecyclerView.ViewHolder;
@SuppressWarnings("ConstantConditions")
@RunWith(JUnit4.class)
public class ViewInfoStoreTest extends TestCase {
ViewInfoStore mStore;
LoggingProcessCallback mCallback;
@Before
public void prepare() {
mStore = new ViewInfoStore();
mCallback = new LoggingProcessCallback();
}
@Test
public void addToPreLayout() {
RecyclerView.ViewHolder vh = new MockViewHolder();
MockInfo info = new MockInfo();
mStore.addToPreLayout(vh, info);
assertSame(info, find(vh, FLAG_PRE));
assertTrue(mStore.isInPreLayout(vh));
mStore.removeViewHolder(vh);
assertFalse(mStore.isInPreLayout(vh));
}
@Test
public void addToPostLayout() {
RecyclerView.ViewHolder vh = new MockViewHolder();
MockInfo info = new MockInfo();
mStore.addToPostLayout(vh, info);
assertSame(info, find(vh, FLAG_POST));
mStore.removeViewHolder(vh);
assertNull(find(vh, FLAG_POST));
}
@Test
public void popFromPreLayout() {
assertEquals(0, sizeOf(FLAG_PRE));
RecyclerView.ViewHolder vh = new MockViewHolder();
MockInfo info = new MockInfo();
mStore.addToPreLayout(vh, info);
assertSame(info, mStore.popFromPreLayout(vh));
assertNull(mStore.popFromPreLayout(vh));
}
@Test
public void addToOldChangeHolders() {
RecyclerView.ViewHolder vh = new MockViewHolder();
mStore.addToOldChangeHolders(1, vh);
assertSame(vh, mStore.getFromOldChangeHolders(1));
mStore.removeViewHolder(vh);
assertNull(mStore.getFromOldChangeHolders(1));
}
@Test
public void appearListTests() {
RecyclerView.ViewHolder vh = new MockViewHolder();
RecyclerView.ItemAnimator.ItemHolderInfo info = new MockInfo();
mStore.addToAppearedInPreLayoutHolders(vh, info);
assertEquals(1, sizeOf(FLAG_APPEAR));
RecyclerView.ViewHolder vh2 = new MockViewHolder();
mStore.addToAppearedInPreLayoutHolders(vh2, info);
assertEquals(2, sizeOf(FLAG_APPEAR));
mStore.removeViewHolder(vh2);
assertEquals(1, sizeOf(FLAG_APPEAR));
}
@Test
public void disappearListTest() {
RecyclerView.ViewHolder vh = new MockViewHolder();
mStore.addToDisappearedInLayout(vh);
assertEquals(1, sizeOf(FLAG_DISAPPEARED));
mStore.addToDisappearedInLayout(vh);
assertEquals(1, sizeOf(FLAG_DISAPPEARED));
RecyclerView.ViewHolder vh2 = new MockViewHolder();
mStore.addToDisappearedInLayout(vh2);
assertEquals(2, sizeOf(FLAG_DISAPPEARED));
mStore.removeViewHolder(vh2);
assertEquals(1, sizeOf(FLAG_DISAPPEARED));
mStore.removeFromDisappearedInLayout(vh);
assertEquals(0, sizeOf(FLAG_DISAPPEARED));
}
@Test
public void processAppear() {
ViewHolder vh = new MockViewHolder();
MockInfo info = new MockInfo();
mStore.addToPostLayout(vh, info);
mStore.process(mCallback);
assertEquals(new Pair<>(null, info), mCallback.appeared.get(vh));
assertTrue(mCallback.disappeared.isEmpty());
assertTrue(mCallback.unused.isEmpty());
assertTrue(mCallback.persistent.isEmpty());
}
@Test
public void processDisappearNormal() {
ViewHolder vh = new MockViewHolder();
MockInfo info = new MockInfo();
mStore.addToPreLayout(vh, info);
mStore.process(mCallback);
assertEquals(new Pair<>(info, null), mCallback.disappeared.get(vh));
assertTrue(mCallback.appeared.isEmpty());
assertTrue(mCallback.unused.isEmpty());
assertTrue(mCallback.persistent.isEmpty());
}
@Test
public void processDisappearMissingLayout() {
ViewHolder vh = new MockViewHolder();
MockInfo info = new MockInfo();
mStore.addToPreLayout(vh, info);
mStore.addToDisappearedInLayout(vh);
mStore.process(mCallback);
assertEquals(new Pair<>(info, null), mCallback.disappeared.get(vh));
assertTrue(mCallback.appeared.isEmpty());
assertTrue(mCallback.unused.isEmpty());
assertTrue(mCallback.persistent.isEmpty());
}
@Test
public void processDisappearMoveOut() {
ViewHolder vh = new MockViewHolder();
MockInfo pre = new MockInfo();
MockInfo post = new MockInfo();
mStore.addToPreLayout(vh, pre);
mStore.addToDisappearedInLayout(vh);
mStore.addToPostLayout(vh, post);
mStore.process(mCallback);
assertEquals(new Pair<>(pre, post), mCallback.disappeared.get(vh));
assertTrue(mCallback.appeared.isEmpty());
assertTrue(mCallback.unused.isEmpty());
assertTrue(mCallback.persistent.isEmpty());
}
@Test
public void processDisappearAppear() {
ViewHolder vh = new MockViewHolder();
MockInfo pre = new MockInfo();
MockInfo post = new MockInfo();
mStore.addToPreLayout(vh, pre);
mStore.addToDisappearedInLayout(vh);
mStore.addToPostLayout(vh, post);
mStore.removeFromDisappearedInLayout(vh);
mStore.process(mCallback);
assertTrue(mCallback.disappeared.isEmpty());
assertTrue(mCallback.appeared.isEmpty());
assertTrue(mCallback.unused.isEmpty());
assertEquals(mCallback.persistent.get(vh), new Pair<>(pre, post));
}
static class MockViewHolder extends RecyclerView.ViewHolder {
public MockViewHolder() {
super(new View(null));
}
}
static class MockInfo extends RecyclerView.ItemAnimator.ItemHolderInfo {
}
private int sizeOf(int flags) {
int cnt = 0;
final int size = mStore.mLayoutHolderMap.size();
for (int i = 0; i < size; i ++) {
ViewInfoStore.InfoRecord record = mStore.mLayoutHolderMap.valueAt(i);
if ((record.flags & flags) != 0) {
cnt ++;
}
}
return cnt;
}
private RecyclerView.ItemAnimator.ItemHolderInfo find(RecyclerView.ViewHolder viewHolder,
int flags) {
final int size = mStore.mLayoutHolderMap.size();
for (int i = 0; i < size; i ++) {
ViewInfoStore.InfoRecord record = mStore.mLayoutHolderMap.valueAt(i);
RecyclerView.ViewHolder holder = mStore.mLayoutHolderMap.keyAt(i);
if ((record.flags & flags) != 0 && holder == viewHolder) {
if (flags == FLAG_PRE || flags == FLAG_APPEAR) {
return record.preInfo;
} else if (flags == FLAG_POST) {
return record.postInfo;
}
throw new UnsupportedOperationException("don't know this flag");
}
}
return null;
}
private static class LoggingProcessCallback implements ViewInfoStore.ProcessCallback {
final Map<ViewHolder, Pair<ItemHolderInfo, ItemHolderInfo>> disappeared = new HashMap<>();
final Map<ViewHolder, Pair<ItemHolderInfo, ItemHolderInfo>> appeared = new HashMap<>();
final Map<ViewHolder, Pair<ItemHolderInfo, ItemHolderInfo>> persistent = new HashMap<>();
final List<ViewHolder> unused = new ArrayList<>();
@Override
public void processDisappeared(ViewHolder viewHolder,
ItemHolderInfo preInfo,
@Nullable ItemHolderInfo postInfo) {
assertNotNull(preInfo);
assertFalse(disappeared.containsKey(viewHolder));
disappeared.put(viewHolder, new Pair<>(preInfo, postInfo));
}
@Override
public void processAppeared(ViewHolder viewHolder,
@Nullable ItemHolderInfo preInfo, @NonNull ItemHolderInfo info) {
assertNotNull(info);
assertFalse(appeared.containsKey(viewHolder));
appeared.put(viewHolder, new Pair<>(preInfo, info));
}
@Override
public void processPersistent(ViewHolder viewHolder,
@NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
assertFalse(persistent.containsKey(viewHolder));
assertNotNull(preInfo);
assertNotNull(postInfo);
persistent.put(viewHolder, new Pair<>(preInfo, postInfo));
}
@Override
public void unused(ViewHolder holder) {
unused.add(holder);
}
}
}