1 /* 2 * Copyright (C) 2015 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 17 package android.support.v7.widget; 18 19 import static org.mockito.Mockito.spy; 20 import static org.mockito.Mockito.times; 21 import static org.mockito.Mockito.verify; 22 import static org.mockito.Mockito.when; 23 24 import android.content.Context; 25 import android.support.annotation.Nullable; 26 import android.support.test.InstrumentationRegistry; 27 import android.support.test.runner.AndroidJUnit4; 28 import android.test.suitebuilder.annotation.MediumTest; 29 import android.util.AttributeSet; 30 import android.view.View; 31 import android.view.ViewGroup; 32 33 import org.junit.After; 34 import org.junit.Before; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 @MediumTest 39 @RunWith(AndroidJUnit4.class) 40 public class WrapContentBasicTest { 41 private Context mContext; 42 private WrapContentLayoutManager mLayoutManager; 43 private RecyclerView mRecyclerView; 44 private WrapAdapter mAdapter; 45 private static int WRAP = View.MeasureSpec.makeMeasureSpec(10, View.MeasureSpec.AT_MOST); 46 private static int EXACT = View.MeasureSpec.makeMeasureSpec(10, View.MeasureSpec.EXACTLY); 47 private static int UNSPECIFIED = View.MeasureSpec 48 .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 49 50 @Before setup()51 public void setup() throws Exception { 52 mContext = InstrumentationRegistry.getContext(); 53 mRecyclerView = new RecyclerView(mContext); 54 mLayoutManager = spy(new WrapContentLayoutManager()); 55 // working around a mockito issue 56 mRecyclerView.setLayoutManager(mLayoutManager); 57 mAdapter = spy(new WrapAdapter()); 58 mRecyclerView.setAdapter(mAdapter); 59 } 60 61 @Test testLayoutInOnMeasureWithoutPredictive()62 public void testLayoutInOnMeasureWithoutPredictive() { 63 mLayoutManager.setAutoMeasureEnabled(true); 64 when(mLayoutManager.supportsPredictiveItemAnimations()).thenReturn(false); 65 mRecyclerView.onMeasure(WRAP, WRAP); 66 mRecyclerView.onMeasure(WRAP, WRAP); 67 mRecyclerView.onLayout(true, 0, 10, 10, 10); 68 verify(mLayoutManager, times(3)) 69 .onLayoutChildren(mRecyclerView.mRecycler, mRecyclerView.mState); 70 } 71 72 @Test dataChangeAfterMeasure()73 public void dataChangeAfterMeasure() { 74 mLayoutManager.setAutoMeasureEnabled(true); 75 mRecyclerView.onMeasure(WRAP, WRAP); 76 mRecyclerView.onMeasure(WRAP, WRAP); 77 mAdapter.notifyItemChanged(1); 78 mRecyclerView.onLayout(true, 0, 10, 10, 10); 79 verify(mLayoutManager, times(3)) 80 .onLayoutChildren(mRecyclerView.mRecycler, mRecyclerView.mState); 81 } 82 83 @Test setDimensionsFromChildren()84 public void setDimensionsFromChildren() { 85 mLayoutManager.setAutoMeasureEnabled(true); 86 View[] children = createMockChildren(3); 87 mLayoutManager.setMeasuredDimensionFromChildren(WRAP, WRAP); 88 verify(mLayoutManager).setMeasuredDimension(children[0].getWidth(), 89 children[0].getHeight()); 90 } 91 92 @Test setDimensionsFromChildrenAnsSpec1()93 public void setDimensionsFromChildrenAnsSpec1() { 94 mLayoutManager.setAutoMeasureEnabled(true); 95 View[] children = createMockChildren(3); 96 int hSpec = View.MeasureSpec.makeMeasureSpec(111, View.MeasureSpec.EXACTLY); 97 mLayoutManager.setMeasuredDimensionFromChildren(WRAP, hSpec); 98 verify(mLayoutManager).setMeasuredDimension(children[0].getWidth(), 111); 99 } 100 101 @Test setDimensionsFromChildrenAnsSpec2()102 public void setDimensionsFromChildrenAnsSpec2() { 103 mLayoutManager.setAutoMeasureEnabled(true); 104 View[] children = createMockChildren(3); 105 int wSpec = View.MeasureSpec.makeMeasureSpec(111, View.MeasureSpec.EXACTLY); 106 mLayoutManager.setMeasuredDimensionFromChildren(wSpec, WRAP); 107 verify(mLayoutManager).setMeasuredDimension(111, children[0].getHeight()); 108 } 109 110 @Test setDimensionsFromChildrenAnsSpec3()111 public void setDimensionsFromChildrenAnsSpec3() { 112 mLayoutManager.setAutoMeasureEnabled(true); 113 View[] children = createMockChildren(3); 114 children[0].layout(0, 0, 100, 100); 115 children[1].layout(-5, 0, 100, 100); 116 children[2].layout(-5, -10, 100, 100); 117 mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED); 118 verify(mLayoutManager).setMeasuredDimension(105, 110); 119 } 120 121 @Test setDimensionsFromChildrenAnsSpec4()122 public void setDimensionsFromChildrenAnsSpec4() { 123 mLayoutManager.setAutoMeasureEnabled(true); 124 View[] children = createMockChildren(3); 125 children[0].layout(0, 0, 100, 100); 126 children[1].layout(-5, 0, 100, 100); 127 children[2].layout(-5, -10, 100, 100); 128 int atMost = View.MeasureSpec.makeMeasureSpec(95, View.MeasureSpec.AT_MOST); 129 mLayoutManager.setMeasuredDimensionFromChildren(atMost, atMost); 130 verify(mLayoutManager).setMeasuredDimension(95, 95); 131 } 132 133 @Test setDimensionsFromChildrenAnsSpec5()134 public void setDimensionsFromChildrenAnsSpec5() { 135 mLayoutManager.setAutoMeasureEnabled(true); 136 View[] children = createMockChildren(3); 137 children[0].layout(0, 0, 100, 100); 138 children[1].layout(-5, 0, 100, 100); 139 children[2].layout(-5, -10, 100, 100); 140 mRecyclerView.setMinimumWidth(250); 141 mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED); 142 verify(mLayoutManager).setMeasuredDimension(250, 110); 143 144 mRecyclerView.setMinimumWidth(5); 145 mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED); 146 verify(mLayoutManager).setMeasuredDimension(105, 110); 147 } 148 149 @Test setDimensionsFromChildrenAnsSpec6()150 public void setDimensionsFromChildrenAnsSpec6() { 151 mLayoutManager.setAutoMeasureEnabled(true); 152 View[] children = createMockChildren(3); 153 children[0].layout(0, 0, 100, 100); 154 children[1].layout(-5, 0, 100, 100); 155 children[2].layout(-5, -10, 100, 100); 156 mRecyclerView.setMinimumHeight(250); 157 mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED); 158 verify(mLayoutManager).setMeasuredDimension(105, 250); 159 160 mRecyclerView.setMinimumHeight(50); 161 mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED); 162 verify(mLayoutManager).setMeasuredDimension(105, 110); 163 } 164 createMockChildren(int count)165 private View[] createMockChildren(int count) { 166 View[] views = new View[count]; 167 for (int i = 0; i < count; i++) { 168 View v = new View(mContext); 169 v.setLayoutParams(new RecyclerView.LayoutParams(1, 1)); 170 views[i] = v; 171 when(mLayoutManager.getChildAt(i)).thenReturn(v); 172 } 173 when(mLayoutManager.getChildCount()).thenReturn(3); 174 return views; 175 } 176 177 public class WrapContentLayoutManager extends RecyclerView.LayoutManager { 178 179 @Override onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state)180 public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 181 182 } 183 184 @Override generateDefaultLayoutParams()185 public RecyclerView.LayoutParams generateDefaultLayoutParams() { 186 return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 187 ViewGroup.LayoutParams.WRAP_CONTENT); 188 } 189 190 // START MOCKITO OVERRIDES 191 // We override package protected methods to make them public. This is necessary to run 192 // mockito on Kitkat 193 @Override setRecyclerView(RecyclerView recyclerView)194 public void setRecyclerView(RecyclerView recyclerView) { 195 super.setRecyclerView(recyclerView); 196 } 197 198 @Override dispatchAttachedToWindow(RecyclerView view)199 public void dispatchAttachedToWindow(RecyclerView view) { 200 super.dispatchAttachedToWindow(view); 201 } 202 203 @Override dispatchDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler)204 public void dispatchDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) { 205 super.dispatchDetachedFromWindow(view, recycler); 206 } 207 208 @Override setExactMeasureSpecsFrom(RecyclerView recyclerView)209 public void setExactMeasureSpecsFrom(RecyclerView recyclerView) { 210 super.setExactMeasureSpecsFrom(recyclerView); 211 } 212 213 @Override setMeasureSpecs(int wSpec, int hSpec)214 public void setMeasureSpecs(int wSpec, int hSpec) { 215 super.setMeasureSpecs(wSpec, hSpec); 216 } 217 218 @Override setMeasuredDimensionFromChildren(int widthSpec, int heightSpec)219 public void setMeasuredDimensionFromChildren(int widthSpec, int heightSpec) { 220 super.setMeasuredDimensionFromChildren(widthSpec, heightSpec); 221 } 222 223 @Override shouldReMeasureChild(View child, int widthSpec, int heightSpec, RecyclerView.LayoutParams lp)224 public boolean shouldReMeasureChild(View child, int widthSpec, int heightSpec, 225 RecyclerView.LayoutParams lp) { 226 return super.shouldReMeasureChild(child, widthSpec, heightSpec, lp); 227 } 228 229 @Override shouldMeasureChild(View child, int widthSpec, int heightSpec, RecyclerView.LayoutParams lp)230 public boolean shouldMeasureChild(View child, int widthSpec, int heightSpec, 231 RecyclerView.LayoutParams lp) { 232 return super.shouldMeasureChild(child, widthSpec, heightSpec, lp); 233 } 234 235 @Override removeAndRecycleScrapInt(RecyclerView.Recycler recycler)236 public void removeAndRecycleScrapInt(RecyclerView.Recycler recycler) { 237 super.removeAndRecycleScrapInt(recycler); 238 } 239 240 @Override stopSmoothScroller()241 public void stopSmoothScroller() { 242 super.stopSmoothScroller(); 243 } 244 245 @Override shouldMeasureTwice()246 public boolean shouldMeasureTwice() { 247 return super.shouldMeasureTwice(); 248 } 249 250 // END MOCKITO OVERRIDES 251 } 252 253 public class WrapAdapter extends RecyclerView.Adapter { 254 255 @Override onCreateViewHolder(ViewGroup parent, int viewType)256 public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 257 return null; 258 } 259 260 @Override onBindViewHolder(RecyclerView.ViewHolder holder, int position)261 public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 262 263 } 264 265 @Override getItemCount()266 public int getItemCount() { 267 return 10; 268 } 269 } 270 } 271