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