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 android.view.View.MeasureSpec.AT_MOST; 20import static android.view.View.MeasureSpec.EXACTLY; 21import static android.view.View.MeasureSpec.UNSPECIFIED; 22import static android.view.View.MeasureSpec.makeMeasureSpec; 23 24import android.graphics.Rect; 25import android.support.test.InstrumentationRegistry; 26import android.support.test.filters.SmallTest; 27import android.view.View; 28 29import org.hamcrest.CoreMatchers; 30import org.hamcrest.MatcherAssert; 31import org.junit.Before; 32import org.junit.Test; 33import org.junit.runner.RunWith; 34import org.junit.runners.Parameterized; 35 36import java.util.Arrays; 37import java.util.List; 38 39@RunWith(Parameterized.class) 40@SmallTest 41public class DefaultMeasureSpecTest { 42 private final int mWSpec; 43 private final int mHSpec; 44 private int mExpectedW; 45 private int mExpectedH; 46 private final Rect mPadding; 47 RecyclerView mRecyclerView; 48 49 @Before 50 public void setUp() throws Exception { 51 mRecyclerView = new RecyclerView(InstrumentationRegistry.getContext()); 52 if (mPadding != null) { 53 mRecyclerView.setPadding(mPadding.left, mPadding.top, mPadding.right, mPadding.bottom); 54 } 55 } 56 57 @Parameterized.Parameters(name = "{0}") 58 public static List<Object[]> param() { 59 List<Object[]> params = Arrays.asList( 60 new Object[]{null, makeMeasureSpec(10, EXACTLY), makeMeasureSpec(20, EXACTLY), 10, 61 20, new Rect(0, 0, 0, 0)}, 62 new Object[]{null, makeMeasureSpec(10, EXACTLY), makeMeasureSpec(100, AT_MOST), 10, 63 0, new Rect(0, 0, 0, 0)}, 64 new Object[]{null, makeMeasureSpec(10, AT_MOST), makeMeasureSpec(100, EXACTLY), 0, 65 100, new Rect(0, 0, 0, 0)}, 66 new Object[]{null, makeMeasureSpec(10, EXACTLY), makeMeasureSpec(100, UNSPECIFIED), 67 10, 0, new Rect(0, 0, 0, 0)}, 68 new Object[]{null, makeMeasureSpec(10, UNSPECIFIED), makeMeasureSpec(100, EXACTLY), 69 0, 100, new Rect(0, 0, 0, 0)}, 70 new Object[]{null, makeMeasureSpec(10, EXACTLY), makeMeasureSpec(20, EXACTLY), 10, 71 20, new Rect(39, 50, 34, 23)}, 72 new Object[]{null, makeMeasureSpec(10, EXACTLY), makeMeasureSpec(100, AT_MOST), 10, 73 50, new Rect(3, 35, 3, 15)}, 74 new Object[]{null, makeMeasureSpec(10, EXACTLY), makeMeasureSpec(100, AT_MOST), 10, 75 100, new Rect(3, 350, 3, 15)}, 76 77 new Object[]{null, makeMeasureSpec(10, AT_MOST), makeMeasureSpec(100, EXACTLY), 10, 78 100, new Rect(15, 500, 5, 30)}, 79 new Object[]{null, makeMeasureSpec(10, AT_MOST), makeMeasureSpec(100, EXACTLY), 5, 80 100, new Rect(3, 500, 2, 30)}, 81 new Object[]{null, makeMeasureSpec(10, EXACTLY), makeMeasureSpec(100, UNSPECIFIED), 82 10, 20, new Rect(500, 15, 30, 5)}, 83 new Object[]{null, makeMeasureSpec(10, UNSPECIFIED), makeMeasureSpec(100, EXACTLY), 84 45, 100, new Rect(15, 400, 30, 5)} 85 ); 86 for (Object[] param : params) { 87 param[0] = "width: " + log((Integer) param[1]) + ", height:" + log((Integer) param[2]); 88 param[0] = param[0] + ", padding:" + param[5]; 89 } 90 return params; 91 } 92 93 public DefaultMeasureSpecTest(@SuppressWarnings("UnusedParameters") String ignored, 94 int wSpec, int hSpec, int expectedW, int expectedH, Rect padding) { 95 mWSpec = wSpec; 96 mHSpec = hSpec; 97 mExpectedW = expectedW; 98 mExpectedH = expectedH; 99 this.mPadding = padding; 100 } 101 102 @Test 103 public void testWithSmallerMinWidth() { 104 mRecyclerView.setMinimumWidth(Math.max(0, mExpectedW - 5)); 105 runTest(); 106 } 107 108 @Test 109 public void testWithSmallerMinHeight() { 110 mRecyclerView.setMinimumHeight(Math.max(0, mExpectedH - 5)); 111 runTest(); 112 } 113 114 @Test 115 public void testWithLargerMinHeight() { 116 mRecyclerView.setMinimumHeight(mExpectedH + 5); 117 int mode = View.MeasureSpec.getMode(mHSpec); 118 switch (mode) { 119 case UNSPECIFIED: 120 mExpectedH += 5; 121 break; 122 case AT_MOST: 123 mExpectedH = Math.min(View.MeasureSpec.getSize(mHSpec), mExpectedH + 5); 124 break; 125 } 126 runTest(); 127 } 128 129 @Test 130 public void testWithLargerMinWidth() { 131 mRecyclerView.setMinimumWidth(mExpectedW + 5); 132 int mode = View.MeasureSpec.getMode(mWSpec); 133 switch (mode) { 134 case UNSPECIFIED: 135 mExpectedW += 5; 136 break; 137 case AT_MOST: 138 mExpectedW = Math.min(View.MeasureSpec.getSize(mWSpec), mExpectedW + 5); 139 break; 140 } 141 runTest(); 142 } 143 144 @Test 145 public void runTest() { 146 mRecyclerView.defaultOnMeasure(mWSpec, mHSpec); 147 MatcherAssert.assertThat("measured width", mRecyclerView.getMeasuredWidth(), 148 CoreMatchers.is(mExpectedW)); 149 MatcherAssert.assertThat("measured height", mRecyclerView.getMeasuredHeight(), 150 CoreMatchers.is(mExpectedH)); 151 } 152 153 private static String log(int spec) { 154 final int size = View.MeasureSpec.getSize(spec); 155 int mode = View.MeasureSpec.getMode(spec); 156 if (mode == View.MeasureSpec.AT_MOST) { 157 return "at most " + size; 158 } 159 if (mode == View.MeasureSpec.UNSPECIFIED) { 160 return "unspecified " + size; 161 } 162 if (mode == View.MeasureSpec.EXACTLY) { 163 return "exactly " + size; 164 } 165 return "?? " + size; 166 } 167} 168