chromium/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionControllerTest.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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import android.app.Activity;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;

import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Feature;
import org.chromium.ui.touch_selection.SelectionEventType;

/**
 * Tests a few methods of the ContextualSearchSelectionController. <ul>
 * <li>That the ContextualSearchSelectionController#handleSelectionmethod supports usages
 * from Smart Text Selection and from normal user driven selection.</li>
 * <li>That the ContextualSearchSelectionController#isSelectionPartOfUrl handles all the different
 * URL cases.</li>
 * </ul>
 */
@RunWith(BaseRobolectricTestRunner.class)
@Config(
        shadows = {
            ContextualSearchSelectionControllerTest.ShadowContextualSearchSelectionController.class
        })
public final class ContextualSearchSelectionControllerTest {
    private static final String USER_SELECTION = "user selection";

    /** Stores the selection set by ContextualSearchSelectionController#handleSelection. */
    private static String sSelectionSetByHandleSelection;

    /** The instance under test, which is also shadowed. */
    private ContextualSearchSelectionController mSelectionControllerUnderTest;

    @Before
    public void setUp() throws Exception {
        Activity activity = Robolectric.buildActivity(Activity.class).setup().get();
        mSelectionControllerUnderTest =
                new ContextualSearchSelectionController(activity, null, null);
        mSelectionControllerUnderTest.setSelectedText(USER_SELECTION);
        sSelectionSetByHandleSelection = null;
    }

    /**
     * Shadows the class that we are testing: ContextualSearchSelectionController.
     * This allows us to stub out some methods without needing to make mocks or stubs for the things
     * those methods call.
     */
    @Implements(ContextualSearchSelectionController.class)
    public static class ShadowContextualSearchSelectionController {
        public ShadowContextualSearchSelectionController() {}

        /**
         * Implements #handleSelection by remembering the selection param, which can later be
         * retrieved by calling #getSelectionSetByHandleSelection
         * @param selection The text that was selected.
         * @param type The type of selection made by the user.
         */
        @Implementation
        protected void handleSelection(
                String selection, @ContextualSearchSelectionController.SelectionType int type) {
            sSelectionSetByHandleSelection = selection;
        }

        /** Returns the selection that was set by the call to #handleSelection. */
        static String getSelectionSetByHandleSelection() {
            return sSelectionSetByHandleSelection;
        }
    }

    /**
     * Returns the string that the selection controller has sent to the Contextual Search Manager
     * in #handleSelection.
     */
    private String getSelectionSetByHandleSelection() {
        return ShadowContextualSearchSelectionController.getSelectionSetByHandleSelection();
    }

    // ============================================================================================
    // Selection manipulation with and without Smart Text Selection
    // ============================================================================================

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testUserDrivenSelectionSequence() {
        mSelectionControllerUnderTest.handleSelectionEvent(
                SelectionEventType.SELECTION_HANDLE_DRAG_STARTED, 0f, 0f);
        final String unexpectedSelectionSent =
                "User flow for ContextualSearchSelectionController#handleSelectionEvent sent a "
                        + "selection to the Manager that was unexpected.";
        Assert.assertNull(unexpectedSelectionSent, getSelectionSetByHandleSelection());
        mSelectionControllerUnderTest.handleSelectionEvent(
                SelectionEventType.SELECTION_HANDLES_MOVED, 0f, 0f);
        Assert.assertNull(unexpectedSelectionSent, getSelectionSetByHandleSelection());
        mSelectionControllerUnderTest.handleSelectionEvent(
                SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED, 0f, 0f);
        Assert.assertEquals(
                "User flow for ContextualSearchSelectionController#handleSelectionEvent "
                        + "sent an unexpected selection to the Manager. Maybe something broke "
                        + "longpress selection modification for Contextual Search.",
                USER_SELECTION,
                getSelectionSetByHandleSelection());
    }

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testSmartTextSelectionIntegration() {
        // When Smart Text Selection is active a SELECTION_HANDLES_MOVED event is sent without a
        // SELECTION_HANDLE_DRAG_STARTED event.
        mSelectionControllerUnderTest.handleSelectionEvent(
                SelectionEventType.SELECTION_HANDLES_MOVED, 0f, 0f);
        // Make sure we did not establish any selection.
        Assert.assertNull(
                "Smart Text Selection interaction with Contextual Search "
                        + "through the ContextualSearchSelectionController#handleSelectionEvent "
                        + "sent a selection to the Manager that was unexpected. Smart Text "
                        + "Selection with the intelligent Long-press gesture may be broken.",
                getSelectionSetByHandleSelection());
    }

