chromium/content/public/android/junit/src/org/chromium/content/browser/input/TextInputStateTest.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.content.browser.input;

import static org.junit.Assert.assertEquals;

import android.text.TextUtils;

import org.junit.Test;
import org.junit.runner.RunWith;

import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Feature;

/** Unit tests for {@TextInputState}. */
@RunWith(BaseRobolectricTestRunner.class)
public class TextInputStateTest {
    @Test
    @Feature({"TextInput"})
    public void testEmptySelection() {
        TextInputState state =
                new TextInputState("hello", new Range(3, 3), new Range(-1, -1), false, true);
        assertEquals("lo", state.getTextAfterSelection(Integer.MAX_VALUE));
        assertEquals("lo", state.getTextAfterSelection(3));
        assertEquals("lo", state.getTextAfterSelection(2));
        assertEquals("", state.getTextAfterSelection(0));
        assertEquals("", state.getTextAfterSelection(-1));
        assertEquals("hel", state.getTextBeforeSelection(Integer.MAX_VALUE));
        assertEquals("hel", state.getTextBeforeSelection(3));
        assertEquals("el", state.getTextBeforeSelection(2));
        assertEquals("", state.getTextBeforeSelection(0));
        assertEquals("", state.getTextBeforeSelection(-1));
        assertEquals(null, state.getSelectedText());
    }

    @Test
    @Feature({"TextInput"})
    public void testNonEmptySelection() {
        TextInputState state =
                new TextInputState("hello", new Range(3, 4), new Range(3, 4), false, true);
        assertEquals("hel", state.getTextBeforeSelection(Integer.MAX_VALUE));
        assertEquals("hel", state.getTextBeforeSelection(4));
        assertEquals("hel", state.getTextBeforeSelection(3));
        assertEquals("", state.getTextBeforeSelection(0));
        assertEquals("", state.getTextBeforeSelection(-1));
        assertEquals("o", state.getTextAfterSelection(Integer.MAX_VALUE));
        assertEquals("o", state.getTextAfterSelection(2));
        assertEquals("o", state.getTextAfterSelection(1));
        assertEquals("", state.getTextAfterSelection(0));
        assertEquals("", state.getTextAfterSelection(-1));
        assertEquals("l", state.getSelectedText());
    }

    @Test
    @Feature({"TextInput"})
    public void textGetSurroundingText() {
        TextInputState stateEmptySelection =
                new TextInputState("hello", new Range(3, 3), new Range(-1, -1), false, true);
        for (int before = -1; before < 6; ++before) {
            for (int after = -1; after < 6; ++after) {
                int beforeLength = before == 5 ? before : Integer.MAX_VALUE;
                int afterLength = after == 5 ? after : Integer.MAX_VALUE;
                verifySurroundingText(
                        getSurroundingTextFrameworkDefaultVersion(
                                stateEmptySelection, beforeLength, afterLength),
                        stateEmptySelection.getSurroundingTextInternal(beforeLength, afterLength));
            }
        }

        TextInputState stateNonEmptySelection =
                new TextInputState("hello", new Range(3, 4), new Range(3, 4), false, true);
        for (int before = -1; before < 6; ++before) {
            for (int after = -1; after < 6; ++after) {
                int beforeLength = before == 5 ? before : Integer.MAX_VALUE;
                int afterLength = after == 5 ? after : Integer.MAX_VALUE;
                verifySurroundingText(
                        getSurroundingTextFrameworkDefaultVersion(
                                stateNonEmptySelection, beforeLength, afterLength),
                        stateNonEmptySelection.getSurroundingTextInternal(
                                beforeLength, afterLength));
            }
        }
    }

    void verifySurroundingText(
            TextInputState.SurroundingTextInternal expected,
            TextInputState.SurroundingTextInternal value) {
        assertEquals(expected.mText, value.mText);
        assertEquals(expected.mSelectionStart, value.mSelectionStart);
        assertEquals(expected.mSelectionEnd, value.mSelectionEnd);
    }

    // From Android framework code InputConnection#getSurroundingtext(int, int, int). Our
    // implementation should match the default implementation behavior.
    // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/inputmethod/InputConnection.java;l=320
    private TextInputState.SurroundingTextInternal getSurroundingTextFrameworkDefaultVersion(
            TextInputState inputState, int beforeLength, int afterLength) {
        CharSequence textBeforeCursor = inputState.getTextBeforeSelection(beforeLength);
        if (textBeforeCursor == null) {
            return null;
        }

        CharSequence textAfterCursor = inputState.getTextAfterSelection(afterLength);
        if (textAfterCursor == null) {
            return null;
        }

        CharSequence selectedText = inputState.getSelectedText();
        if (selectedText == null) {
            selectedText = "";
        }
        CharSequence surroundingText =
                TextUtils.concat(textBeforeCursor, selectedText, textAfterCursor);
        return new TextInputState.SurroundingTextInternal(
                surroundingText,
                textBeforeCursor.length(),
                textBeforeCursor.length() + selectedText.length(),
                -1);
    }
}