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 */
16package android.support.v17.leanback.widget;
17
18import static org.junit.Assert.assertEquals;
19import static org.mockito.Matchers.anyInt;
20import static org.mockito.Mockito.mock;
21import static org.mockito.Mockito.times;
22import static org.mockito.Mockito.verify;
23
24import android.support.test.filters.SmallTest;
25import android.support.test.runner.AndroidJUnit4;
26import android.support.v7.widget.RecyclerView;
27
28import org.junit.Test;
29import org.junit.runner.RunWith;
30
31/**
32 * Testing SingleRow algorithm
33 */
34@SmallTest
35@RunWith(AndroidJUnit4.class)
36public class SingleRowTest extends GridTest {
37
38    private SingleRow mSingleRow;
39
40    @Test
41    public void testAppendPrependRemove() {
42        mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
43
44        mSingleRow = new SingleRow();
45        mSingleRow.setSpacing(20);
46        mSingleRow.setProvider(mProvider);
47        mSingleRow.appendVisibleItems(200);
48        assertEquals(dump(mSingleRow) + " Should filled 2 items", 1, mSingleRow.mLastVisibleIndex);
49
50        mSingleRow.appendVisibleItems(201);
51        assertEquals(dump(mSingleRow) + " Should filled 3 items",
52                2, mSingleRow.mLastVisibleIndex);
53
54        mSingleRow.appendVisibleItems(251);
55        assertEquals(dump(mSingleRow) + " Should filled 4 items",
56                3, mSingleRow.mLastVisibleIndex);
57
58        mSingleRow.appendVisibleItems(Integer.MAX_VALUE);
59        assertEquals(dump(mSingleRow) + " Should filled 6 items",
60                5, mSingleRow.mLastVisibleIndex);
61        assertEquals(mProvider.getEdge(0), 0);
62        assertEquals(mProvider.getEdge(1), 100);
63        assertEquals(mProvider.getEdge(2), 200);
64        assertEquals(mProvider.getEdge(3), 250);
65        assertEquals(mProvider.getEdge(4), 370);
66        assertEquals(mProvider.getEdge(5), 430);
67
68        mSingleRow.removeInvisibleItemsAtEnd(0, 200);
69        assertEquals(dump(mSingleRow) + " Should filled 2 items", 1, mSingleRow.mLastVisibleIndex);
70
71        mSingleRow.appendVisibleItems(Integer.MAX_VALUE);
72        assertEquals(dump(mSingleRow) + " Should filled 6 items",
73                5, mSingleRow.mLastVisibleIndex);
74
75        mSingleRow.removeInvisibleItemsAtFront(1000, 80);
76        assertEquals(dump(mSingleRow) + " visible index should start from 1",
77                1, mSingleRow.mFirstVisibleIndex);
78
79        mSingleRow.prependVisibleItems(0);
80        assertEquals(dump(mSingleRow) + " visible index should start from 0",
81                0, mSingleRow.mFirstVisibleIndex);
82    }
83
84    @Test
85    public void testAppendPrependRemoveReversed() {
86        mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
87
88        mSingleRow = new SingleRow();
89        mSingleRow.setSpacing(20);
90        mSingleRow.setProvider(mProvider);
91        mSingleRow.setReversedFlow(true);
92        mSingleRow.appendVisibleItems(-200);
93        assertEquals(dump(mSingleRow) + " Should filled 2 items", 1, mSingleRow.mLastVisibleIndex);
94
95        mSingleRow.appendVisibleItems(-201);
96        assertEquals(dump(mSingleRow) + " Should filled 3 items",
97                2, mSingleRow.mLastVisibleIndex);
98
99        mSingleRow.appendVisibleItems(-251);
100        assertEquals(dump(mSingleRow) + " Should filled 4 items",
101                3, mSingleRow.mLastVisibleIndex);
102
103        mSingleRow.appendVisibleItems(Integer.MIN_VALUE);
104        assertEquals(dump(mSingleRow) + " Should filled 6 items",
105                5, mSingleRow.mLastVisibleIndex);
106        assertEquals(mProvider.getEdge(0), 0);
107        assertEquals(mProvider.getEdge(1), -100);
108        assertEquals(mProvider.getEdge(2), -200);
109        assertEquals(mProvider.getEdge(3), -250);
110        assertEquals(mProvider.getEdge(4), -370);
111        assertEquals(mProvider.getEdge(5), -430);
112
113        mSingleRow.removeInvisibleItemsAtEnd(0, -200);
114        assertEquals(dump(mSingleRow) + " Should filled 2 items", 1, mSingleRow.mLastVisibleIndex);
115
116        mSingleRow.appendVisibleItems(Integer.MIN_VALUE);
117        assertEquals(dump(mSingleRow) + " Should filled 6 items",
118                5, mSingleRow.mLastVisibleIndex);
119
120        mSingleRow.removeInvisibleItemsAtFront(1000, -80);
121        assertEquals(dump(mSingleRow) + " Should filled 6 items",
122                1, mSingleRow.mFirstVisibleIndex);
123    }
124
125    @Test
126    public void testPrependWithSpacing() {
127
128        mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
129
130        mSingleRow = new SingleRow();
131        mSingleRow.setSpacing(20);
132        mSingleRow.setProvider(mProvider);
133        mSingleRow.appendVisibleItems(200);
134        assertEquals(dump(mSingleRow) + " Should filled 2 items", 1, mSingleRow.mLastVisibleIndex);
135
136        mProvider.scroll(90);
137        mSingleRow.removeInvisibleItemsAtFront(Integer.MAX_VALUE, 0);
138        mSingleRow.appendVisibleItems(200);
139        assertEquals(dump(mSingleRow) + " Should filled 1 ~ 3", 1, mSingleRow.mFirstVisibleIndex);
140        assertEquals(dump(mSingleRow) + " Should filled 1 ~ 3", 3, mSingleRow.mLastVisibleIndex);
141        assertEquals(mProvider.getEdge(1), 10);
142
143        mSingleRow.prependVisibleItems(0);
144        assertEquals(dump(mSingleRow) + " Should not prepend 0", 1, mSingleRow.mFirstVisibleIndex);
145    }
146
147    @Test
148    public void testPrependWithSpacingReversed() {
149
150        mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
151
152        mSingleRow = new SingleRow();
153        mSingleRow.setSpacing(20);
154        mSingleRow.setProvider(mProvider);
155        mSingleRow.setReversedFlow(true);
156        mSingleRow.appendVisibleItems(-200);
157        assertEquals(dump(mSingleRow) + " Should filled 2 items", 1, mSingleRow.mLastVisibleIndex);
158
159        mProvider.scroll(-90);
160        mSingleRow.removeInvisibleItemsAtFront(Integer.MAX_VALUE, 0);
161        mSingleRow.appendVisibleItems(-200);
162        assertEquals(dump(mSingleRow) + " Should filled 1 ~ 3", 1, mSingleRow.mFirstVisibleIndex);
163        assertEquals(dump(mSingleRow) + " Should filled 1 ~ 3", 3, mSingleRow.mLastVisibleIndex);
164        assertEquals(mProvider.getEdge(1), -10);
165
166        mSingleRow.prependVisibleItems(0);
167        assertEquals(dump(mSingleRow) + " Should not prepend 0", 1, mSingleRow.mFirstVisibleIndex);
168    }
169
170    public void validatePrefetch(int fromLimit, int delta, Integer[]... positionData) {
171        // duplicates logic in support.v7.widget.CacheUtils#verifyPositionsPrefetched
172        RecyclerView.LayoutManager.LayoutPrefetchRegistry registry
173                = mock(RecyclerView.LayoutManager.LayoutPrefetchRegistry.class);
174        mSingleRow.collectAdjacentPrefetchPositions(fromLimit, delta, registry);
175
176        verify(registry, times(positionData.length)).addPosition(anyInt(), anyInt());
177        for (Integer[] aPositionData : positionData) {
178            verify(registry).addPosition(aPositionData[0], aPositionData[1]);
179        }
180    }
181
182    @Test
183    public void testPrefetchBounds() {
184        mProvider = new Provider(new int[]{100, 100});
185
186        mSingleRow = new SingleRow();
187        mSingleRow.setSpacing(20);
188        mSingleRow.setProvider(mProvider);
189        mSingleRow.appendVisibleItems(150);
190
191        validatePrefetch(0, -10);
192        validatePrefetch(-150, 10);
193    }
194
195    @Test
196    public void testPrefetchBoundsReversed() {
197        mProvider = new Provider(new int[]{100, 100});
198
199        mSingleRow = new SingleRow();
200        mSingleRow.setSpacing(20);
201        mSingleRow.setProvider(mProvider);
202        mSingleRow.setReversedFlow(true);
203        mSingleRow.appendVisibleItems(-150);
204
205        validatePrefetch(0, -10);
206        validatePrefetch(150, 10);
207    }
208
209    @Test
210    public void testPrefetchItems() {
211        mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
212
213        mSingleRow = new SingleRow();
214        mSingleRow.setSpacing(20);
215        mSingleRow.setProvider(mProvider);
216        mSingleRow.appendVisibleItems(200);
217
218        // next item, 2, is 0 pixels away
219        validatePrefetch(200, 10, new Integer[] {2, 0});
220
221        // nothing above
222        validatePrefetch(0, -10);
223
224        mProvider.scroll(90);
225        mSingleRow.removeInvisibleItemsAtFront(Integer.MAX_VALUE, 0);
226        mSingleRow.appendVisibleItems(200);
227
228        // next item, 4, is 80 pixels away
229        validatePrefetch(200, 10, new Integer[] {4, 80});
230
231        // next item, 0, is 10 pixels away
232        validatePrefetch(0, -10, new Integer[] {0, 10});
233    }
234
235    @Test
236    public void testPrefetchItemsReversed() {
237        mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
238
239        mSingleRow = new SingleRow();
240        mSingleRow.setSpacing(20);
241        mSingleRow.setProvider(mProvider);
242        mSingleRow.setReversedFlow(true);
243        mSingleRow.appendVisibleItems(-200);
244
245        // next item, 2, is 0 pixels away
246        validatePrefetch(-200, -10, new Integer[] {2, 0});
247
248        // nothing above
249        validatePrefetch(0, 10);
250
251        mProvider.scroll(-90);
252        mSingleRow.removeInvisibleItemsAtFront(Integer.MAX_VALUE, 0);
253        mSingleRow.appendVisibleItems(-200);
254
255        // next item, 4, is 80 pixels away
256        validatePrefetch(-200, -10, new Integer[] {4, 80});
257
258        // one above, 0, is 10 pixels away
259        validatePrefetch(0, 10, new Integer[] {0, 10});
260
261    }
262}