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.leanback.widget; 18 19import static org.junit.Assert.assertTrue; 20import static org.mockito.Matchers.any; 21import static org.mockito.Mockito.never; 22import static org.mockito.Mockito.spy; 23import static org.mockito.Mockito.times; 24 25import android.content.Context; 26import android.support.test.InstrumentationRegistry; 27import android.support.test.filters.SmallTest; 28import android.view.View; 29import android.view.ViewGroup; 30 31import androidx.recyclerview.widget.LinearLayoutManager; 32import androidx.recyclerview.widget.RecyclerView; 33 34import org.junit.Before; 35import org.junit.Test; 36import org.junit.runner.RunWith; 37import org.junit.runners.JUnit4; 38import org.mockito.Mockito; 39 40import java.util.ArrayList; 41import java.util.List; 42 43@SmallTest 44@RunWith(JUnit4.class) 45public class ItemBridgeAdapterTest { 46 private static final int sViewWidth = 100; 47 private static final int sViewHeight = 100; 48 49 public static class BasePresenter extends Presenter { 50 51 @Override 52 public ViewHolder onCreateViewHolder(ViewGroup parent) { 53 View view = new View(parent.getContext()); 54 view.setLayoutParams(new ViewGroup.LayoutParams(sViewWidth, sViewHeight)); 55 return new ViewHolder(view); 56 } 57 58 @Override 59 public void onBindViewHolder(ViewHolder viewHolder, Object item) { 60 } 61 62 @Override 63 public void onUnbindViewHolder(ViewHolder viewHolder) { 64 65 } 66 } 67 68 private ItemBridgeAdapter mItemBridgeAdapter; 69 70 private ArrayObjectAdapter mAdapter; 71 72 private RecyclerView mRecyclerView; 73 74 private Presenter mPresenter; 75 76 @Before 77 public void setup() { 78 mPresenter = spy(BasePresenter.class); 79 80 mItemBridgeAdapter = new ItemBridgeAdapter(); 81 mAdapter = new ArrayObjectAdapter(mPresenter); 82 mAdapter.setItems(populateData(), null); 83 mItemBridgeAdapter.setAdapter(mAdapter); 84 85 Context context = InstrumentationRegistry.getTargetContext(); 86 mRecyclerView = new RecyclerView(context); 87 mRecyclerView.setItemViewCacheSize(0); 88 mRecyclerView.setLayoutManager(new LinearLayoutManager(context, 89 LinearLayoutManager.VERTICAL, false)); 90 mRecyclerView.setHasFixedSize(false); // force layout items in layout pass 91 mRecyclerView.setAdapter(mItemBridgeAdapter); 92 measureAndLayoutRecycleView(mRecyclerView); 93 } 94 95 List populateData() { 96 List data = new ArrayList(); 97 for (int i = 0; i < 10000; i++) { 98 data.add(i); 99 } 100 return data; 101 } 102 103 static void measureAndLayoutRecycleView(RecyclerView recyclerView) { 104 measureAndLayout(recyclerView, 1920, 1080); 105 } 106 107 static void measureAndLayout(View view, int expectedWidth, int expectedHeight) { 108 view.measure(View.MeasureSpec.makeMeasureSpec(expectedWidth, View.MeasureSpec.EXACTLY), 109 View.MeasureSpec.makeMeasureSpec(expectedHeight, View.MeasureSpec.EXACTLY)); 110 view.layout(0, 0, expectedWidth, expectedHeight); 111 } 112 113 @Test 114 public void onCreateAndOnBind() { 115 int childCount = mRecyclerView.getChildCount(); 116 assertTrue(childCount > 0); 117 // Assert number of invokes of onCreateViewHolder and onBindViewHolder. 118 Mockito.verify(mPresenter, times(childCount)).onCreateViewHolder(any(ViewGroup.class)); 119 Mockito.verify(mPresenter, times(childCount)) 120 .onBindViewHolder(any(Presenter.ViewHolder.class), any()); 121 } 122 @Test 123 public void onUnbind() { 124 assertTrue(mRecyclerView.getChildCount() > 0); 125 // When scroll one item offscreen, assert onUnbindViewHolder called once. 126 mRecyclerView.scrollBy(0, mRecyclerView.getChildAt(0).getHeight()); 127 Mockito.verify(mPresenter, times(1)) 128 .onUnbindViewHolder(any(Presenter.ViewHolder.class)); 129 } 130 131 @Test 132 public void onUnbindWithTransientState() { 133 assertTrue(mRecyclerView.getChildCount() > 0); 134 // Set TransientState to true to simulate the view is running custom ViewPropertyAnimation. 135 mRecyclerView.getChildAt(0).setHasTransientState(true); 136 // When scroll one item with custom animation offscreen, assert onUnbindViewHolder 137 // was called once when ViewHolder is still having transient state. 138 mRecyclerView.scrollBy(0, mRecyclerView.getChildAt(0).getHeight()); 139 Mockito.verify(mPresenter, times(1)) 140 .onUnbindViewHolder(any(Presenter.ViewHolder.class)); 141 } 142} 143