BaseRecyclerViewInstrumentationTest.java revision 15a9db9177a871c7b1cd65b8923beac1b9b75174
1/*
2 * Copyright (C) 2014 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 android.test.ActivityInstrumentationTestCase2;
20import android.util.Log;
21import android.view.View;
22import android.view.ViewGroup;
23import android.widget.TextView;
24
25import java.util.ArrayList;
26import java.util.List;
27import java.util.concurrent.CountDownLatch;
28import java.util.concurrent.TimeUnit;
29
30abstract public class BaseRecyclerViewInstrumentationTest extends
31        ActivityInstrumentationTestCase2<TestActivity> {
32
33    private static final String TAG = "RecyclerViewTest";
34
35    private static final boolean DEBUG = true;
36
37    public BaseRecyclerViewInstrumentationTest() {
38        super("android.support.v7.widget", TestActivity.class);
39    }
40
41    class TestViewHolder extends RecyclerView.ViewHolder {
42
43        Item mBindedItem;
44
45        public TestViewHolder(View itemView) {
46            super(itemView);
47        }
48    }
49
50    class TestLayoutManager extends RecyclerView.LayoutManager {
51
52        CountDownLatch layoutLatch;
53
54        public void expectLayouts(int count) {
55            layoutLatch = new CountDownLatch(count);
56        }
57
58        public void waitForLayout(long timeout, TimeUnit timeUnit) throws InterruptedException {
59            layoutLatch.await(timeout, timeUnit);
60            assertEquals("all expected layouts should be executed at the expected time",
61                    0, layoutLatch.getCount());
62        }
63
64        @Override
65        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
66            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
67                    ViewGroup.LayoutParams.WRAP_CONTENT);
68        }
69
70        void assertVisibleItemPositions() {
71            int i = getChildCount();
72            TestAdapter testAdapter = (TestAdapter) mRecyclerView.getAdapter();
73            while (i-- > 0) {
74                View view = getChildAt(i);
75                RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();
76                Item item = ((TestViewHolder) lp.mViewHolder).mBindedItem;
77                if (DEBUG) {
78                    Log.d(TAG, "testing item " + i);
79                }
80                assertSame("item position in LP should match adapter value",
81                        testAdapter.mItems.get(lp.getViewPosition()), item);
82            }
83        }
84
85        void layoutRange(RecyclerView.Recycler recycler, int start,
86                int end) {
87            if (DEBUG) {
88                Log.d(TAG, "will layout items from " + start + " to " + end);
89            }
90            for (int i = start; i < end; i++) {
91                if (DEBUG) {
92                    Log.d(TAG, "laying out item " + i);
93                }
94                View view = recycler.getViewForPosition(i);
95                assertNotNull("view should not be null for valid position", view);
96                addView(view);
97                measureChildWithMargins(view, 0, 0);
98                layoutDecorated(view, 0, (i - start) * 10, getDecoratedMeasuredWidth(view)
99                        , getDecoratedMeasuredHeight(view));
100            }
101        }
102    }
103
104    static class Item {
105
106        int originalIndex;
107
108        final String text;
109
110        Item(int originalIndex, String text) {
111            this.originalIndex = originalIndex;
112            this.text = text;
113        }
114    }
115
116    class TestAdapter extends RecyclerView.Adapter<TestViewHolder> {
117
118        List<Item> mItems;
119
120        TestAdapter(int count) {
121            mItems = new ArrayList<Item>(count);
122            for (int i = 0; i < count; i++) {
123                mItems.add(new Item(i, "Item " + i));
124            }
125        }
126
127        @Override
128        public TestViewHolder onCreateViewHolder(ViewGroup parent,
129                int viewType) {
130            return new TestViewHolder(new TextView(parent.getContext()));
131        }
132
133        @Override
134        public void onBindViewHolder(TestViewHolder holder, int position) {
135            final Item item = mItems.get(position);
136            ((TextView) (holder.itemView)).setText(item.text);
137            holder.mBindedItem = item;
138        }
139
140        public void deleteRangeAndNotify(final int start, final int end) throws Throwable {
141            runTestOnUiThread(new Runnable() {
142                @Override
143                public void run() {
144                    for (int i = start; i < end; i++) {
145                        mItems.remove(start);
146                    }
147                    notifyItemRangeRemoved(start, end - start);
148                }
149            });
150        }
151
152        public void addRangeAndNotify(final int start, final int end) throws Throwable {
153            runTestOnUiThread(new Runnable() {
154                @Override
155                public void run() {
156                    final int count = end - start;
157                    for (int i = start; i < end; i++) {
158                        mItems.add(start, new Item(i, "new item " + i));
159                    }
160                    // offset others
161                    for (int i = end; i < mItems.size(); i++) {
162                        mItems.get(i).originalIndex += count;
163                    }
164                    notifyItemRangeInserted(start, count);
165                }
166            });
167
168        }
169
170        @Override
171        public int getItemCount() {
172            return mItems.size();
173        }
174    }
175}
176
177