Home | History | Annotate | Download | only in latin
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.inputmethod.latin;
     18 
     19 import android.content.res.Resources;
     20 import android.inputmethodservice.InputMethodService;
     21 import android.os.Parcel;
     22 import android.test.AndroidTestCase;
     23 import android.test.MoreAsserts;
     24 import android.test.suitebuilder.annotation.SmallTest;
     25 import android.text.SpannableString;
     26 import android.text.TextUtils;
     27 import android.text.style.SuggestionSpan;
     28 import android.view.inputmethod.ExtractedText;
     29 import android.view.inputmethod.ExtractedTextRequest;
     30 import android.view.inputmethod.InputConnection;
     31 import android.view.inputmethod.InputConnectionWrapper;
     32 
     33 import com.android.inputmethod.latin.PrevWordsInfo.WordInfo;
     34 import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
     35 import com.android.inputmethod.latin.utils.PrevWordsInfoUtils;
     36 import com.android.inputmethod.latin.utils.RunInLocale;
     37 import com.android.inputmethod.latin.utils.ScriptUtils;
     38 import com.android.inputmethod.latin.utils.StringUtils;
     39 import com.android.inputmethod.latin.utils.TextRange;
     40 
     41 import java.util.Locale;
     42 
     43 @SmallTest
     44 public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
     45 
     46     // The following is meant to be a reasonable default for
     47     // the "word_separators" resource.
     48     private SpacingAndPunctuations mSpacingAndPunctuations;
     49 
     50     @Override
     51     protected void setUp() throws Exception {
     52         super.setUp();
     53         final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() {
     54             @Override
     55             protected SpacingAndPunctuations job(final Resources res) {
     56                 return new SpacingAndPunctuations(res);
     57             }
     58         };
     59         final Resources res = getContext().getResources();
     60         mSpacingAndPunctuations = job.runInLocale(res, Locale.ENGLISH);
     61     }
     62 
     63     private class MockConnection extends InputConnectionWrapper {
     64         final CharSequence mTextBefore;
     65         final CharSequence mTextAfter;
     66         final ExtractedText mExtractedText;
     67 
     68         public MockConnection(final CharSequence text, final int cursorPosition) {
     69             super(null, false);
     70             // Interaction of spans with Parcels is completely non-trivial, but in the actual case
     71             // the CharSequences do go through Parcels because they go through IPC. There
     72             // are some significant differences between the behavior of Spanned objects that
     73             // have and that have not gone through parceling, so it's much easier to simulate
     74             // the environment with Parcels than try to emulate things by hand.
     75             final Parcel p = Parcel.obtain();
     76             TextUtils.writeToParcel(text.subSequence(0, cursorPosition), p, 0 /* flags */);
     77             TextUtils.writeToParcel(text.subSequence(cursorPosition, text.length()), p,
     78                     0 /* flags */);
     79             final byte[] marshalled = p.marshall();
     80             p.unmarshall(marshalled, 0, marshalled.length);
     81             p.setDataPosition(0);
     82             mTextBefore = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
     83             mTextAfter = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
     84             mExtractedText = null;
     85             p.recycle();
     86         }
     87 
     88         public MockConnection(String textBefore, String textAfter, ExtractedText extractedText) {
     89             super(null, false);
     90             mTextBefore = textBefore;
     91             mTextAfter = textAfter;
     92             mExtractedText = extractedText;
     93         }
     94 
     95         public int cursorPos() {
     96             return mTextBefore.length();
     97         }
     98 
     99         /* (non-Javadoc)
    100          * @see android.view.inputmethod.InputConnectionWrapper#getTextBeforeCursor(int, int)
    101          */
    102         @Override
    103         public CharSequence getTextBeforeCursor(int n, int flags) {
    104             return mTextBefore;
    105         }
    106 
    107         /* (non-Javadoc)
    108          * @see android.view.inputmethod.InputConnectionWrapper#getTextAfterCursor(int, int)
    109          */
    110         @Override
    111         public CharSequence getTextAfterCursor(int n, int flags) {
    112             return mTextAfter;
    113         }
    114 
    115         /* (non-Javadoc)
    116          * @see android.view.inputmethod.InputConnectionWrapper#getExtractedText(
    117          *         ExtractedTextRequest, int)
    118          */
    119         @Override
    120         public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
    121             return mExtractedText;
    122         }
    123 
    124         @Override
    125         public boolean beginBatchEdit() {
    126             return true;
    127         }
    128 
    129         @Override
    130         public boolean endBatchEdit() {
    131             return true;
    132         }
    133 
    134         @Override
    135         public boolean finishComposingText() {
    136             return true;
    137         }
    138     }
    139 
    140     private class MockInputMethodService extends InputMethodService {
    141         private MockConnection mMockConnection;
    142         public void setInputConnection(final MockConnection mockConnection) {
    143             mMockConnection = mockConnection;
    144         }
    145         public int cursorPos() {
    146             return mMockConnection.cursorPos();
    147         }
    148         @Override
    149         public InputConnection getCurrentInputConnection() {
    150             return mMockConnection;
    151         }
    152     }
    153 
    154     /************************** Tests ************************/
    155 
    156     /**
    157      * Test for getting previous word (for bigram suggestions)
    158      */
    159     public void testGetPreviousWord() {
    160         // If one of the following cases breaks, the bigram suggestions won't work.
    161         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    162                 "abc def", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "abc");
    163         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    164                 "abc", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE);
    165         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    166                 "abc. def", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE);
    167 
    168         assertFalse(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    169                 "abc def", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mIsBeginningOfSentence);
    170         assertTrue(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    171                 "abc", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mIsBeginningOfSentence);
    172 
    173         // For n-gram
    174         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    175                 "abc def", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "def");
    176         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    177                 "abc def", mSpacingAndPunctuations, 1).mPrevWordsInfo[1].mWord, "abc");
    178         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    179                 "abc def", mSpacingAndPunctuations, 2).mPrevWordsInfo[1],
    180                 WordInfo.BEGINNING_OF_SENTENCE);
    181 
    182         // The following tests reflect the current behavior of the function
    183         // RichInputConnection#getNthPreviousWord.
    184         // TODO: However at this time, the code does never go
    185         // into such a path, so it should be safe to change the behavior of
    186         // this function if needed - especially since it does not seem very
    187         // logical. These tests are just there to catch any unintentional
    188         // changes in the behavior of the RichInputConnection#getPreviousWord method.
    189         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    190                 "abc def ", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "abc");
    191         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    192                 "abc def.", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "abc");
    193         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    194                 "abc def .", mSpacingAndPunctuations, 2).mPrevWordsInfo[0].mWord, "def");
    195         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    196                 "abc ", mSpacingAndPunctuations, 2), PrevWordsInfo.BEGINNING_OF_SENTENCE);
    197 
    198         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    199                 "abc def", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "def");
    200         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    201                 "abc def ", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "def");
    202         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    203                 "abc 'def", mSpacingAndPunctuations, 1).mPrevWordsInfo[0].mWord, "'def");
    204         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    205                 "abc def.", mSpacingAndPunctuations, 1), PrevWordsInfo.BEGINNING_OF_SENTENCE);
    206         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    207                 "abc def .", mSpacingAndPunctuations, 1), PrevWordsInfo.BEGINNING_OF_SENTENCE);
    208         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    209                 "abc, def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO);
    210         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    211                 "abc? def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO);
    212         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    213                 "abc! def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO);
    214         assertEquals(PrevWordsInfoUtils.getPrevWordsInfoFromNthPreviousWord(
    215                 "abc 'def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO);
    216     }
    217 
    218     public void testGetWordRangeAtCursor() {
    219         /**
    220          * Test logic in getting the word range at the cursor.
    221          */
    222         final SpacingAndPunctuations SPACE = new SpacingAndPunctuations(
    223                 mSpacingAndPunctuations, new int[] { Constants.CODE_SPACE });
    224         final SpacingAndPunctuations TAB = new SpacingAndPunctuations(
    225                 mSpacingAndPunctuations, new int[] { Constants.CODE_TAB });
    226         final int[] SPACE_TAB = StringUtils.toSortedCodePointArray(" \t");
    227         // A character that needs surrogate pair to represent its code point (U+2008A).
    228         final String SUPPLEMENTARY_CHAR_STRING = "\uD840\uDC8A";
    229         final SpacingAndPunctuations SUPPLEMENTARY_CHAR = new SpacingAndPunctuations(
    230                 mSpacingAndPunctuations, StringUtils.toSortedCodePointArray(
    231                         SUPPLEMENTARY_CHAR_STRING));
    232         final String HIRAGANA_WORD = "\u3042\u3044\u3046\u3048\u304A"; // 
    233         final String GREEK_WORD = "\u03BA\u03B1\u03B9"; // 
    234 
    235         ExtractedText et = new ExtractedText();
    236         final MockInputMethodService mockInputMethodService = new MockInputMethodService();
    237         final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
    238         mockInputMethodService.setInputConnection(new MockConnection("word wo", "rd", et));
    239         et.startOffset = 0;
    240         et.selectionStart = 7;
    241         TextRange r;
    242 
    243         ic.beginBatchEdit();
    244         // basic case
    245         r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
    246         assertTrue(TextUtils.equals("word", r.mWord));
    247 
    248         // tab character instead of space
    249         mockInputMethodService.setInputConnection(new MockConnection("one\tword\two", "rd", et));
    250         ic.beginBatchEdit();
    251         r = ic.getWordRangeAtCursor(TAB, ScriptUtils.SCRIPT_LATIN);
    252         ic.endBatchEdit();
    253         assertTrue(TextUtils.equals("word", r.mWord));
    254 
    255         // splitting on supplementary character
    256         mockInputMethodService.setInputConnection(
    257                 new MockConnection("one word" + SUPPLEMENTARY_CHAR_STRING + "wo", "rd", et));
    258         ic.beginBatchEdit();
    259         r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_LATIN);
    260         ic.endBatchEdit();
    261         assertTrue(TextUtils.equals("word", r.mWord));
    262 
    263         // split on chars outside the specified script
    264         mockInputMethodService.setInputConnection(
    265                 new MockConnection(HIRAGANA_WORD + "wo", "rd" + GREEK_WORD, et));
    266         ic.beginBatchEdit();
    267         r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_LATIN);
    268         ic.endBatchEdit();
    269         assertTrue(TextUtils.equals("word", r.mWord));
    270 
    271         // likewise for greek
    272         mockInputMethodService.setInputConnection(
    273                 new MockConnection("text" + GREEK_WORD, "text", et));
    274         ic.beginBatchEdit();
    275         r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_GREEK);
    276         ic.endBatchEdit();
    277         assertTrue(TextUtils.equals(GREEK_WORD, r.mWord));
    278     }
    279 
    280     /**
    281      * Test logic in getting the word range at the cursor.
    282      */
    283     public void testGetSuggestionSpansAtWord() {
    284         helpTestGetSuggestionSpansAtWord(10);
    285         helpTestGetSuggestionSpansAtWord(12);
    286         helpTestGetSuggestionSpansAtWord(15);
    287         helpTestGetSuggestionSpansAtWord(16);
    288     }
    289 
    290     private void helpTestGetSuggestionSpansAtWord(final int cursorPos) {
    291         final SpacingAndPunctuations SPACE = new SpacingAndPunctuations(
    292                 mSpacingAndPunctuations, new int[] { Constants.CODE_SPACE });
    293         final MockInputMethodService mockInputMethodService = new MockInputMethodService();
    294         final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
    295 
    296         final String[] SUGGESTIONS1 = { "swing", "strong" };
    297         final String[] SUGGESTIONS2 = { "storing", "strung" };
    298 
    299         // Test the usual case.
    300         SpannableString text = new SpannableString("This is a string for test");
    301         text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
    302                 10 /* start */, 16 /* end */, 0 /* flags */);
    303         mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
    304         TextRange r;
    305         SuggestionSpan[] suggestions;
    306 
    307         r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
    308         suggestions = r.getSuggestionSpansAtWord();
    309         assertEquals(suggestions.length, 1);
    310         MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
    311 
    312         // Test the case with 2 suggestion spans in the same place.
    313         text = new SpannableString("This is a string for test");
    314         text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
    315                 10 /* start */, 16 /* end */, 0 /* flags */);
    316         text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
    317                 10 /* start */, 16 /* end */, 0 /* flags */);
    318         mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
    319         r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
    320         suggestions = r.getSuggestionSpansAtWord();
    321         assertEquals(suggestions.length, 2);
    322         MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
    323         MoreAsserts.assertEquals(suggestions[1].getSuggestions(), SUGGESTIONS2);
    324 
    325         // Test a case with overlapping spans, 2nd extending past the start of the word
    326         text = new SpannableString("This is a string for test");
    327         text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
    328                 10 /* start */, 16 /* end */, 0 /* flags */);
    329         text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
    330                 5 /* start */, 16 /* end */, 0 /* flags */);
    331         mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
    332         r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
    333         suggestions = r.getSuggestionSpansAtWord();
    334         assertEquals(suggestions.length, 1);
    335         MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
    336 
    337         // Test a case with overlapping spans, 2nd extending past the end of the word
    338         text = new SpannableString("This is a string for test");
    339         text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
    340                 10 /* start */, 16 /* end */, 0 /* flags */);
    341         text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
    342                 10 /* start */, 20 /* end */, 0 /* flags */);
    343         mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
    344         r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
    345         suggestions = r.getSuggestionSpansAtWord();
    346         assertEquals(suggestions.length, 1);
    347         MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
    348 
    349         // Test a case with overlapping spans, 2nd extending past both ends of the word
    350         text = new SpannableString("This is a string for test");
    351         text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
    352                 10 /* start */, 16 /* end */, 0 /* flags */);
    353         text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
    354                 5 /* start */, 20 /* end */, 0 /* flags */);
    355         mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
    356         r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
    357         suggestions = r.getSuggestionSpansAtWord();
    358         assertEquals(suggestions.length, 1);
    359         MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1);
    360 
    361         // Test a case with overlapping spans, none right on the word
    362         text = new SpannableString("This is a string for test");
    363         text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
    364                 5 /* start */, 16 /* end */, 0 /* flags */);
    365         text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */),
    366                 5 /* start */, 20 /* end */, 0 /* flags */);
    367         mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
    368         r = ic.getWordRangeAtCursor(SPACE, ScriptUtils.SCRIPT_LATIN);
    369         suggestions = r.getSuggestionSpansAtWord();
    370         assertEquals(suggestions.length, 0);
    371     }
    372 
    373     public void testCursorTouchingWord() {
    374         final MockInputMethodService ims = new MockInputMethodService();
    375         final RichInputConnection ic = new RichInputConnection(ims);
    376         final SpacingAndPunctuations sap = mSpacingAndPunctuations;
    377 
    378         ims.setInputConnection(new MockConnection("users", 5));
    379         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    380         assertTrue(ic.isCursorTouchingWord(sap));
    381 
    382         ims.setInputConnection(new MockConnection("users'", 5));
    383         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    384         assertTrue(ic.isCursorTouchingWord(sap));
    385 
    386         ims.setInputConnection(new MockConnection("users'", 6));
    387         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    388         assertTrue(ic.isCursorTouchingWord(sap));
    389 
    390         ims.setInputConnection(new MockConnection("'users'", 6));
    391         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    392         assertTrue(ic.isCursorTouchingWord(sap));
    393 
    394         ims.setInputConnection(new MockConnection("'users'", 7));
    395         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    396         assertTrue(ic.isCursorTouchingWord(sap));
    397 
    398         ims.setInputConnection(new MockConnection("users '", 6));
    399         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    400         assertFalse(ic.isCursorTouchingWord(sap));
    401 
    402         ims.setInputConnection(new MockConnection("users '", 7));
    403         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    404         assertFalse(ic.isCursorTouchingWord(sap));
    405 
    406         ims.setInputConnection(new MockConnection("re-", 3));
    407         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    408         assertTrue(ic.isCursorTouchingWord(sap));
    409 
    410         ims.setInputConnection(new MockConnection("re--", 4));
    411         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    412         assertFalse(ic.isCursorTouchingWord(sap));
    413 
    414         ims.setInputConnection(new MockConnection("-", 1));
    415         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    416         assertFalse(ic.isCursorTouchingWord(sap));
    417 
    418         ims.setInputConnection(new MockConnection("--", 2));
    419         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    420         assertFalse(ic.isCursorTouchingWord(sap));
    421 
    422         ims.setInputConnection(new MockConnection(" -", 2));
    423         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    424         assertFalse(ic.isCursorTouchingWord(sap));
    425 
    426         ims.setInputConnection(new MockConnection(" --", 3));
    427         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    428         assertFalse(ic.isCursorTouchingWord(sap));
    429 
    430         ims.setInputConnection(new MockConnection(" users '", 1));
    431         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    432         assertTrue(ic.isCursorTouchingWord(sap));
    433 
    434         ims.setInputConnection(new MockConnection(" users '", 3));
    435         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    436         assertTrue(ic.isCursorTouchingWord(sap));
    437 
    438         ims.setInputConnection(new MockConnection(" users '", 7));
    439         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    440         assertFalse(ic.isCursorTouchingWord(sap));
    441 
    442         ims.setInputConnection(new MockConnection(" users are", 7));
    443         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    444         assertTrue(ic.isCursorTouchingWord(sap));
    445 
    446         ims.setInputConnection(new MockConnection(" users 'are", 7));
    447         ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true);
    448         assertFalse(ic.isCursorTouchingWord(sap));
    449     }
    450 }
    451