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