1 // Copyright 2020 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser.tasks; 6 7 import static org.junit.Assert.assertEquals; 8 import static org.junit.Assert.assertFalse; 9 import static org.junit.Assert.assertNotNull; 10 import static org.junit.Assert.assertTrue; 11 import static org.mockito.ArgumentMatchers.anyLong; 12 import static org.mockito.ArgumentMatchers.eq; 13 import static org.mockito.Mockito.doReturn; 14 import static org.mockito.Mockito.times; 15 import static org.mockito.Mockito.verify; 16 17 import static org.chromium.chrome.browser.tasks.SingleTabViewProperties.CLICK_LISTENER; 18 import static org.chromium.chrome.browser.tasks.SingleTabViewProperties.FAVICON; 19 import static org.chromium.chrome.browser.tasks.SingleTabViewProperties.TITLE; 20 21 import android.graphics.drawable.BitmapDrawable; 22 import android.graphics.drawable.Drawable; 23 24 import org.junit.After; 25 import org.junit.Before; 26 import org.junit.Test; 27 import org.junit.runner.RunWith; 28 import org.mockito.ArgumentCaptor; 29 import org.mockito.Captor; 30 import org.mockito.Mock; 31 import org.mockito.MockitoAnnotations; 32 import org.robolectric.annotation.Config; 33 34 import org.chromium.base.Callback; 35 import org.chromium.base.test.BaseRobolectricTestRunner; 36 import org.chromium.chrome.browser.tab.Tab; 37 import org.chromium.chrome.browser.tab.TabSelectionType; 38 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; 39 import org.chromium.chrome.browser.tabmodel.TabList; 40 import org.chromium.chrome.browser.tabmodel.TabModel; 41 import org.chromium.chrome.browser.tabmodel.TabModelObserver; 42 import org.chromium.chrome.browser.tabmodel.TabModelSelector; 43 import org.chromium.chrome.browser.tasks.tab_management.TabListFaviconProvider; 44 import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher; 45 import org.chromium.ui.modelutil.PropertyModel; 46 47 /** Tests for {@link SingleTabSwitcherMediator}. */ 48 @RunWith(BaseRobolectricTestRunner.class) 49 @Config(manifest = Config.NONE) 50 public class SingleTabSwitcherMediatorUnitTest { 51 private final int mTabId = 1; 52 private final String mTitle = "test"; 53 private final String mUrlString = "chrome://test.com"; 54 private final int mTabId2 = 2; 55 private final String mTitle2 = "test2"; 56 private final String mUrlString2 = "chrome://test2.com"; 57 private SingleTabSwitcherMediator mMediator; 58 private PropertyModel mPropertyModel; 59 60 @Mock 61 private TabModelSelector mTabModelSelector; 62 @Mock 63 private TabModel mNormalTabModel; 64 @Mock 65 private TabModel mIncognitoTabModel; 66 @Mock 67 private Tab mTab; 68 @Mock 69 private Tab mTab2; 70 @Mock 71 private TabListFaviconProvider mTabListFaviconProvider; 72 @Mock 73 private TabSwitcher.OnTabSelectingListener mOnTabSelectingListener; 74 @Mock 75 private TabSwitcher.OverviewModeObserver mOverviewModeObserver; 76 @Captor 77 private ArgumentCaptor<EmptyTabModelSelectorObserver> mTabModelSelectorObserverCaptor; 78 @Captor 79 private ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor; 80 @Captor 81 private ArgumentCaptor<Callback<Drawable>> mFaviconCallbackCaptor; 82 83 @Before setUp()84 public void setUp() { 85 MockitoAnnotations.initMocks(this); 86 87 doReturn(new BitmapDrawable()) 88 .when(mTabListFaviconProvider) 89 .getDefaultFaviconDrawable(false); 90 doReturn(mNormalTabModel).when(mTabModelSelector).getModel(false); 91 doReturn(mTabId).when(mTabModelSelector).getCurrentTabId(); 92 doReturn(false).when(mTabModelSelector).isIncognitoSelected(); 93 doReturn(mTab).when(mNormalTabModel).getTabAt(0); 94 doReturn(0).when(mNormalTabModel).index(); 95 doReturn(1).when(mNormalTabModel).getCount(); 96 doReturn(false).when(mNormalTabModel).isIncognito(); 97 doReturn(mUrlString).when(mTab).getUrlString(); 98 doReturn(mTabId).when(mTab).getId(); 99 doReturn(mTitle).when(mTab).getTitle(); 100 doReturn(mUrlString2).when(mTab2).getUrlString(); 101 doReturn(mTabId2).when(mTab2).getId(); 102 doReturn(mTitle2).when(mTab2).getTitle(); 103 doReturn(true).when(mIncognitoTabModel).isIncognito(); 104 105 mPropertyModel = new PropertyModel(SingleTabViewProperties.ALL_KEYS); 106 mMediator = new SingleTabSwitcherMediator( 107 mPropertyModel, mTabModelSelector, mTabListFaviconProvider); 108 } 109 110 @After tearDown()111 public void tearDown() { 112 mMediator = null; 113 } 114 115 @Test showAndHide()116 public void showAndHide() { 117 assertNotNull(mPropertyModel.get(FAVICON)); 118 assertNotNull(mPropertyModel.get(CLICK_LISTENER)); 119 assertFalse(mMediator.overviewVisible()); 120 mMediator.setOnTabSelectingListener(mOnTabSelectingListener); 121 mMediator.addOverviewModeObserver(mOverviewModeObserver); 122 123 mMediator.showOverview(true); 124 verify(mNormalTabModel).addObserver(mTabModelObserverCaptor.capture()); 125 verify(mTabModelSelector).addObserver(mTabModelSelectorObserverCaptor.capture()); 126 verify(mTabListFaviconProvider) 127 .getFaviconForUrlAsync(eq(mUrlString), eq(false), mFaviconCallbackCaptor.capture()); 128 assertTrue(mMediator.overviewVisible()); 129 verify(mOverviewModeObserver).startedShowing(); 130 verify(mOverviewModeObserver).finishedShowing(); 131 assertEquals(mPropertyModel.get(TITLE), mTitle); 132 133 mPropertyModel.get(CLICK_LISTENER).onClick(null); 134 verify(mOnTabSelectingListener).onTabSelecting(anyLong(), eq(mTabId)); 135 136 mMediator.hideOverview(true); 137 assertFalse(mMediator.overviewVisible()); 138 assertEquals(mPropertyModel.get(TITLE), ""); 139 verify(mOverviewModeObserver).startedHiding(); 140 verify(mOverviewModeObserver).finishedHiding(); 141 142 mMediator.removeOverviewModeObserver(mOverviewModeObserver); 143 mMediator.setOnTabSelectingListener(null); 144 } 145 146 @Test selectTabAfterSwitchingTabModel()147 public void selectTabAfterSwitchingTabModel() { 148 assertFalse(mMediator.overviewVisible()); 149 mMediator.setOnTabSelectingListener(mOnTabSelectingListener); 150 mMediator.addOverviewModeObserver(mOverviewModeObserver); 151 152 mMediator.showOverview(true); 153 verify(mNormalTabModel).addObserver(mTabModelObserverCaptor.capture()); 154 verify(mTabModelSelector).addObserver(mTabModelSelectorObserverCaptor.capture()); 155 verify(mTabListFaviconProvider) 156 .getFaviconForUrlAsync(eq(mUrlString), eq(false), mFaviconCallbackCaptor.capture()); 157 assertTrue(mMediator.overviewVisible()); 158 verify(mOverviewModeObserver).startedShowing(); 159 verify(mOverviewModeObserver).finishedShowing(); 160 assertEquals(mPropertyModel.get(TITLE), mTitle); 161 162 mTabModelObserverCaptor.getValue().didSelectTab(mTab, TabSelectionType.FROM_USER, -1); 163 verify(mOnTabSelectingListener).onTabSelecting(anyLong(), eq(mTabId)); 164 165 mTabModelSelectorObserverCaptor.getValue().onTabModelSelected( 166 mIncognitoTabModel, mNormalTabModel); 167 mTabModelSelectorObserverCaptor.getValue().onTabModelSelected( 168 mNormalTabModel, mIncognitoTabModel); 169 170 // The next tab selecting event should be ignored. 171 mTabModelObserverCaptor.getValue().didSelectTab(mTab, TabSelectionType.FROM_USER, mTabId); 172 verify(mOnTabSelectingListener, times(1)).onTabSelecting(anyLong(), eq(mTabId)); 173 174 mTabModelObserverCaptor.getValue().didSelectTab(mTab, TabSelectionType.FROM_USER, mTabId); 175 verify(mOnTabSelectingListener, times(2)).onTabSelecting(anyLong(), eq(mTabId)); 176 177 mMediator.hideOverview(true); 178 assertFalse(mMediator.overviewVisible()); 179 assertEquals(mPropertyModel.get(TITLE), ""); 180 verify(mOverviewModeObserver).startedHiding(); 181 verify(mOverviewModeObserver).finishedHiding(); 182 } 183 184 @Test selectNextTabAfterClosingTheSelectedTab()185 public void selectNextTabAfterClosingTheSelectedTab() { 186 assertFalse(mMediator.overviewVisible()); 187 mMediator.setOnTabSelectingListener(mOnTabSelectingListener); 188 mMediator.addOverviewModeObserver(mOverviewModeObserver); 189 190 mMediator.showOverview(true); 191 verify(mNormalTabModel).addObserver(mTabModelObserverCaptor.capture()); 192 verify(mTabModelSelector).addObserver(mTabModelSelectorObserverCaptor.capture()); 193 verify(mTabListFaviconProvider) 194 .getFaviconForUrlAsync(eq(mUrlString), eq(false), mFaviconCallbackCaptor.capture()); 195 assertTrue(mMediator.overviewVisible()); 196 verify(mOverviewModeObserver).startedShowing(); 197 verify(mOverviewModeObserver).finishedShowing(); 198 assertEquals(mPropertyModel.get(TITLE), mTitle); 199 200 mTabModelObserverCaptor.getValue().didSelectTab( 201 mTab2, TabSelectionType.FROM_CLOSE, mTabId2); 202 verify(mOnTabSelectingListener, times(0)).onTabSelecting(anyLong(), eq(mTabId2)); 203 assertEquals(mPropertyModel.get(TITLE), mTitle2); 204 205 mMediator.hideOverview(true); 206 assertFalse(mMediator.overviewVisible()); 207 assertEquals(mPropertyModel.get(TITLE), ""); 208 verify(mOverviewModeObserver).startedHiding(); 209 verify(mOverviewModeObserver).finishedHiding(); 210 } 211 212 @Test selectTabAfterSwitchingTabModelAndReshown()213 public void selectTabAfterSwitchingTabModelAndReshown() { 214 assertFalse(mMediator.overviewVisible()); 215 mMediator.setOnTabSelectingListener(mOnTabSelectingListener); 216 mMediator.addOverviewModeObserver(mOverviewModeObserver); 217 218 mMediator.showOverview(true); 219 verify(mNormalTabModel).addObserver(mTabModelObserverCaptor.capture()); 220 verify(mTabModelSelector).addObserver(mTabModelSelectorObserverCaptor.capture()); 221 verify(mTabListFaviconProvider) 222 .getFaviconForUrlAsync(eq(mUrlString), eq(false), mFaviconCallbackCaptor.capture()); 223 assertEquals(mPropertyModel.get(TITLE), mTitle); 224 225 mTabModelSelectorObserverCaptor.getValue().onTabModelSelected( 226 mIncognitoTabModel, mNormalTabModel); 227 mTabModelSelectorObserverCaptor.getValue().onTabModelSelected( 228 mNormalTabModel, mIncognitoTabModel); 229 mMediator.hideOverview(true); 230 231 // The next tab selecting event should not be ignored after hiding and reshowing. 232 mMediator.showOverview(true); 233 mTabModelObserverCaptor.getValue().didSelectTab(mTab, TabSelectionType.FROM_USER, -1); 234 verify(mOnTabSelectingListener).onTabSelecting(anyLong(), eq(mTabId)); 235 236 mMediator.hideOverview(true); 237 } 238 239 @Test onBackPressed()240 public void onBackPressed() { 241 assertFalse(mMediator.overviewVisible()); 242 mMediator.setOnTabSelectingListener(mOnTabSelectingListener); 243 mMediator.addOverviewModeObserver(mOverviewModeObserver); 244 245 assertFalse(mMediator.onBackPressed()); 246 247 mMediator.showOverview(true); 248 assertTrue(mMediator.onBackPressed()); 249 verify(mOnTabSelectingListener).onTabSelecting(anyLong(), eq(mTabId)); 250 251 doReturn(TabList.INVALID_TAB_INDEX).when(mTabModelSelector).getCurrentTabId(); 252 assertFalse(mMediator.onBackPressed()); 253 254 doReturn(mTabId).when(mTabModelSelector).getCurrentTabId(); 255 doReturn(true).when(mTabModelSelector).isIncognitoSelected(); 256 assertFalse(mMediator.onBackPressed()); 257 } 258 } 259