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
17package android.support.v7.widget;
18
19import org.junit.After;
20import org.junit.Before;
21import org.junit.Test;
22import org.junit.runner.RunWith;
23
24import android.content.Context;
25import android.support.annotation.Nullable;
26import android.support.test.InstrumentationRegistry;
27import android.support.test.runner.AndroidJUnit4;
28import android.test.AndroidTestCase;
29import android.view.Display;
30import android.view.View;
31import android.view.ViewGroup;
32
33import static org.mockito.Mockito.any;
34import static org.mockito.Mockito.anyInt;
35import static org.mockito.Mockito.doReturn;
36import static org.mockito.Mockito.eq;
37import static org.mockito.Mockito.mock;
38import static org.mockito.Mockito.spy;
39import static org.mockito.Mockito.times;
40import static org.mockito.Mockito.verify;
41import static org.mockito.Mockito.when;
42
43@RunWith(AndroidJUnit4.class)
44public class WrapContentBasicTest extends AndroidTestCase {
45
46    private WrapContentLayoutManager mLayoutManager;
47    private RecyclerView mRecyclerView;
48    private WrapAdapter mAdapter;
49    private static int WRAP = View.MeasureSpec.makeMeasureSpec(10, View.MeasureSpec.AT_MOST);
50    private static int EXACT = View.MeasureSpec.makeMeasureSpec(10, View.MeasureSpec.EXACTLY);
51    private static int UNSPECIFIED = View.MeasureSpec
52            .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
53
54    @Before
55    @Override
56    public void setUp() throws Exception {
57        super.setUp();
58        setContext(InstrumentationRegistry.getContext());
59        RecyclerView rv = new RecyclerView(getContext());
60        mRecyclerView = spy(rv);
61        mLayoutManager = spy(new WrapContentLayoutManager());
62        // working around a mockito issue
63        rv.mLayout = mLayoutManager;
64        mAdapter = spy(new WrapAdapter());
65        mRecyclerView.setLayoutManager(mLayoutManager);
66        mRecyclerView.setAdapter(mAdapter);
67    }
68
69    @After
70    @Override
71    public void tearDown() throws Exception {
72        super.tearDown();
73    }
74
75    @Test
76    public void testLayoutInOnMeasureWithoutPredictive() {
77        mLayoutManager.setAutoMeasureEnabled(true);
78        when(mLayoutManager.supportsPredictiveItemAnimations()).thenReturn(false);
79        mRecyclerView.onMeasure(WRAP, WRAP);
80        mRecyclerView.onMeasure(WRAP, WRAP);
81        mRecyclerView.onLayout(true, 0, 10, 10, 10);
82        verify(mLayoutManager, times(3))
83                .onLayoutChildren(mRecyclerView.mRecycler, mRecyclerView.mState);
84    }
85
86    @Test
87    public void dataChangeAfterMeasure() {
88        mLayoutManager.setAutoMeasureEnabled(true);
89        mRecyclerView.onMeasure(WRAP, WRAP);
90        mRecyclerView.onMeasure(WRAP, WRAP);
91        mAdapter.notifyItemChanged(1);
92        mRecyclerView.onLayout(true, 0, 10, 10, 10);
93        verify(mLayoutManager, times(3))
94                .onLayoutChildren(mRecyclerView.mRecycler, mRecyclerView.mState);
95    }
96
97    @Test
98    public void setDimensionsFromChildren() {
99        mLayoutManager.setAutoMeasureEnabled(true);
100        View[] children = createMockChildren(3);
101        mLayoutManager.setMeasuredDimensionFromChildren(WRAP, WRAP);
102        verify(mLayoutManager).setMeasuredDimension(children[0].getWidth(),
103                children[0].getHeight());
104    }
105
106    @Test
107    public void setDimensionsFromChildrenAnsSpec1() {
108        mLayoutManager.setAutoMeasureEnabled(true);
109        View[] children = createMockChildren(3);
110        int hSpec = View.MeasureSpec.makeMeasureSpec(111, View.MeasureSpec.EXACTLY);
111        mLayoutManager.setMeasuredDimensionFromChildren(WRAP, hSpec);
112        verify(mLayoutManager).setMeasuredDimension(children[0].getWidth(), 111);
113    }
114
115    @Test
116    public void setDimensionsFromChildrenAnsSpec2() {
117        mLayoutManager.setAutoMeasureEnabled(true);
118        View[] children = createMockChildren(3);
119        int wSpec = View.MeasureSpec.makeMeasureSpec(111, View.MeasureSpec.EXACTLY);
120        mLayoutManager.setMeasuredDimensionFromChildren(wSpec, WRAP);
121        verify(mLayoutManager).setMeasuredDimension(111, children[0].getHeight());
122    }
123
124    @Test
125    public void setDimensionsFromChildrenAnsSpec3() {
126        mLayoutManager.setAutoMeasureEnabled(true);
127        View[] children = createMockChildren(3);
128        children[0].layout(0, 0, 100, 100);
129        children[1].layout(-5, 0, 100, 100);
130        children[2].layout(-5, -10, 100, 100);
131        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
132        verify(mLayoutManager).setMeasuredDimension(105, 110);
133    }
134
135    @Test
136    public void setDimensionsFromChildrenAnsSpec4() {
137        mLayoutManager.setAutoMeasureEnabled(true);
138        View[] children = createMockChildren(3);
139        children[0].layout(0, 0, 100, 100);
140        children[1].layout(-5, 0, 100, 100);
141        children[2].layout(-5, -10, 100, 100);
142        int atMost = View.MeasureSpec.makeMeasureSpec(95, View.MeasureSpec.AT_MOST);
143        mLayoutManager.setMeasuredDimensionFromChildren(atMost, atMost);
144        verify(mLayoutManager).setMeasuredDimension(95, 95);
145    }
146
147    @Test
148    public void setDimensionsFromChildrenAnsSpec5() {
149        mLayoutManager.setAutoMeasureEnabled(true);
150        View[] children = createMockChildren(3);
151        children[0].layout(0, 0, 100, 100);
152        children[1].layout(-5, 0, 100, 100);
153        children[2].layout(-5, -10, 100, 100);
154        when(mRecyclerView.getMinimumWidth()).thenReturn(250);
155        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
156        verify(mLayoutManager).setMeasuredDimension(250, 110);
157
158        when(mRecyclerView.getMinimumWidth()).thenReturn(5);
159        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
160        verify(mLayoutManager).setMeasuredDimension(105, 110);
161    }
162
163    @Test
164    public void setDimensionsFromChildrenAnsSpec6() {
165        mLayoutManager.setAutoMeasureEnabled(true);
166        View[] children = createMockChildren(3);
167        children[0].layout(0, 0, 100, 100);
168        children[1].layout(-5, 0, 100, 100);
169        children[2].layout(-5, -10, 100, 100);
170        when(mRecyclerView.getMinimumHeight()).thenReturn(250);
171        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
172        verify(mLayoutManager).setMeasuredDimension(105, 250);
173
174        when(mRecyclerView.getMinimumHeight()).thenReturn(50);
175        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
176        verify(mLayoutManager).setMeasuredDimension(105, 110);
177    }
178
179    private View[] createMockChildren(int count) {
180        View[] views = new View[count];
181        for (int i = 0; i < count; i++) {
182            View v = new View(getContext());
183            v.setLayoutParams(new RecyclerView.LayoutParams(1, 1));
184            views[i] = v;
185            when(mLayoutManager.getChildAt(i)).thenReturn(v);
186        }
187        when(mLayoutManager.getChildCount()).thenReturn(3);
188        return views;
189    }
190
191    public class WrapContentLayoutManager extends RecyclerView.LayoutManager {
192
193        @Override
194        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
195
196        }
197
198        @Override
199        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
200            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
201                    ViewGroup.LayoutParams.WRAP_CONTENT);
202        }
203    }
204
205    public class WrapAdapter extends RecyclerView.Adapter {
206
207        @Override
208        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
209            return null;
210        }
211
212        @Override
213        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
214
215        }
216
217        @Override
218        public int getItemCount() {
219            return 10;
220        }
221    }
222}
223