RichInputConnectionAndTextRangeTests.java revision 914078fd9198aeb3d7ffa034562321d688d588f7
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
331c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagiimport com.android.inputmethod.latin.PrevWordsInfo.WordInfo;
34494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaokaimport com.android.inputmethod.latin.settings.SpacingAndPunctuations;
35bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagiimport com.android.inputmethod.latin.utils.PrevWordsInfoUtils;
36494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.RunInLocale;
37292deb632cbab232334190e68d29184094d6d51bJean Chalardimport com.android.inputmethod.latin.utils.ScriptUtils;
38c93cf1c398fbea8bde4b568dae1fbe2f8d9b4180Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.StringUtils;
39494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.TextRange;
40494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka
412f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardimport java.util.Locale;
422f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
432f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard@SmallTest
442f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalardpublic class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
452f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
462f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    // The following is meant to be a reasonable default for
472f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    // the "word_separators" resource.
48494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka    private SpacingAndPunctuations mSpacingAndPunctuations;
492f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
502f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    @Override
512f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    protected void setUp() throws Exception {
522f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        super.setUp();
53494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() {
54494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka            @Override
55494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka            protected SpacingAndPunctuations job(final Resources res) {
56494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka                return new SpacingAndPunctuations(res);
57494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka            }
58494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        };
59494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        final Resources res = getContext().getResources();
60494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaoka        mSpacingAndPunctuations = job.runInLocale(res, Locale.ENGLISH);
612f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
622f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
632f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    private class MockConnection extends InputConnectionWrapper {
642f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final CharSequence mTextBefore;
652f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final CharSequence mTextAfter;
662f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final ExtractedText mExtractedText;
672f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
682f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public MockConnection(final CharSequence text, final int cursorPosition) {
692f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            super(null, false);
702f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            // Interaction of spans with Parcels is completely non-trivial, but in the actual case
712f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            // the CharSequences do go through Parcels because they go through IPC. There
722f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            // are some significant differences between the behavior of Spanned objects that
732f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            // have and that have not gone through parceling, so it's much easier to simulate
742f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            // the environment with Parcels than try to emulate things by hand.
752f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            final Parcel p = Parcel.obtain();
762f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            TextUtils.writeToParcel(text.subSequence(0, cursorPosition), p, 0 /* flags */);
772f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            TextUtils.writeToParcel(text.subSequence(cursorPosition, text.length()), p,
782f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                    0 /* flags */);
792f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            final byte[] marshalled = p.marshall();
802f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            p.unmarshall(marshalled, 0, marshalled.length);
812f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            p.setDataPosition(0);
822f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            mTextBefore = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
832f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            mTextAfter = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
842f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            mExtractedText = null;
852f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            p.recycle();
862f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
872f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
882f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public MockConnection(String textBefore, String textAfter, ExtractedText extractedText) {
892f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            super(null, false);
902f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            mTextBefore = textBefore;
912f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            mTextAfter = textAfter;
922f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            mExtractedText = extractedText;
932f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
942f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
9572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        public int cursorPos() {
9672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard            return mTextBefore.length();
9772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        }
9872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
992f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        /* (non-Javadoc)
1002f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         * @see android.view.inputmethod.InputConnectionWrapper#getTextBeforeCursor(int, int)
1012f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         */
1022f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
1032f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public CharSequence getTextBeforeCursor(int n, int flags) {
1042f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            return mTextBefore;
1052f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1062f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1072f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        /* (non-Javadoc)
1082f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         * @see android.view.inputmethod.InputConnectionWrapper#getTextAfterCursor(int, int)
1092f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         */
1102f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
1112f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public CharSequence getTextAfterCursor(int n, int flags) {
1122f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            return mTextAfter;
1132f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1142f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1152f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        /* (non-Javadoc)
1162f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         * @see android.view.inputmethod.InputConnectionWrapper#getExtractedText(
1172f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         *         ExtractedTextRequest, int)
1182f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard         */
1192f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
1202f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
1212f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            return mExtractedText;
1222f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1232f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1242f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
1252f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public boolean beginBatchEdit() {
1262f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            return true;
1272f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1282f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1292f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
1302f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public boolean endBatchEdit() {
1312f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            return true;
1322f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1332f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1342f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
1352f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public boolean finishComposingText() {
1362f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard            return true;
1372f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1382f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
1392f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1402f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    private class MockInputMethodService extends InputMethodService {
14172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        private MockConnection mMockConnection;
14272b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        public void setInputConnection(final MockConnection mockConnection) {
14372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard            mMockConnection = mockConnection;
14472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        }
14572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        public int cursorPos() {
14672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard            return mMockConnection.cursorPos();
1472f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1482f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        @Override
1492f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        public InputConnection getCurrentInputConnection() {
15072b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard            return mMockConnection;
1512f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        }
1522f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
1532f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1542f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    /************************** Tests ************************/
1552f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
1562f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    /**
1572f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard     * Test for getting previous word (for bigram suggestions)
1582f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard     */
1592f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    public void testGetPreviousWord() {
1602f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // If one of the following cases breaks, the bigram suggestions won't work.
161bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
162e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                "abc def", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "abc");
163bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
164f2c2657566e882c01c7af189be7f6c2946fddd9fKeisuke Kuroyanagi                "abc", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE);
165bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
166f2c2657566e882c01c7af189be7f6c2946fddd9fKeisuke Kuroyanagi                "abc. def", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE);
16717f326b7458c2bde2569e283a96e703755485328Keisuke Kuroyanagi
168bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertFalse(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
169e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                "abc def", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mIsBeginningOfSentence);
170bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertTrue(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
171e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                "abc", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mIsBeginningOfSentence);
1721c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
1731c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        // For n-gram
174bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
1751c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi                "abc def", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "def");
176bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
1771c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi                "abc def", mSpacingAndPunctuations, 1).mPrevWordsInfo[1].mWord, "abc");
178bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
1791c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi                "abc def", mSpacingAndPunctuations, 2).mPrevWordsInfo[1],
1801c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi                WordInfo.BEGINNING_OF_SENTENCE);
1811c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
1822f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // The following tests reflect the current behavior of the function
1832f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // RichInputConnection#getNthPreviousWord.
1842f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // TODO: However at this time, the code does never go
1852f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // into such a path, so it should be safe to change the behavior of
1862f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // this function if needed - especially since it does not seem very
1872f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // logical. These tests are just there to catch any unintentional
1882f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // changes in the behavior of the RichInputConnection#getPreviousWord method.
189bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
190e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                "abc def ", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "abc");
191bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
192e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                "abc def.", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "abc");
193bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
194e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                "abc def .", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "def");
195bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
196f2c2657566e882c01c7af189be7f6c2946fddd9fKeisuke Kuroyanagi                "abc ", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE);
19717f326b7458c2bde2569e283a96e703755485328Keisuke Kuroyanagi
198bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
199e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                "abc def", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "def");
200bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
201e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                "abc def ", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "def");
202bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
203e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                "abc 'def", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "'def");
204bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
205f2c2657566e882c01c7af189be7f6c2946fddd9fKeisuke Kuroyanagi                "abc def.", mSpacingAndPunctuations, 1), PrevWordsInfo.BEGINNING_OF_SENTENCE);
206bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
207f2c2657566e882c01c7af189be7f6c2946fddd9fKeisuke Kuroyanagi                "abc def .", mSpacingAndPunctuations, 1), PrevWordsInfo.BEGINNING_OF_SENTENCE);
208bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
209f2c2657566e882c01c7af189be7f6c2946fddd9fKeisuke Kuroyanagi                "abc, def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO);
210bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
211f2c2657566e882c01c7af189be7f6c2946fddd9fKeisuke Kuroyanagi                "abc? def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO);
212bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
213f2c2657566e882c01c7af189be7f6c2946fddd9fKeisuke Kuroyanagi                "abc! def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO);
214bb843eb223ce0f8fb1088ed3393a4165123ddb1fKeisuke Kuroyanagi        assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
2158f71fab2ed619e34222a172a5004d7f91b4520a6Keisuke Kuroyanagi                "abc 'def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO);
2162f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
2172f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2182f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    public void testGetWordRangeAtCursor() {
219914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        /**
220914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard         * Test logic in getting the word range at the cursor.
221914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard         */
222914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final SpacingAndPunctuations SPACE = new SpacingAndPunctuations(
223914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard                mSpacingAndPunctuations, new int[] { Constants.CODE_SPACE });
224914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final SpacingAndPunctuations TAB = new SpacingAndPunctuations(
225914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard                mSpacingAndPunctuations, new int[] { Constants.CODE_TAB });
226914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final int[] SPACE_TAB = StringUtils.toSortedCodePointArray(" \t");
227914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        // A character that needs surrogate pair to represent its code point (U+2008A).
228914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final String SUPPLEMENTARY_CHAR_STRING = "\uD840\uDC8A";
229914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final SpacingAndPunctuations SUPPLEMENTARY_CHAR = new SpacingAndPunctuations(
230914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard                mSpacingAndPunctuations, StringUtils.toSortedCodePointArray(
231914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard                        SUPPLEMENTARY_CHAR_STRING));
232914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final String HIRAGANA_WORD = "\u3042\u3044\u3046\u3048\u304A"; // あいうえお
233914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final String GREEK_WORD = "\u03BA\u03B1\u03B9"; // και
234914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard
2352f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ExtractedText et = new ExtractedText();
2362f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final MockInputMethodService mockInputMethodService = new MockInputMethodService();
2372f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
2382f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection("word wo", "rd", et));
2392f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        et.startOffset = 0;
2402f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        et.selectionStart = 7;
241675bcf191c3cdb5ba5af70efb9357ffceb389c2eJean Chalard        TextRange r;
2422f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2432f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.beginBatchEdit();
2442f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // basic case
245292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
2462f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertTrue(TextUtils.equals("word", r.mWord));
2472f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2482f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // tab character instead of space
2492f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection("one\tword\two", "rd", et));
2502f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.beginBatchEdit();
251292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(TAB, ScriptUtils.SCRIPT_LATIN);
2522f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.endBatchEdit();
25320c89b1cf5e30026844922d312163ffcd1c20b26Jean Chalard        assertTrue(TextUtils.equals("word", r.mWord));
2542f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2552f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // splitting on supplementary character
2562f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(
257914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard                new MockConnection("one word" + SUPPLEMENTARY_CHAR_STRING + "wo", "rd", et));
2582f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.beginBatchEdit();
259914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_LATIN);
2602f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.endBatchEdit();
2612f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertTrue(TextUtils.equals("word", r.mWord));
262292deb632cbab232334190e68d29184094d6d51bJean Chalard
263292deb632cbab232334190e68d29184094d6d51bJean Chalard        // split on chars outside the specified script
264292deb632cbab232334190e68d29184094d6d51bJean Chalard        mockInputMethodService.setInputConnection(
265292deb632cbab232334190e68d29184094d6d51bJean Chalard                new MockConnection(HIRAGANA_WORD + "wo", "rd" + GREEK_WORD, et));
266292deb632cbab232334190e68d29184094d6d51bJean Chalard        ic.beginBatchEdit();
267914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_LATIN);
268292deb632cbab232334190e68d29184094d6d51bJean Chalard        ic.endBatchEdit();
269292deb632cbab232334190e68d29184094d6d51bJean Chalard        assertTrue(TextUtils.equals("word", r.mWord));
270292deb632cbab232334190e68d29184094d6d51bJean Chalard
271292deb632cbab232334190e68d29184094d6d51bJean Chalard        // likewise for greek
272292deb632cbab232334190e68d29184094d6d51bJean Chalard        mockInputMethodService.setInputConnection(
273292deb632cbab232334190e68d29184094d6d51bJean Chalard                new MockConnection("text" + GREEK_WORD, "text", et));
274292deb632cbab232334190e68d29184094d6d51bJean Chalard        ic.beginBatchEdit();
275914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_GREEK);
276292deb632cbab232334190e68d29184094d6d51bJean Chalard        ic.endBatchEdit();
277292deb632cbab232334190e68d29184094d6d51bJean Chalard        assertTrue(TextUtils.equals(GREEK_WORD, r.mWord));
2782f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
2792f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2802f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    /**
2812f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard     * Test logic in getting the word range at the cursor.
2822f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard     */
2832f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    public void testGetSuggestionSpansAtWord() {
2842f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        helpTestGetSuggestionSpansAtWord(10);
2852f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        helpTestGetSuggestionSpansAtWord(12);
2862f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        helpTestGetSuggestionSpansAtWord(15);
2872f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        helpTestGetSuggestionSpansAtWord(16);
2882f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
2892f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2902f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    private void helpTestGetSuggestionSpansAtWord(final int cursorPos) {
291914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final SpacingAndPunctuations SPACE = new SpacingAndPunctuations(
292914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard                mSpacingAndPunctuations, new int[] { Constants.CODE_SPACE });
2932f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final MockInputMethodService mockInputMethodService = new MockInputMethodService();
2942f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
2952f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2962f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final String[] SUGGESTIONS1 = { "swing", "strong" };
2972f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final String[] SUGGESTIONS2 = { "storing", "strung" };
2982f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2992f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test the usual case.
3002f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        SpannableString text = new SpannableString("This is a string for test");
3012f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3022f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3032f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
304675bcf191c3cdb5ba5af70efb9357ffceb389c2eJean Chalard        TextRange r;
3052f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        SuggestionSpan[] suggestions;
3062f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
307292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
3082f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3092f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 1);
3102f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
3112f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
3122f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test the case with 2 suggestion spans in the same place.
3132f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
3142f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3152f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3162f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
3172f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3182f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
319292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
3202f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3212f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 2);
3222f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
3232f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[1].getSuggestions(), SUGGESTIONS2);
3242f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
3252f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test a case with overlapping spans, 2nd extending past the start of the word
3262f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
3272f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3282f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3292f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
3302f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                5 /* start */, 16 /* end */, 0 /* flags */);
3312f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
332292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
3332f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3342f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 1);
3352f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
3362f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
3372f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test a case with overlapping spans, 2nd extending past the end of the word
3382f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
3392f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3402f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3412f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
3422f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 20 /* end */, 0 /* flags */);
3432f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
344292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
3452f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3462f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 1);
3472f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
3482f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
3492f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test a case with overlapping spans, 2nd extending past both ends of the word
3502f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
3512f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3522f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3532f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
3542f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                5 /* start */, 20 /* end */, 0 /* flags */);
3552f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
356292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
3572f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3582f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 1);
3592f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
3602f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
3612f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test a case with overlapping spans, none right on the word
3622f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
3632f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3642f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                5 /* start */, 16 /* end */, 0 /* flags */);
3652f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
3662f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                5 /* start */, 20 /* end */, 0 /* flags */);
3672f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
368292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
3692f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3702f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 0);
3712f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
37272b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
37372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard    public void testCursorTouchingWord() {
37472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        final MockInputMethodService ims = new MockInputMethodService();
37572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        final RichInputConnection ic = new RichInputConnection(ims);
37672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        final SpacingAndPunctuations sap = mSpacingAndPunctuations;
37772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
37872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("users", 5));
37972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
38072b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertTrue(ic.isCursorTouchingWord(sap));
38172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
38272b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("users'", 5));
38372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
38472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertTrue(ic.isCursorTouchingWord(sap));
38572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
38672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("users'", 6));
38772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
38872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertTrue(ic.isCursorTouchingWord(sap));
38972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
39072b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("'users'", 6));
39172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
39272b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertTrue(ic.isCursorTouchingWord(sap));
39372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
39472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("'users'", 7));
39572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
39672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertTrue(ic.isCursorTouchingWord(sap));
39772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
39872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("users '", 6));
39972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
40072b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertFalse(ic.isCursorTouchingWord(sap));
40172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
40272b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("users '", 7));
40372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
40472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertFalse(ic.isCursorTouchingWord(sap));
40572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
40672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("re-", 3));
40772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
40872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertTrue(ic.isCursorTouchingWord(sap));
40972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
41072b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("re--", 4));
41172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
41272b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertFalse(ic.isCursorTouchingWord(sap));
41372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
41472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("-", 1));
41572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
41672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertFalse(ic.isCursorTouchingWord(sap));
41772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
41872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("--", 2));
41972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
42072b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertFalse(ic.isCursorTouchingWord(sap));
42172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
42272b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" -", 2));
42372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
42472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertFalse(ic.isCursorTouchingWord(sap));
42572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
42672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" --", 3));
42772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
42872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertFalse(ic.isCursorTouchingWord(sap));
42972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
43072b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" users '", 1));
43172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
43272b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertTrue(ic.isCursorTouchingWord(sap));
43372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
43472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" users '", 3));
43572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
43672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertTrue(ic.isCursorTouchingWord(sap));
43772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
43872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" users '", 7));
43972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
44072b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertFalse(ic.isCursorTouchingWord(sap));
44172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
44272b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" users are", 7));
44372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
44472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertTrue(ic.isCursorTouchingWord(sap));
44572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
44672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" users 'are", 7));
44772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
44872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        assertFalse(ic.isCursorTouchingWord(sap));
44972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard    }
4502f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard}
451