RichInputConnectionAndTextRangeTests.java revision 494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3
12f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard/*
22f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard * Copyright (C) 2012 The Android Open Source Project
32f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard *
42f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard * Licensed under the Apache License, Version 2.0 (the "License");
52f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard * you may not use this file except in compliance with the License.
62f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard * You may obtain a copy of the License at
72f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard *
82f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard *      http://www.apache.org/licenses/LICENSE-2.0
92f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard *
102f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard * Unless required by applicable law or agreed to in writing, software
112f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard * distributed under the License is distributed on an "AS IS" BASIS,
122f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard * See the License for the specific language governing permissions and
142f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard * limitations under the License.
152f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard */
162f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
172f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardpackage com.android.inputmethod.latin;
182f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
19494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaokaimport android.content.res.Resources;
202f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport android.inputmethodservice.InputMethodService;
212f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport android.os.Parcel;
222f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport android.test.AndroidTestCase;
232f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport android.test.MoreAsserts;
242f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport android.test.suitebuilder.annotation.SmallTest;
252f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport android.text.SpannableString;
262f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport android.text.TextUtils;
272f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport android.text.style.SuggestionSpan;
282f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport android.view.inputmethod.ExtractedText;
292f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport android.view.inputmethod.ExtractedTextRequest;
302f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport android.view.inputmethod.InputConnection;
312f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport android.view.inputmethod.InputConnectionWrapper;
322f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
33494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaokaimport com.android.inputmethod.latin.settings.SpacingAndPunctuations;
34494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.RunInLocale;
35494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.TextRange;
36494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka
372f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport java.util.Locale;
382f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
392f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard@SmallTest
402f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardpublic class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
412f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
422f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    // The following is meant to be a reasonable default for
432f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    // the "word_separators" resource.
44494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka    private SpacingAndPunctuations mSpacingAndPunctuations;
452f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
462f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    @Override
472f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    protected void setUp() throws Exception {
482f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        super.setUp();
49494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() {
50494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka            @Override
51494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka            protected SpacingAndPunctuations job(final Resources res) {
52494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka                return new SpacingAndPunctuations(res);
53494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka            }
54494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        };
55494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        final Resources res = getContext().getResources();
56494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        mSpacingAndPunctuations = job.runInLocale(res, Locale.ENGLISH);
572f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
582f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
592f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    private class MockConnection extends InputConnectionWrapper {
602f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final CharSequence mTextBefore;
612f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final CharSequence mTextAfter;
622f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final ExtractedText mExtractedText;
632f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
642f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public MockConnection(final CharSequence text, final int cursorPosition) {
652f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            super(null, false);
662f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            // Interaction of spans with Parcels is completely non-trivial, but in the actual case
672f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            // the CharSequences do go through Parcels because they go through IPC. There
682f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            // are some significant differences between the behavior of Spanned objects that
692f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            // have and that have not gone through parceling, so it's much easier to simulate
702f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            // the environment with Parcels than try to emulate things by hand.
712f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            final Parcel p = Parcel.obtain();
722f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            TextUtils.writeToParcel(text.subSequence(0, cursorPosition), p, 0 /* flags */);
732f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            TextUtils.writeToParcel(text.subSequence(cursorPosition, text.length()), p,
742f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                    0 /* flags */);
752f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            final byte[] marshalled = p.marshall();
762f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            p.unmarshall(marshalled, 0, marshalled.length);
772f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            p.setDataPosition(0);
782f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            mTextBefore = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
792f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            mTextAfter = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
802f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            mExtractedText = null;
812f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            p.recycle();
822f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
832f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
842f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public MockConnection(String textBefore, String textAfter, ExtractedText extractedText) {
852f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            super(null, false);
862f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            mTextBefore = textBefore;
872f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            mTextAfter = textAfter;
882f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            mExtractedText = extractedText;
892f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
902f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
912f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        /* (non-Javadoc)
922f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         * @see android.view.inputmethod.InputConnectionWrapper#getTextBeforeCursor(int, int)
932f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         */
942f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
952f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public CharSequence getTextBeforeCursor(int n, int flags) {
962f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            return mTextBefore;
972f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
982f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
992f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        /* (non-Javadoc)
1002f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         * @see android.view.inputmethod.InputConnectionWrapper#getTextAfterCursor(int, int)
1012f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         */
1022f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
1032f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public CharSequence getTextAfterCursor(int n, int flags) {
1042f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            return mTextAfter;
1052f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1062f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1072f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        /* (non-Javadoc)
1082f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         * @see android.view.inputmethod.InputConnectionWrapper#getExtractedText(
1092f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         *         ExtractedTextRequest, int)
1102f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         */
1112f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
1122f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
1132f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            return mExtractedText;
1142f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1152f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1162f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
1172f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public boolean beginBatchEdit() {
1182f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            return true;
1192f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1202f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1212f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
1222f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public boolean endBatchEdit() {
1232f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            return true;
1242f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1252f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1262f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
1272f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public boolean finishComposingText() {
1282f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            return true;
1292f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1302f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
1312f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1322f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    private class MockInputMethodService extends InputMethodService {
1332f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        InputConnection mInputConnection;
1342f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public void setInputConnection(final InputConnection inputConnection) {
1352f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            mInputConnection = inputConnection;
1362f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1372f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
1382f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public InputConnection getCurrentInputConnection() {
1392f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            return mInputConnection;
1402f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1412f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
1422f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1432f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    /************************** Tests ************************/
1442f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1452f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    /**
1462f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard     * Test for getting previous word (for bigram suggestions)
1472f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard     */
1482f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    public void testGetPreviousWord() {
1492f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // If one of the following cases breaks, the bigram suggestions won't work.
150494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        assertEquals(RichInputConnection.getNthPreviousWord(
151494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka                "abc def", mSpacingAndPunctuations, 2), "abc");
152494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        assertNull(RichInputConnection.getNthPreviousWord(
153494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka                "abc", mSpacingAndPunctuations, 2));
154494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        assertNull(RichInputConnection.getNthPreviousWord(
155494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka                "abc. def", mSpacingAndPunctuations, 2));
1562f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1572f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // The following tests reflect the current behavior of the function
1582f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // RichInputConnection#getNthPreviousWord.
1592f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // TODO: However at this time, the code does never go
1602f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // into such a path, so it should be safe to change the behavior of
1612f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // this function if needed - especially since it does not seem very
1622f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // logical. These tests are just there to catch any unintentional
1632f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // changes in the behavior of the RichInputConnection#getPreviousWord method.
164494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        assertEquals(RichInputConnection.getNthPreviousWord(
165494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka                "abc def ", mSpacingAndPunctuations, 2), "abc");
166494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        assertEquals(RichInputConnection.getNthPreviousWord(
167494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka                "abc def.", mSpacingAndPunctuations, 2), "abc");
168494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        assertEquals(RichInputConnection.getNthPreviousWord(
169494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka                "abc def .", mSpacingAndPunctuations, 2), "def");
170494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        assertNull(RichInputConnection.getNthPreviousWord(
171494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka                "abc ", mSpacingAndPunctuations, 2));
172494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka
173494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        assertEquals(RichInputConnection.getNthPreviousWord(
174494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka                "abc def", mSpacingAndPunctuations, 1), "def");
175494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        assertEquals(RichInputConnection.getNthPreviousWord(
176494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka                "abc def ", mSpacingAndPunctuations, 1), "def");
177494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        assertNull(RichInputConnection.getNthPreviousWord(
178494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka                "abc def.", mSpacingAndPunctuations, 1));
179494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        assertNull(RichInputConnection.getNthPreviousWord(
180494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka                "abc def .", mSpacingAndPunctuations, 1));
1812f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
1822f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1832f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    /**
1842f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard     * Test logic in getting the word range at the cursor.
1852f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard     */
1862f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    public void testGetWordRangeAtCursor() {
1872f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ExtractedText et = new ExtractedText();
1882f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final MockInputMethodService mockInputMethodService = new MockInputMethodService();
1892f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
1902f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection("word wo", "rd", et));
1912f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        et.startOffset = 0;
1922f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        et.selectionStart = 7;
193675bcf191c3cdb5ba5af70efb9357ffceb389c2eJean Chalard        TextRange r;
1942f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1952f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.beginBatchEdit();
1962f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // basic case
1972f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        r = ic.getWordRangeAtCursor(" ", 0);
1982f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertTrue(TextUtils.equals("word", r.mWord));
1992f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2002f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // more than one word
2012f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        r = ic.getWordRangeAtCursor(" ", 1);
2022f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertTrue(TextUtils.equals("word word", r.mWord));
2032f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.endBatchEdit();
2042f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2052f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // tab character instead of space
2062f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection("one\tword\two", "rd", et));
2072f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.beginBatchEdit();
2082f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        r = ic.getWordRangeAtCursor("\t", 1);
2092f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.endBatchEdit();
2102f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertTrue(TextUtils.equals("word\tword", r.mWord));
2112f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2122f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // only one word doesn't go too far
2132f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection("one\tword\two", "rd", et));
2142f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.beginBatchEdit();
2152f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        r = ic.getWordRangeAtCursor("\t", 1);
2162f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.endBatchEdit();
2172f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertTrue(TextUtils.equals("word\tword", r.mWord));
2182f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2192f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // tab or space
2202f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection("one word\two", "rd", et));
2212f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.beginBatchEdit();
2222f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        r = ic.getWordRangeAtCursor(" \t", 1);
2232f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.endBatchEdit();
2242f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertTrue(TextUtils.equals("word\tword", r.mWord));
2252f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2262f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // tab or space multiword
2272f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection("one word\two", "rd", et));
2282f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.beginBatchEdit();
2292f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        r = ic.getWordRangeAtCursor(" \t", 2);
2302f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.endBatchEdit();
2312f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertTrue(TextUtils.equals("one word\tword", r.mWord));
2322f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2332f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // splitting on supplementary character
2342f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final String supplementaryChar = "\uD840\uDC8A";
2352f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(
2362f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                new MockConnection("one word" + supplementaryChar + "wo", "rd", et));
2372f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.beginBatchEdit();
2382f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        r = ic.getWordRangeAtCursor(supplementaryChar, 0);
2392f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.endBatchEdit();
2402f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertTrue(TextUtils.equals("word", r.mWord));
2412f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
2422f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2432f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    /**
2442f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard     * Test logic in getting the word range at the cursor.
2452f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard     */
2462f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    public void testGetSuggestionSpansAtWord() {
2472f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        helpTestGetSuggestionSpansAtWord(10);
2482f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        helpTestGetSuggestionSpansAtWord(12);
2492f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        helpTestGetSuggestionSpansAtWord(15);
2502f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        helpTestGetSuggestionSpansAtWord(16);
2512f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
2522f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2532f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    private void helpTestGetSuggestionSpansAtWord(final int cursorPos) {
2542f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final MockInputMethodService mockInputMethodService = new MockInputMethodService();
2552f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
2562f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2572f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final String[] SUGGESTIONS1 = { "swing", "strong" };
2582f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final String[] SUGGESTIONS2 = { "storing", "strung" };
2592f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2602f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test the usual case.
2612f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        SpannableString text = new SpannableString("This is a string for test");
2622f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
2632f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
2642f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
265675bcf191c3cdb5ba5af70efb9357ffceb389c2eJean Chalard        TextRange r;
2662f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        SuggestionSpan[] suggestions;
2672f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2682f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        r = ic.getWordRangeAtCursor(" ", 0);
2692f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
2702f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 1);
2712f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
2722f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2732f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test the case with 2 suggestion spans in the same place.
2742f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
2752f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
2762f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
2772f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
2782f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
2792f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
2802f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        r = ic.getWordRangeAtCursor(" ", 0);
2812f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
2822f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 2);
2832f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
2842f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[1].getSuggestions(), SUGGESTIONS2);
2852f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2862f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test a case with overlapping spans, 2nd extending past the start of the word
2872f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
2882f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
2892f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
2902f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
2912f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                5 /* start */, 16 /* end */, 0 /* flags */);
2922f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
2932f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        r = ic.getWordRangeAtCursor(" ", 0);
2942f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
2952f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 1);
2962f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
2972f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2982f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test a case with overlapping spans, 2nd extending past the end of the word
2992f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
3002f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3012f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3022f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
3032f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 20 /* end */, 0 /* flags */);
3042f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
3052f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        r = ic.getWordRangeAtCursor(" ", 0);
3062f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3072f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 1);
3082f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
3092f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
3102f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test a case with overlapping spans, 2nd extending past both ends of the word
3112f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
3122f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3132f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3142f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
3152f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                5 /* start */, 20 /* end */, 0 /* flags */);
3162f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
3172f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        r = ic.getWordRangeAtCursor(" ", 0);
3182f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3192f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 1);
3202f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
3212f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
3222f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test a case with overlapping spans, none right on the word
3232f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
3242f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3252f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                5 /* start */, 16 /* end */, 0 /* flags */);
3262f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
3272f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                5 /* start */, 20 /* end */, 0 /* flags */);
3282f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
3292f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        r = ic.getWordRangeAtCursor(" ", 0);
3302f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3312f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 0);
3322f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
3332f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard}
334