// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tab;
import android.content.Context;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
import org.chromium.base.ObserverList;
import org.chromium.base.UserDataHost;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.JniMocker;
import org.chromium.cc.input.BrowserControlsState;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.components.browser_ui.util.BrowserControlsVisibilityDelegate;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.WindowAndroid;
import java.lang.ref.WeakReference;
/** Unit tests for {@link TabBrowserControlsConstraintsHelper}. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
@LooperMode(LooperMode.Mode.LEGACY)
public class TabBrowserControlsConstraintsHelperTest {
private final UserDataHost mUserDataHost = new UserDataHost();
@Rule public JniMocker mocker = new JniMocker();
@Mock TabImpl mTab;
@Mock WebContents mWebContents;
@Mock TabDelegateFactory mDelegateFactory;
@Mock TabBrowserControlsConstraintsHelper.Natives mJniMock;
private TabBrowserControlsConstraintsHelper mHelper;
private TabObserver mRegisteredTabObserver;
private TestVisibilityDelegate mVisibilityDelegate;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mocker.mock(TabBrowserControlsConstraintsHelperJni.TEST_HOOKS, mJniMock);
Mockito.when(mTab.getUserDataHost()).thenReturn(mUserDataHost);
Mockito.when(mTab.getDelegateFactory()).thenReturn(mDelegateFactory);
Mockito.when(mTab.getWebContents()).thenReturn(mWebContents);
ObserverList<TabObserver> observers = new ObserverList<>();
Mockito.when(mTab.getTabObservers())
.thenAnswer(invocation -> observers.rewindableIterator());
mVisibilityDelegate = new TestVisibilityDelegate();
Mockito.when(mDelegateFactory.createBrowserControlsVisibilityDelegate(Mockito.any()))
.thenReturn(mVisibilityDelegate);
}
private void initHelper() {
ArgumentCaptor<TabObserver> observerArg = ArgumentCaptor.forClass(TabObserver.class);
TabBrowserControlsConstraintsHelper.createForTab(mTab);
mHelper = TabBrowserControlsConstraintsHelper.get(mTab);
Mockito.verify(mTab).addObserver(observerArg.capture());
mRegisteredTabObserver = observerArg.getValue();
}
@Test
public void testUpdateVisibilityDelegate_onInitialized() {
initHelper();
Mockito.verify(mDelegateFactory, Mockito.never())
.createBrowserControlsVisibilityDelegate(mTab);
mRegisteredTabObserver.onInitialized(mTab, null);
Mockito.verify(mDelegateFactory, Mockito.times(1))
.createBrowserControlsVisibilityDelegate(mTab);
verifyUpdateState(BrowserControlsState.BOTH);
mVisibilityDelegate.set(BrowserControlsState.SHOWN);
verifyUpdateState(BrowserControlsState.SHOWN);
}
@Test
public void testUpdateVisibilityDelegate_TabAlreadyInitializedAndAttached() {
Mockito.when(mTab.isInitialized()).thenReturn(true);
WindowAndroid window = Mockito.mock(WindowAndroid.class);
Mockito.when(mWebContents.getTopLevelNativeWindow()).thenReturn(window);
ChromeActivity activity = Mockito.mock(ChromeActivity.class);
WeakReference<Context> activityRef = new WeakReference<>(activity);
Mockito.when(window.getContext()).thenReturn(activityRef);
initHelper();
Mockito.verify(mDelegateFactory, Mockito.times(1))
.createBrowserControlsVisibilityDelegate(mTab);
verifyUpdateState(BrowserControlsState.BOTH);
mVisibilityDelegate.set(BrowserControlsState.SHOWN);
verifyUpdateState(BrowserControlsState.SHOWN);
}
@Test
public void testUpdateVisibilityDelegate_onAttachmentChanged() {
initHelper();
Mockito.verify(mDelegateFactory, Mockito.never())
.createBrowserControlsVisibilityDelegate(mTab);
mRegisteredTabObserver.onActivityAttachmentChanged(mTab, null);
Mockito.verify(mDelegateFactory, Mockito.never())
.createBrowserControlsVisibilityDelegate(mTab);
WindowAndroid window = Mockito.mock(WindowAndroid.class);
mRegisteredTabObserver.onActivityAttachmentChanged(mTab, window);
Mockito.verify(mDelegateFactory, Mockito.times(1))
.createBrowserControlsVisibilityDelegate(mTab);
verifyUpdateState(BrowserControlsState.BOTH);
mVisibilityDelegate.set(BrowserControlsState.SHOWN);
verifyUpdateState(BrowserControlsState.SHOWN);
}
@Test
public void testUpdateVisibilityDelegate_ChangeDelegates() {
initHelper();
Mockito.verify(mDelegateFactory, Mockito.never())
.createBrowserControlsVisibilityDelegate(mTab);
mRegisteredTabObserver.onInitialized(mTab, null);
Mockito.verify(mDelegateFactory).createBrowserControlsVisibilityDelegate(mTab);
Mockito.verifyNoMoreInteractions(mDelegateFactory);
verifyUpdateState(BrowserControlsState.BOTH);
mVisibilityDelegate.set(BrowserControlsState.HIDDEN);
verifyUpdateState(BrowserControlsState.HIDDEN, false);
TabDelegateFactory newDelegateFactory = Mockito.mock(TabDelegateFactory.class);
TestVisibilityDelegate newVisibilityDelegate = new TestVisibilityDelegate();
Mockito.when(mTab.getDelegateFactory()).thenReturn(newDelegateFactory);
Mockito.when(newDelegateFactory.createBrowserControlsVisibilityDelegate(Mockito.any()))
.thenReturn(newVisibilityDelegate);
WindowAndroid window = Mockito.mock(WindowAndroid.class);
mRegisteredTabObserver.onActivityAttachmentChanged(mTab, window);
Mockito.verify(newDelegateFactory).createBrowserControlsVisibilityDelegate(mTab);
verifyUpdateState(BrowserControlsState.BOTH);
mVisibilityDelegate.set(BrowserControlsState.SHOWN);
Mockito.verify(mJniMock, Mockito.never())
.updateState(
Mockito.anyLong(),
Mockito.any(),
Mockito.any(),
Mockito.anyInt(),
Mockito.anyInt(),
Mockito.anyBoolean(),
Mockito.any());
}
@Test
public void testWebContentsSwap() {
initHelper();
Mockito.verify(mDelegateFactory, Mockito.never())
.createBrowserControlsVisibilityDelegate(mTab);
mRegisteredTabObserver.onInitialized(mTab, null);
Mockito.verify(mDelegateFactory).createBrowserControlsVisibilityDelegate(mTab);
Mockito.verifyNoMoreInteractions(mDelegateFactory);
verifyUpdateState(BrowserControlsState.BOTH);
mRegisteredTabObserver.onWebContentsSwapped(mTab, true, true);
verifyUpdateState(BrowserControlsState.BOTH);
}
@Test
public void testWebContentsSwap_whenShown() {
initHelper();
Mockito.verify(mDelegateFactory, Mockito.never())
.createBrowserControlsVisibilityDelegate(mTab);
mRegisteredTabObserver.onInitialized(mTab, null);
Mockito.verify(mDelegateFactory).createBrowserControlsVisibilityDelegate(mTab);
Mockito.verifyNoMoreInteractions(mDelegateFactory);
verifyUpdateState(BrowserControlsState.BOTH);
mVisibilityDelegate.set(BrowserControlsState.SHOWN);
verifyUpdateState(BrowserControlsState.SHOWN);
mRegisteredTabObserver.onWebContentsSwapped(mTab, true, true);
verifyUpdateState(BrowserControlsState.SHOWN, BrowserControlsState.SHOWN, false);
}
private void verifyUpdateState(@BrowserControlsState int constraints) {
verifyUpdateState(constraints, BrowserControlsState.BOTH, true);
}
private void verifyUpdateState(@BrowserControlsState int constraints, boolean animate) {
verifyUpdateState(constraints, BrowserControlsState.BOTH, animate);
}
private void verifyUpdateState(
@BrowserControlsState int constraints,
@BrowserControlsState int current,
boolean animate) {
Mockito.verify(mJniMock)
.updateState(
Mockito.anyLong(),
Mockito.same(mHelper),
Mockito.same(mWebContents),
Mockito.eq(constraints),
Mockito.eq(current),
Mockito.eq(animate),
Mockito.any());
Mockito.clearInvocations(mJniMock);
}
private static class TestVisibilityDelegate extends BrowserControlsVisibilityDelegate {
public TestVisibilityDelegate() {
super(BrowserControlsState.BOTH);
}
}
}