1/* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package androidx.recyclerview.widget; 18 19import static org.junit.Assert.assertEquals; 20import static org.junit.Assert.assertFalse; 21import static org.junit.Assert.assertNull; 22import static org.junit.Assert.assertSame; 23import static org.junit.Assert.assertTrue; 24 25import android.content.Context; 26import android.support.test.InstrumentationRegistry; 27import android.support.test.filters.SmallTest; 28import android.support.test.runner.AndroidJUnit4; 29import android.view.View; 30import android.view.ViewGroup; 31 32import org.junit.Before; 33import org.junit.Test; 34import org.junit.runner.RunWith; 35 36import java.util.ArrayList; 37import java.util.List; 38 39@RunWith(AndroidJUnit4.class) 40@SmallTest 41public class ChildHelperTest { 42 LoggingCallback mLoggingCallback; 43 ChildHelper mChildHelper; 44 Context mContext; 45 46 @Before 47 public void setup() throws Exception { 48 mContext = InstrumentationRegistry.getContext(); 49 mLoggingCallback = new LoggingCallback(); 50 mChildHelper = new ChildHelper(mLoggingCallback); 51 } 52 53 private RecyclerView.ViewHolder vh() { 54 View view = new View(mContext); 55 RecyclerViewBasicTest.MockViewHolder mockViewHolder 56 = new RecyclerViewBasicTest.MockViewHolder(view); 57 RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(0 , 0); 58 lp.mViewHolder = mockViewHolder; 59 view.setLayoutParams(lp); 60 return mockViewHolder; 61 } 62 63 @Test 64 public void addChild() { 65 RecyclerView.ViewHolder vh = vh(); 66 mChildHelper.addView(vh.itemView, false); 67 assertEquals(1, mLoggingCallback.getChildCount()); 68 assertFalse(mChildHelper.isHidden(vh.itemView)); 69 assertEquals(0, mLoggingCallback.mOnEnteredHiddenState.size()); 70 } 71 72 @Test 73 public void addChildHidden() { 74 RecyclerView.ViewHolder vh = vh(); 75 mChildHelper.addView(vh.itemView, true); 76 assertEquals(1, mLoggingCallback.getChildCount()); 77 assertTrue(mChildHelper.isHidden(vh.itemView)); 78 assertTrue(mLoggingCallback.mOnEnteredHiddenState.contains(vh.itemView)); 79 } 80 81 @Test 82 public void addChildAndHide() { 83 RecyclerView.ViewHolder vh = vh(); 84 mChildHelper.addView(vh.itemView, false); 85 mChildHelper.hide(vh.itemView); 86 assertTrue(mChildHelper.isHidden(vh.itemView)); 87 mChildHelper.unhide(vh.itemView); 88 assertFalse(mChildHelper.isHidden(vh.itemView)); 89 } 90 91 @Test 92 public void findHiddenNonRemoved() { 93 RecyclerView.ViewHolder vh = vh(); 94 vh.mPosition = 12; 95 mChildHelper.addView(vh.itemView, true); 96 assertSame(vh.itemView, mChildHelper.findHiddenNonRemovedView(12)); 97 } 98 99 @Test 100 public void findHiddenRemoved() { 101 RecyclerView.ViewHolder vh = vh(); 102 vh.mPosition = 12; 103 vh.addFlags(RecyclerView.ViewHolder.FLAG_REMOVED); 104 mChildHelper.addView(vh.itemView, true); 105 assertNull(mChildHelper.findHiddenNonRemovedView(12)); 106 } 107 108 private static class LoggingCallback implements ChildHelper.Callback { 109 List<View> mViews = new ArrayList<>(); 110 List<View> mDetached = new ArrayList<>(); 111 List<View> mOnEnteredHiddenState = new ArrayList<>(); 112 List<View> mOnExitedHiddenState = new ArrayList<>(); 113 @Override 114 public int getChildCount() { 115 return mViews.size(); 116 } 117 118 @Override 119 public void addView(View child, int index) { 120 mViews.add(index, child); 121 } 122 123 @Override 124 public int indexOfChild(View view) { 125 return mViews.indexOf(view); 126 } 127 128 private boolean validateIndex(int index) { 129 return index < getChildCount() && index >= 0; 130 } 131 132 @Override 133 public void removeViewAt(int index) { 134 if (validateIndex(index)) { 135 mViews.remove(index); 136 } 137 } 138 139 @Override 140 public View getChildAt(int offset) { 141 if (validateIndex(offset)) { 142 return mViews.remove(offset); 143 } 144 return null; 145 } 146 147 @Override 148 public void removeAllViews() { 149 mViews.clear(); 150 } 151 152 @Override 153 public RecyclerView.ViewHolder getChildViewHolder(View view) { 154 return RecyclerView.getChildViewHolderInt(view); 155 } 156 157 @Override 158 public void attachViewToParent(View child, int index, ViewGroup.LayoutParams layoutParams) { 159 assertTrue(mDetached.remove(child)); 160 addView(child, index); 161 } 162 163 @Override 164 public void detachViewFromParent(int offset) { 165 mDetached.add(getChildAt(offset)); 166 } 167 168 @Override 169 public void onEnteredHiddenState(View child) { 170 mOnEnteredHiddenState.add(child); 171 } 172 173 @Override 174 public void onLeftHiddenState(View child) { 175 mOnExitedHiddenState.add(child); 176 } 177 } 178} 179