    // ============================================================================================
    // isSelectionPartOfUrl test cases
    // ============================================================================================

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testBasicUrlExtraction() {
        String testSentence = "A sentence containing a http://www.example.com valid url";

        // Select "com".
        assertEquals("com", testSentence.subSequence(43, 46));
        assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 43, 46));

        // Select "http".
        assertEquals("http", testSentence.subSequence(24, 28));
        assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 24, 28));

        // Select "www".
        assertEquals("www", testSentence.subSequence(31, 34));
        assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 31, 34));

        // Select "example".
        assertEquals("example", testSentence.subSequence(35, 42));
        assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 35, 42));

        // Select "containing".
        assertEquals("containing", testSentence.subSequence(11, 21));
        assertFalse(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 11, 21));

        // Select "url".
        assertEquals("url", testSentence.subSequence(53, 56));
        assertFalse(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 53, 56));
    }

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testUrlWithNoScheme() {
        String testSentence = "This is a sentence about example.com/foo#bar.";

        // Select "foo".
        assertEquals("foo", testSentence.subSequence(37, 40));
        assertFalse(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 37, 40));
    }

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testUrlWithAnchor() {
        String testSentence = "This is a sentence about http://example.com/foo#bar.";

        // Select "foo".
        assertEquals("foo", testSentence.subSequence(44, 47));
        assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 44, 47));

        // Select "bar".
        assertEquals("bar", testSentence.subSequence(48, 51));
        assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 48, 51));

        // Select "This".
        assertEquals("This", testSentence.subSequence(0, 4));
        assertFalse(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 0, 4));
    }

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testUrlSurroundedByParens() {
        String testSentence = "This is another sentence (http://example.com).";

        // Select "com".
        assertEquals("com", testSentence.subSequence(41, 44));
        assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 41, 44));

        // Select "(".
        assertEquals("(", testSentence.subSequence(25, 26));
        assertFalse(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 25, 26));
    }

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testUrlWithHttpsSchema() {
        String testSentence = "https://supersecure.net.";

        // Select "supersecure".
        assertEquals("supersecure", testSentence.subSequence(8, 19));
        assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 8, 19));
    }

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testUrlWithFileSchema() {
        String testSentence = "file://some_text_file.txt";

        // Select "text".
        assertEquals("text", testSentence.subSequence(12, 16));
        assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 12, 16));
    }

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testUrlWithFtpSchema() {
        String testSentence = "ftp://some_text_file.txt";

        // Select "text".
        assertEquals("text", testSentence.subSequence(11, 15));
        assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 11, 15));
    }

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testUrlWithSshSchema() {
        String testSentence = "ssh://some_text_file.txt";

        // Select "text".
        assertEquals("text", testSentence.subSequence(11, 15));
        assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 11, 15));
    }

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testUrlWithPortAndQuery() {
        String testSentence = "http://website.com:8080/html?query";

        // Select "8080".
        assertEquals("8080", testSentence.subSequence(19, 23));
        assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 19, 23));

        // Select "query".
        assertEquals("query", testSentence.subSequence(29, 34));
        assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 29, 34));
    }

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testIpAddress() {
        String testSentence = "127.0.0.1";

        // Select "0".
        assertEquals("0", testSentence.subSequence(4, 5));
        assertFalse(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 4, 5));
    }

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testEmailAddress() {
        String testSentence = "Please email me at [email protected] or call...";

        // Select "username".
        assertEquals("username", testSentence.subSequence(19, 27));
        assertFalse(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 19, 27));
    }

    @Test
    @Feature({"ContextualSearchSelectionController"})
    public void testUrlLikeSyntax() {
        String testSentence = "Example sentence with no URLs, but.weird.syntax";

        // Select "syntax".
        assertEquals("weird", testSentence.subSequence(35, 40));
        assertFalse(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 35, 40));
    }
}