chromium/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/ActionChipsViewUnitTest.java

// Copyright 2023 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.omnibox.suggestions.base;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;

import android.view.KeyEvent;
import android.view.View;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import org.chromium.base.ContextUtils;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.omnibox.suggestions.RecyclerViewSelectionController;

/** Tests for {@link ActionChipsView}. */
@RunWith(BaseRobolectricTestRunner.class)
public class ActionChipsViewUnitTest {
    public @Rule MockitoRule mMockitoRule = MockitoJUnit.rule();
    private @Mock RecyclerViewSelectionController mController;
    private @Mock View mChild;
    private @Spy ActionChipsView mView = new ActionChipsView(ContextUtils.getApplicationContext());

    private void installAdapter() {
        mView.setSelectionControllerForTesting(mController);
        clearInvocations(mController);
        clearInvocations(mView);
    }

    @Test
    public void keyDispatch_tabSelectsNextItem() {
        installAdapter();

        var event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_TAB);

        doReturn(true).when(mController).selectNextItem();
        assertTrue(event.dispatch(mView));
        verify(mController, times(1)).selectNextItem();
        verifyNoMoreInteractions(mController);
        clearInvocations(mController);

        doReturn(false).when(mController).selectNextItem();
        assertFalse(event.dispatch(mView));
        verify(mController, times(1)).selectNextItem();
        verifyNoMoreInteractions(mController);
    }

    @Test
    public void keyDispatch_shiftTabSelectsPreviousItem() {
        installAdapter();

        var event =
                new KeyEvent(
                        0,
                        0,
                        KeyEvent.ACTION_DOWN,
                        KeyEvent.KEYCODE_TAB,
                        0,
                        KeyEvent.META_SHIFT_ON);

        doReturn(true).when(mController).selectPreviousItem();
        assertTrue(event.dispatch(mView));
        verify(mController, times(1)).selectPreviousItem();
        verifyNoMoreInteractions(mController);

        clearInvocations(mController);

        doReturn(false).when(mController).selectPreviousItem();
        assertFalse(event.dispatch(mView));
        verify(mController, times(1)).selectPreviousItem();
        verifyNoMoreInteractions(mController);
    }

    @Test
    public void keyDispatch_enterKeyPassedThroughWhenNoChipsSelected() {
        installAdapter();

        var event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
        assertFalse(event.dispatch(mView));

        verify(mView, times(1)).onKeyDown(event.getKeyCode(), event);
        verify(mView, times(1)).superOnKeyDown(event.getKeyCode(), event);
        verifyNoMoreInteractions(mView);

        verify(mController, times(1)).getSelectedView();
        verifyNoMoreInteractions(mController);
    }

    @Test
    public void keyDispatch_enterKeyAcceptsSelectedChip() {
        installAdapter();

        doReturn(mChild).when(mController).getSelectedView();
        doReturn(true).when(mChild).performClick();
        clearInvocations(mView);

        var event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
        assertTrue(event.dispatch(mView));

        verify(mChild, times(1)).performClick();
        verify(mView, times(1)).onKeyDown(event.getKeyCode(), event);
        verifyNoMoreInteractions(mView);

        verify(mController, times(1)).getSelectedView();
        verifyNoMoreInteractions(mController);
    }

    @Test
    public void keyDispatch_unhandledKeysArePassedToSuper() {
        installAdapter();

        var event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_T);
        assertFalse(event.dispatch(mView));

        verify(mView, times(1)).onKeyDown(KeyEvent.KEYCODE_T, event);
        verify(mView, times(1)).superOnKeyDown(KeyEvent.KEYCODE_T, event);
        verifyNoMoreInteractions(mView);

        verifyNoMoreInteractions(mController);
    }

    @Test
    public void selection_doesNothingWhenNoAdapter() {
        mView.setSelected(true);
        verifyNoMoreInteractions(mController);

        mView.setSelected(false);
        verifyNoMoreInteractions(mController);
    }

    @Test
    public void selection_resetsCarouselSelectionWhenSelected() {
        installAdapter();

        mView.setSelected(true);
        verify(mController, times(1)).resetSelection();
        verifyNoMoreInteractions(mController);
    }

    @Test
    public void selection_resetsCarouselSelectionWhenDeselected() {
        installAdapter();

        mView.setSelected(false);
        verify(mController, times(1)).resetSelection();
        verifyNoMoreInteractions(mController);
    }
}