chromium/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTest.java

// Copyright 2016 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.contextualsearch;

import androidx.test.filters.SmallTest;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;

import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.profiles.ProfileProvider;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.ui.resources.dynamics.DynamicResourceLoader;

/** Mock touch events with Contextual Search to test behavior of its panel and manager. */
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@Batch(Batch.PER_CLASS)
public class ContextualSearchTest extends ContextualSearchInstrumentationBase {
    @Override
    @Before
    public void setUp() throws Exception {
        super.setUp();

        // TODO(donnd): Fix and move this into ContextualSearchInstrumentationBase.
        // Likely cause of the problem is JniMocker.
        MockitoAnnotations.initMocks(this);
        mocker.mock(ContextualSearchManagerJni.TEST_HOOKS, mContextualSearchManagerJniMock);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    ChromeActivity activity = (ChromeActivity) mManager.getActivity();
                    mPanel =
                            new ContextualSearchPanelWrapper(
                                    activity,
                                    activity.getCompositorViewHolderForTesting().getLayoutManager(),
                                    mPanelManager,
                                    ProfileProvider.getOrCreateProfile(
                                            activity.getProfileProviderSupplier().get(), false));
                    mPanel.setManagementDelegate(mContextualSearchManager);
                    mContextualSearchManager.setContextualSearchPanel(mPanel);
                    mPanelManager.setDynamicResourceLoader(new DynamicResourceLoader(0, null));
                });
    }

    /** Tests that a Long-press gesture followed by tapping empty space closes the panel. */
    @Test
    @SmallTest
    @Feature({"ContextualSearch"})
    @Restriction(Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE)
    public void testLongpressFollowedByNonTextTap() {
        Assert.assertEquals(0, mPanelManager.getRequestPanelShowCount());

        // Fake a selection event.
        mockLongpressText("text");
        // Generate the surrounding-text-available callback.
        // Surrounding text is gathered for longpress due to icing integration.
        generateTextSurroundingSelectionAvailable();

        Assert.assertEquals(1, mPanelManager.getRequestPanelShowCount());
        Assert.assertEquals(0, mPanelManager.getPanelHideCount());
        Assert.assertEquals(
                mContextualSearchManager.getSelectionController().getSelectedText(), "text");

        // Fake tap on non-text.
        mockTapEmptySpace();

        Assert.assertEquals(1, mPanelManager.getRequestPanelShowCount());
        Assert.assertEquals(1, mPanelManager.getPanelHideCount());
        Assert.assertNull(mContextualSearchManager.getSelectionController().getSelectedText());
    }

    /** Tests that a Tap gesture followed by tapping empty space closes the panel. */
    @Test
    @SmallTest
    @Feature({"ContextualSearch"})
    @Restriction(Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE)
    public void testTextTapFollowedByNonTextTap() {
        Assert.assertEquals(0, mPanelManager.getRequestPanelShowCount());

        // Fake a Tap event.
        mockTapText("text");
        // Generate the surrounding-text-available callback.
        generateTextSurroundingSelectionAvailable();
        // Right now the tap-processing sequence will stall at selectWordAroundCaret, so we need
        // to prod it forward by generating an ACK:
        generateSelectWordAroundCaretAck();
        Assert.assertEquals(1, mPanelManager.getRequestPanelShowCount());
        Assert.assertEquals(0, mPanelManager.getPanelHideCount());
    }

    /**
     * Tests that a Tap gesture processing is robust even when the selection somehow gets cleared
     * during that process. This tests a failure-case found in crbug.com/728644.
     */
    @Test
    @SmallTest
    @Feature({"ContextualSearch"})
    @Restriction(Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE)
    public void testTapProcessIsRobustWhenSelectionGetsCleared() {
        Assert.assertEquals(0, mPanelManager.getRequestPanelShowCount());

        // Fake a Tap event.
        mockTapText("text");
        // Generate the surrounding-text-available callback.
        generateTextSurroundingSelectionAvailable();

        // Now clear the selection!
        mContextualSearchManager.getSelectionController().clearSelection();

        // Continue processing the Tap by acknowledging the SelectWordAroundCaret has selected the
        // word.  However we just simulated a condition that clears the selection above, so we're
        // testing for robustness in completion of the processing even when there's no selection.
        generateSelectWordAroundCaretAck();
        Assert.assertEquals(0, mPanelManager.getRequestPanelShowCount());
        Assert.assertEquals(0, mPanelManager.getPanelHideCount());
    }
}