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
339342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport com.android.inputmethod.latin.common.Constants;
344beeb9253a06482299e0c67467531d30436a02fcJean Chalardimport com.android.inputmethod.latin.common.StringUtils;
35494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaokaimport com.android.inputmethod.latin.settings.SpacingAndPunctuations;
36bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagiimport com.android.inputmethod.latin.utils.NgramContextUtils;
37494e2d6c17cdbf27615a2fbc02b12d2562bf7cd3Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.RunInLocale;
38292deb632cbab232334190e68d29184094d6d51bJean Chalardimport com.android.inputmethod.latin.utils.ScriptUtils;
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
1405f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    static 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.
161bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
162bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                "abc def", mSpacingAndPunctuations, 2).getNthPrevWord(1), "abc");
163bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
164bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi                "abc", mSpacingAndPunctuations, 2), NgramContext.BEGINNING_OF_SENTENCE);
165bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
166bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi                "abc. def", mSpacingAndPunctuations, 2), NgramContext.BEGINNING_OF_SENTENCE);
16717f326b7458c2bde2569e283a96e703755485328Keisuke Kuroyanagi
168bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertFalse(NgramContextUtils.getNgramContextFromNthPreviousWord(
169bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                "abc def", mSpacingAndPunctuations, 2).isBeginningOfSentenceContext());
170bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertTrue(NgramContextUtils.getNgramContextFromNthPreviousWord(
171bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                "abc", mSpacingAndPunctuations, 2).isBeginningOfSentenceContext());
1721c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
1731c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        // For n-gram
174bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
175bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                "abc def", mSpacingAndPunctuations, 1).getNthPrevWord(1), "def");
176bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
177bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                "abc def", mSpacingAndPunctuations, 1).getNthPrevWord(2), "abc");
178bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertTrue(NgramContextUtils.getNgramContextFromNthPreviousWord(
17911a3965f8c376db4d8fbdf3c6ea6ac54550ae6edAdrian Velicu                "abc def", mSpacingAndPunctuations, 2).isNthPrevWordBeginningOfSentence(2));
1801c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
1812f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // The following tests reflect the current behavior of the function
1822f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // RichInputConnection#getNthPreviousWord.
1832f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // TODO: However at this time, the code does never go
1842f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // into such a path, so it should be safe to change the behavior of
1852f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // this function if needed - especially since it does not seem very
1862f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // logical. These tests are just there to catch any unintentional
1872f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // changes in the behavior of the RichInputConnection#getPreviousWord method.
188bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
189bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                "abc def ", mSpacingAndPunctuations, 2).getNthPrevWord(1), "abc");
190bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
191bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                "abc def.", mSpacingAndPunctuations, 2).getNthPrevWord(1), "abc");
192bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
193bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                "abc def .", mSpacingAndPunctuations, 2).getNthPrevWord(1), "def");
194bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertTrue(NgramContextUtils.getNgramContextFromNthPreviousWord(
195bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                "abc ", mSpacingAndPunctuations, 2).isBeginningOfSentenceContext());
19617f326b7458c2bde2569e283a96e703755485328Keisuke Kuroyanagi
197bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
198bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                "abc def", mSpacingAndPunctuations, 1).getNthPrevWord(1), "def");
199bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
200bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                "abc def ", mSpacingAndPunctuations, 1).getNthPrevWord(1), "def");
201bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
202bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                "abc 'def", mSpacingAndPunctuations, 1).getNthPrevWord(1), "'def");
203bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
204bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi                "abc def.", mSpacingAndPunctuations, 1), NgramContext.BEGINNING_OF_SENTENCE);
205bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
206bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi                "abc def .", mSpacingAndPunctuations, 1), NgramContext.BEGINNING_OF_SENTENCE);
207bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
208bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi                "abc, def", mSpacingAndPunctuations, 2), NgramContext.EMPTY_PREV_WORDS_INFO);
20925433d7a0b9ed9a60dc70e5dd34ad329ef21b036Mohammadinamul Sheik        // question mark is treated as the end of the sentence. Hence, beginning of the
21025433d7a0b9ed9a60dc70e5dd34ad329ef21b036Mohammadinamul Sheik        // sentence is expected.
211bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
21225433d7a0b9ed9a60dc70e5dd34ad329ef21b036Mohammadinamul Sheik                "abc? def", mSpacingAndPunctuations, 2), NgramContext.BEGINNING_OF_SENTENCE);
21325433d7a0b9ed9a60dc70e5dd34ad329ef21b036Mohammadinamul Sheik        // Exclamation mark is treated as the end of the sentence. Hence, beginning of the
21425433d7a0b9ed9a60dc70e5dd34ad329ef21b036Mohammadinamul Sheik        // sentence is expected.
215bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
21625433d7a0b9ed9a60dc70e5dd34ad329ef21b036Mohammadinamul Sheik                "abc! def", mSpacingAndPunctuations, 2), NgramContext.BEGINNING_OF_SENTENCE);
217bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        assertEquals(NgramContextUtils.getNgramContextFromNthPreviousWord(
218bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi                "abc 'def", mSpacingAndPunctuations, 2), NgramContext.EMPTY_PREV_WORDS_INFO);
2192f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
2202f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2212f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    public void testGetWordRangeAtCursor() {
222914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        /**
223914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard         * Test logic in getting the word range at the cursor.
224914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard         */
225914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final SpacingAndPunctuations SPACE = new SpacingAndPunctuations(
226914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard                mSpacingAndPunctuations, new int[] { Constants.CODE_SPACE });
227914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final SpacingAndPunctuations TAB = new SpacingAndPunctuations(
228914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard                mSpacingAndPunctuations, new int[] { Constants.CODE_TAB });
229914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        // A character that needs surrogate pair to represent its code point (U+2008A).
230914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final String SUPPLEMENTARY_CHAR_STRING = "\uD840\uDC8A";
231914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final SpacingAndPunctuations SUPPLEMENTARY_CHAR = new SpacingAndPunctuations(
232914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard                mSpacingAndPunctuations, StringUtils.toSortedCodePointArray(
233914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard                        SUPPLEMENTARY_CHAR_STRING));
234914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final String HIRAGANA_WORD = "\u3042\u3044\u3046\u3048\u304A"; // あいうえお
235914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final String GREEK_WORD = "\u03BA\u03B1\u03B9"; // και
236914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard
2372f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ExtractedText et = new ExtractedText();
2382f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final MockInputMethodService mockInputMethodService = new MockInputMethodService();
2392f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
2402f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection("word wo", "rd", et));
2412f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        et.startOffset = 0;
2422f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        et.selectionStart = 7;
243675bcf191c3cdb5ba5af70efb9357ffceb389c2eJean Chalard        TextRange r;
2442f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2452f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.beginBatchEdit();
2462f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // basic case
247292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
2482f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertTrue(TextUtils.equals("word", r.mWord));
2492f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2502f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // tab character instead of space
2512f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection("one\tword\two", "rd", et));
2522f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.beginBatchEdit();
253292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(TAB, ScriptUtils.SCRIPT_LATIN);
2542f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.endBatchEdit();
25520c89b1cf5e30026844922d312163ffcd1c20b26Jean Chalard        assertTrue(TextUtils.equals("word", r.mWord));
2562f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2572f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // splitting on supplementary character
2582f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(
259914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard                new MockConnection("one word" + SUPPLEMENTARY_CHAR_STRING + "wo", "rd", et));
2602f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.beginBatchEdit();
261914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_LATIN);
2622f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        ic.endBatchEdit();
2632f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertTrue(TextUtils.equals("word", r.mWord));
264292deb632cbab232334190e68d29184094d6d51bJean Chalard
265292deb632cbab232334190e68d29184094d6d51bJean Chalard        // split on chars outside the specified script
266292deb632cbab232334190e68d29184094d6d51bJean Chalard        mockInputMethodService.setInputConnection(
267292deb632cbab232334190e68d29184094d6d51bJean Chalard                new MockConnection(HIRAGANA_WORD + "wo", "rd" + GREEK_WORD, et));
268292deb632cbab232334190e68d29184094d6d51bJean Chalard        ic.beginBatchEdit();
269914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_LATIN);
270292deb632cbab232334190e68d29184094d6d51bJean Chalard        ic.endBatchEdit();
271292deb632cbab232334190e68d29184094d6d51bJean Chalard        assertTrue(TextUtils.equals("word", r.mWord));
272292deb632cbab232334190e68d29184094d6d51bJean Chalard
273292deb632cbab232334190e68d29184094d6d51bJean Chalard        // likewise for greek
274292deb632cbab232334190e68d29184094d6d51bJean Chalard        mockInputMethodService.setInputConnection(
275292deb632cbab232334190e68d29184094d6d51bJean Chalard                new MockConnection("text" + GREEK_WORD, "text", et));
276292deb632cbab232334190e68d29184094d6d51bJean Chalard        ic.beginBatchEdit();
277914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_GREEK);
278292deb632cbab232334190e68d29184094d6d51bJean Chalard        ic.endBatchEdit();
279292deb632cbab232334190e68d29184094d6d51bJean Chalard        assertTrue(TextUtils.equals(GREEK_WORD, r.mWord));
2802f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
2812f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2822f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    /**
2832f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard     * Test logic in getting the word range at the cursor.
2842f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard     */
2852f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    public void testGetSuggestionSpansAtWord() {
2862f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        helpTestGetSuggestionSpansAtWord(10);
2872f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        helpTestGetSuggestionSpansAtWord(12);
2882f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        helpTestGetSuggestionSpansAtWord(15);
2892f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        helpTestGetSuggestionSpansAtWord(16);
2902f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
2912f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2922f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    private void helpTestGetSuggestionSpansAtWord(final int cursorPos) {
293914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard        final SpacingAndPunctuations SPACE = new SpacingAndPunctuations(
294914078fd9198aeb3d7ffa034562321d688d588f7Jean Chalard                mSpacingAndPunctuations, new int[] { Constants.CODE_SPACE });
2952f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final MockInputMethodService mockInputMethodService = new MockInputMethodService();
2962f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
2972f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
2982f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final String[] SUGGESTIONS1 = { "swing", "strong" };
2992f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        final String[] SUGGESTIONS2 = { "storing", "strung" };
3002f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
3012f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test the usual case.
3022f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        SpannableString text = new SpannableString("This is a string for test");
3032f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3042f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3052f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
306675bcf191c3cdb5ba5af70efb9357ffceb389c2eJean Chalard        TextRange r;
3072f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        SuggestionSpan[] suggestions;
3082f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
309292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
3102f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3112f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 1);
3122f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
3132f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
3142f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test the case with 2 suggestion spans in the same place.
3152f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
3162f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3172f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3182f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
3192f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3202f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
321292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
3222f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3232f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 2);
3242f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
3252f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[1].getSuggestions(), SUGGESTIONS2);
3262f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
3272f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test a case with overlapping spans, 2nd extending past the start of the word
3282f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
3292f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3302f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3312f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
3322f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                5 /* start */, 16 /* end */, 0 /* flags */);
3332f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
334292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
3352f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3362f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 1);
3372f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
3382f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
3392f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test a case with overlapping spans, 2nd extending past the end of the word
3402f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
3412f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3422f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3432f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
3442f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 20 /* end */, 0 /* flags */);
3452f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
346292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
3472f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3482f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 1);
3492f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
3502f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
3512f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test a case with overlapping spans, 2nd extending past both ends of the word
3522f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
3532f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3542f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                10 /* start */, 16 /* end */, 0 /* flags */);
3552f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
3562f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                5 /* start */, 20 /* end */, 0 /* flags */);
3572f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
358292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
3592f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3602f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 1);
3612f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
3622f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard
3632f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        // Test a case with overlapping spans, none right on the word
3642f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text = new SpannableString("This is a string for test");
3652f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
3662f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                5 /* start */, 16 /* end */, 0 /* flags */);
3672f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
3682f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard                5 /* start */, 20 /* end */, 0 /* flags */);
3692f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
370292deb632cbab232334190e68d29184094d6d51bJean Chalard        r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
3712f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        suggestions = r.getSuggestionSpansAtWord();
3722f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard        assertEquals(suggestions.length, 0);
3732f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard    }
37472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
37572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard    public void testCursorTouchingWord() {
37672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        final MockInputMethodService ims = new MockInputMethodService();
37772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        final RichInputConnection ic = new RichInputConnection(ims);
37872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        final SpacingAndPunctuations sap = mSpacingAndPunctuations;
37972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
38072b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("users", 5));
38172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
382f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertTrue(ic.isCursorTouchingWord(sap, true /* checkTextAfter */));
38372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
38472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("users'", 5));
38572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
386f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertTrue(ic.isCursorTouchingWord(sap, true));
38772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
38872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("users'", 6));
38972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
390f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertTrue(ic.isCursorTouchingWord(sap, true));
39172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
39272b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("'users'", 6));
39372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
394f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertTrue(ic.isCursorTouchingWord(sap, true));
39572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
39672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("'users'", 7));
39772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
398f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertTrue(ic.isCursorTouchingWord(sap, true));
39972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
40072b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("users '", 6));
40172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
402f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertFalse(ic.isCursorTouchingWord(sap, true));
40372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
40472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("users '", 7));
40572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
406f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertFalse(ic.isCursorTouchingWord(sap, true));
40772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
40872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("re-", 3));
40972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
410f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertTrue(ic.isCursorTouchingWord(sap, true));
41172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
41272b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("re--", 4));
41372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
414f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertFalse(ic.isCursorTouchingWord(sap, true));
41572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
41672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("-", 1));
41772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
418f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertFalse(ic.isCursorTouchingWord(sap, true));
41972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
42072b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection("--", 2));
42172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
422f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertFalse(ic.isCursorTouchingWord(sap, true));
42372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
42472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" -", 2));
42572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
426f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertFalse(ic.isCursorTouchingWord(sap, true));
42772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
42872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" --", 3));
42972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
430f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertFalse(ic.isCursorTouchingWord(sap, true));
43172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
43272b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" users '", 1));
43372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
434f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertTrue(ic.isCursorTouchingWord(sap, true));
43572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
43672b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" users '", 3));
43772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
438f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertTrue(ic.isCursorTouchingWord(sap, true));
43972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
44072b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" users '", 7));
44172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
442f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertFalse(ic.isCursorTouchingWord(sap, true));
44372b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
44472b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" users are", 7));
44572b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
446f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertTrue(ic.isCursorTouchingWord(sap, true));
44772b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard
44872b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ims.setInputConnection(new MockConnection(" users 'are", 7));
44972b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard        ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
450f470729df26c67f48bd55bbf16a3d6066eac2a2fTom Ouyang        assertFalse(ic.isCursorTouchingWord(sap, true));
45172b67f65411cf07cb8cb2d52e859f46d9d5b91d4Jean Chalard    }
4522f7f6257b66fc1ed19b600f3d55902fd0de2e338Jean Chalard}
453