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
17package com.android.inputmethod.latin;
18
19import android.test.suitebuilder.annotation.LargeTest;
20import android.text.TextUtils;
21import android.view.inputmethod.BaseInputConnection;
22
23import com.android.inputmethod.latin.settings.Settings;
24
25@LargeTest
26public class InputLogicTests extends InputTestsBase {
27
28    public void testTypeWord() {
29        final String WORD_TO_TYPE = "abcd";
30        type(WORD_TO_TYPE);
31        assertEquals("type word", WORD_TO_TYPE, mEditText.getText().toString());
32    }
33
34    public void testPickSuggestionThenBackspace() {
35        final String WORD_TO_TYPE = "this";
36        final String EXPECTED_RESULT = "thi";
37        type(WORD_TO_TYPE);
38        pickSuggestionManually(WORD_TO_TYPE);
39        mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1);
40        type(Constants.CODE_DELETE);
41        assertEquals("press suggestion then backspace", EXPECTED_RESULT,
42                mEditText.getText().toString());
43    }
44
45    public void testPickAutoCorrectionThenBackspace() {
46        final String WORD_TO_TYPE = "tgis";
47        final String WORD_TO_PICK = "this";
48        final String EXPECTED_RESULT = "thi";
49        type(WORD_TO_TYPE);
50        // Choose the auto-correction. For "tgis", the auto-correction should be "this".
51        pickSuggestionManually(WORD_TO_PICK);
52        mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1);
53        assertEquals("pick typed word over auto-correction then backspace", WORD_TO_PICK,
54                mEditText.getText().toString());
55        type(Constants.CODE_DELETE);
56        assertEquals("pick typed word over auto-correction then backspace", EXPECTED_RESULT,
57                mEditText.getText().toString());
58    }
59
60    public void testPickTypedWordOverAutoCorrectionThenBackspace() {
61        final String WORD_TO_TYPE = "tgis";
62        final String EXPECTED_RESULT = "tgi";
63        type(WORD_TO_TYPE);
64        // Choose the typed word.
65        pickSuggestionManually(WORD_TO_TYPE);
66        mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1);
67        assertEquals("pick typed word over auto-correction then backspace", WORD_TO_TYPE,
68                mEditText.getText().toString());
69        type(Constants.CODE_DELETE);
70        assertEquals("pick typed word over auto-correction then backspace", EXPECTED_RESULT,
71                mEditText.getText().toString());
72    }
73
74    public void testPickDifferentSuggestionThenBackspace() {
75        final String WORD_TO_TYPE = "tgis";
76        final String WORD_TO_PICK = "thus";
77        final String EXPECTED_RESULT = "thu";
78        type(WORD_TO_TYPE);
79        // Choose the second suggestion, which should be "thus" when "tgis" is typed.
80        pickSuggestionManually(WORD_TO_PICK);
81        mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1);
82        assertEquals("pick different suggestion then backspace", WORD_TO_PICK,
83                mEditText.getText().toString());
84        type(Constants.CODE_DELETE);
85        assertEquals("pick different suggestion then backspace", EXPECTED_RESULT,
86                mEditText.getText().toString());
87    }
88
89    public void testDeleteSelection() {
90        final String STRING_TO_TYPE = "some text delete me some text";
91        final int typedLength = STRING_TO_TYPE.length();
92        final int SELECTION_START = 10;
93        final int SELECTION_END = 19;
94        final String EXPECTED_RESULT = "some text  some text";
95        type(STRING_TO_TYPE);
96        // There is no IMF to call onUpdateSelection for us so we must do it by hand.
97        // Send once to simulate the cursor actually responding to the move caused by typing.
98        // This is necessary because LatinIME is bookkeeping to avoid confusing a real cursor
99        // move with a move triggered by LatinIME inputting stuff.
100        mLatinIME.onUpdateSelection(0, 0, typedLength, typedLength, -1, -1);
101        mInputConnection.setSelection(SELECTION_START, SELECTION_END);
102        // And now we simulate the user actually selecting some text.
103        mLatinIME.onUpdateSelection(typedLength, typedLength,
104                SELECTION_START, SELECTION_END, -1, -1);
105        type(Constants.CODE_DELETE);
106        assertEquals("delete selection", EXPECTED_RESULT, mEditText.getText().toString());
107    }
108
109    public void testDeleteSelectionTwice() {
110        final String STRING_TO_TYPE = "some text delete me some text";
111        final int typedLength = STRING_TO_TYPE.length();
112        final int SELECTION_START = 10;
113        final int SELECTION_END = 19;
114        final String EXPECTED_RESULT = "some text some text";
115        type(STRING_TO_TYPE);
116        // There is no IMF to call onUpdateSelection for us so we must do it by hand.
117        // Send once to simulate the cursor actually responding to the move caused by typing.
118        // This is necessary because LatinIME is bookkeeping to avoid confusing a real cursor
119        // move with a move triggered by LatinIME inputting stuff.
120        mLatinIME.onUpdateSelection(0, 0, typedLength, typedLength, -1, -1);
121        mInputConnection.setSelection(SELECTION_START, SELECTION_END);
122        // And now we simulate the user actually selecting some text.
123        mLatinIME.onUpdateSelection(typedLength, typedLength,
124                SELECTION_START, SELECTION_END, -1, -1);
125        type(Constants.CODE_DELETE);
126        type(Constants.CODE_DELETE);
127        assertEquals("delete selection twice", EXPECTED_RESULT, mEditText.getText().toString());
128    }
129
130    public void testAutoCorrect() {
131        final String STRING_TO_TYPE = "tgis ";
132        final String EXPECTED_RESULT = "this ";
133        type(STRING_TO_TYPE);
134        assertEquals("simple auto-correct", EXPECTED_RESULT, mEditText.getText().toString());
135    }
136
137    public void testAutoCorrectWithQuote() {
138        final String STRING_TO_TYPE = "didn' ";
139        final String EXPECTED_RESULT = "didn't ";
140        type(STRING_TO_TYPE);
141        assertEquals("auto-correct with quote", EXPECTED_RESULT, mEditText.getText().toString());
142    }
143
144    public void testAutoCorrectWithPeriod() {
145        final String STRING_TO_TYPE = "tgis.";
146        final String EXPECTED_RESULT = "this.";
147        type(STRING_TO_TYPE);
148        assertEquals("auto-correct with period", EXPECTED_RESULT, mEditText.getText().toString());
149    }
150
151    public void testAutoCorrectWithPeriodThenRevert() {
152        final String STRING_TO_TYPE = "tgis.";
153        final String EXPECTED_RESULT = "tgis.";
154        type(STRING_TO_TYPE);
155        mLatinIME.onUpdateSelection(0, 0, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1);
156        type(Constants.CODE_DELETE);
157        assertEquals("auto-correct with period then revert", EXPECTED_RESULT,
158                mEditText.getText().toString());
159    }
160
161    public void testAutoCorrectWithSpaceThenRevert() {
162        final String STRING_TO_TYPE = "tgis ";
163        final String EXPECTED_RESULT = "tgis ";
164        type(STRING_TO_TYPE);
165        mLatinIME.onUpdateSelection(0, 0, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1);
166        type(Constants.CODE_DELETE);
167        assertEquals("auto-correct with space then revert", EXPECTED_RESULT,
168                mEditText.getText().toString());
169    }
170
171    public void testAutoCorrectToSelfDoesNotRevert() {
172        final String STRING_TO_TYPE = "this ";
173        final String EXPECTED_RESULT = "this";
174        type(STRING_TO_TYPE);
175        mLatinIME.onUpdateSelection(0, 0, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1);
176        type(Constants.CODE_DELETE);
177        assertEquals("auto-correct with space does not revert", EXPECTED_RESULT,
178                mEditText.getText().toString());
179    }
180
181    public void testDoubleSpace() {
182        // Set default pref just in case
183        setBooleanPreference(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true, true);
184        // U+1F607 is an emoji
185        final String[] STRINGS_TO_TYPE =
186                new String[] { "this   ", "a+  ", "\u1F607  ", "..  ", ")  ", "(  ", "%  " };
187        final String[] EXPECTED_RESULTS =
188                new String[] { "this.  ", "a+. ", "\u1F607. ", "..  ", "). ", "(  ", "%. " };
189        for (int i = 0; i < STRINGS_TO_TYPE.length; ++i) {
190            mEditText.setText("");
191            type(STRINGS_TO_TYPE[i]);
192            assertEquals("double space processing", EXPECTED_RESULTS[i],
193                    mEditText.getText().toString());
194        }
195    }
196
197    public void testCancelDoubleSpace() {
198        final String STRING_TO_TYPE = "this  ";
199        final String EXPECTED_RESULT = "this ";
200        type(STRING_TO_TYPE);
201        type(Constants.CODE_DELETE);
202        assertEquals("double space make a period", EXPECTED_RESULT, mEditText.getText().toString());
203    }
204
205    private void testDoubleSpacePeriodWithSettings(final boolean expectsPeriod,
206            final Object... settingsKeysValues) {
207        final Object[] oldSettings = new Object[settingsKeysValues.length / 2];
208        final String STRING_WITHOUT_PERIOD = "this  ";
209        final String STRING_WITH_PERIOD = "this. ";
210        final String EXPECTED_RESULT = expectsPeriod ? STRING_WITH_PERIOD : STRING_WITHOUT_PERIOD;
211        try {
212            for (int i = 0; i < settingsKeysValues.length; i += 2) {
213                if (settingsKeysValues[i + 1] instanceof String) {
214                    oldSettings[i / 2] = setStringPreference((String)settingsKeysValues[i],
215                            (String)settingsKeysValues[i + 1], "0");
216                } else {
217                    oldSettings[i / 2] = setBooleanPreference((String)settingsKeysValues[i],
218                            (Boolean)settingsKeysValues[i + 1], false);
219                }
220            }
221            mLatinIME.loadSettings();
222            mEditText.setText("");
223            type(STRING_WITHOUT_PERIOD);
224            assertEquals("double-space-to-period with specific settings "
225                    + TextUtils.join(" ", settingsKeysValues),
226                    EXPECTED_RESULT, mEditText.getText().toString());
227        } finally {
228            // Restore old settings
229            for (int i = 0; i < settingsKeysValues.length; i += 2) {
230                if (null == oldSettings[i / 2]) {
231                    break;
232                } if (oldSettings[i / 2] instanceof String) {
233                    setStringPreference((String)settingsKeysValues[i], (String)oldSettings[i / 2],
234                            "");
235                } else {
236                    setBooleanPreference((String)settingsKeysValues[i], (Boolean)oldSettings[i / 2],
237                            false);
238                }
239            }
240        }
241    }
242
243    public void testDoubleSpacePeriod() {
244        // Reset settings to default, else these tests will go flaky.
245        setBooleanPreference(Settings.PREF_SHOW_SUGGESTIONS, true, true);
246        setStringPreference(Settings.PREF_AUTO_CORRECTION_THRESHOLD, "1", "1");
247        setBooleanPreference(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true, true);
248        testDoubleSpacePeriodWithSettings(true /* expectsPeriod */);
249        // "Suggestion visibility" to off
250        testDoubleSpacePeriodWithSettings(true, Settings.PREF_SHOW_SUGGESTIONS, false);
251        // "Suggestion visibility" to on
252        testDoubleSpacePeriodWithSettings(true, Settings.PREF_SHOW_SUGGESTIONS, true);
253
254        // "Double-space period" to "off"
255        testDoubleSpacePeriodWithSettings(false, Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, false);
256
257        // "Auto-correction" to "off"
258        testDoubleSpacePeriodWithSettings(true, Settings.PREF_AUTO_CORRECTION_THRESHOLD, "0");
259        // "Auto-correction" to "modest"
260        testDoubleSpacePeriodWithSettings(true, Settings.PREF_AUTO_CORRECTION_THRESHOLD, "1");
261        // "Auto-correction" to "very aggressive"
262        testDoubleSpacePeriodWithSettings(true, Settings.PREF_AUTO_CORRECTION_THRESHOLD, "3");
263
264        // "Suggestion visibility" to "always hide" and "Auto-correction" to "off"
265        testDoubleSpacePeriodWithSettings(true, Settings.PREF_SHOW_SUGGESTIONS, false,
266                Settings.PREF_AUTO_CORRECTION_THRESHOLD, "0");
267        // "Suggestion visibility" to "always hide" and "Auto-correction" to "off"
268        testDoubleSpacePeriodWithSettings(false, Settings.PREF_SHOW_SUGGESTIONS, false,
269                Settings.PREF_AUTO_CORRECTION_THRESHOLD, "0",
270                Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, false);
271    }
272
273    public void testBackspaceAtStartAfterAutocorrect() {
274        final String STRING_TO_TYPE = "tgis ";
275        final int typedLength = STRING_TO_TYPE.length();
276        final String EXPECTED_RESULT = "this ";
277        final int NEW_CURSOR_POSITION = 0;
278        type(STRING_TO_TYPE);
279        mLatinIME.onUpdateSelection(0, 0, typedLength, typedLength, -1, -1);
280        mInputConnection.setSelection(NEW_CURSOR_POSITION, NEW_CURSOR_POSITION);
281        mLatinIME.onUpdateSelection(typedLength, typedLength,
282                NEW_CURSOR_POSITION, NEW_CURSOR_POSITION, -1, -1);
283        type(Constants.CODE_DELETE);
284        assertEquals("auto correct then move cursor to start of line then backspace",
285                EXPECTED_RESULT, mEditText.getText().toString());
286    }
287
288    public void testAutoCorrectThenMoveCursorThenBackspace() {
289        final String STRING_TO_TYPE = "and tgis ";
290        final int typedLength = STRING_TO_TYPE.length();
291        final String EXPECTED_RESULT = "andthis ";
292        final int NEW_CURSOR_POSITION = STRING_TO_TYPE.indexOf('t');
293        type(STRING_TO_TYPE);
294        mLatinIME.onUpdateSelection(0, 0, typedLength, typedLength, -1, -1);
295        mInputConnection.setSelection(NEW_CURSOR_POSITION, NEW_CURSOR_POSITION);
296        mLatinIME.onUpdateSelection(typedLength, typedLength,
297                NEW_CURSOR_POSITION, NEW_CURSOR_POSITION, -1, -1);
298        type(Constants.CODE_DELETE);
299        assertEquals("auto correct then move cursor then backspace",
300                EXPECTED_RESULT, mEditText.getText().toString());
301    }
302
303    public void testNoSpaceAfterManualPick() {
304        final String WORD_TO_TYPE = "this";
305        final String EXPECTED_RESULT = WORD_TO_TYPE;
306        type(WORD_TO_TYPE);
307        pickSuggestionManually(WORD_TO_TYPE);
308        assertEquals("no space after manual pick", EXPECTED_RESULT,
309                mEditText.getText().toString());
310    }
311
312    public void testManualPickThenType() {
313        final String WORD1_TO_TYPE = "this";
314        final String WORD2_TO_TYPE = "is";
315        final String EXPECTED_RESULT = "this is";
316        type(WORD1_TO_TYPE);
317        pickSuggestionManually(WORD1_TO_TYPE);
318        type(WORD2_TO_TYPE);
319        assertEquals("manual pick then type", EXPECTED_RESULT, mEditText.getText().toString());
320    }
321
322    public void testManualPickThenSeparator() {
323        final String WORD1_TO_TYPE = "this";
324        final String WORD2_TO_TYPE = "!";
325        final String EXPECTED_RESULT = "this!";
326        type(WORD1_TO_TYPE);
327        pickSuggestionManually(WORD1_TO_TYPE);
328        type(WORD2_TO_TYPE);
329        assertEquals("manual pick then separator", EXPECTED_RESULT, mEditText.getText().toString());
330    }
331
332    // This test matches the one in InputLogicTestsNonEnglish. In some non-English languages,
333    // ! and ? are clustering punctuation signs.
334    public void testClusteringPunctuation() {
335        final String WORD1_TO_TYPE = "test";
336        final String WORD2_TO_TYPE = "!!?!:!";
337        final String EXPECTED_RESULT = "test!!?!:!";
338        type(WORD1_TO_TYPE);
339        pickSuggestionManually(WORD1_TO_TYPE);
340        type(WORD2_TO_TYPE);
341        assertEquals("clustering punctuation", EXPECTED_RESULT, mEditText.getText().toString());
342    }
343
344    public void testManualPickThenStripperThenPick() {
345        final String WORD_TO_TYPE = "this";
346        final String STRIPPER = "\n";
347        final String EXPECTED_RESULT = "this\nthis";
348        type(WORD_TO_TYPE);
349        pickSuggestionManually(WORD_TO_TYPE);
350        type(STRIPPER);
351        type(WORD_TO_TYPE);
352        pickSuggestionManually(WORD_TO_TYPE);
353        assertEquals("manual pick then \\n then manual pick", EXPECTED_RESULT,
354                mEditText.getText().toString());
355    }
356
357    public void testManualPickThenSpaceThenType() {
358        final String WORD1_TO_TYPE = "this";
359        final String WORD2_TO_TYPE = " is";
360        final String EXPECTED_RESULT = "this is";
361        type(WORD1_TO_TYPE);
362        pickSuggestionManually(WORD1_TO_TYPE);
363        type(WORD2_TO_TYPE);
364        assertEquals("manual pick then space then type", EXPECTED_RESULT,
365                mEditText.getText().toString());
366    }
367
368    public void testManualPickThenManualPick() {
369        final String WORD1_TO_TYPE = "this";
370        final String WORD2_TO_PICK = "is";
371        final String EXPECTED_RESULT = "this is";
372        type(WORD1_TO_TYPE);
373        pickSuggestionManually(WORD1_TO_TYPE);
374        // Here we fake picking a word through bigram prediction.
375        pickSuggestionManually(WORD2_TO_PICK);
376        assertEquals("manual pick then manual pick", EXPECTED_RESULT,
377                mEditText.getText().toString());
378    }
379
380    public void testDeleteWholeComposingWord() {
381        final String WORD_TO_TYPE = "this";
382        type(WORD_TO_TYPE);
383        for (int i = 0; i < WORD_TO_TYPE.length(); ++i) {
384            type(Constants.CODE_DELETE);
385        }
386        assertEquals("delete whole composing word", "", mEditText.getText().toString());
387    }
388
389    public void testResumeSuggestionOnBackspace() {
390        final String STRING_TO_TYPE = "and this ";
391        final int typedLength = STRING_TO_TYPE.length();
392        type(STRING_TO_TYPE);
393        assertEquals("resume suggestion on backspace", -1,
394                BaseInputConnection.getComposingSpanStart(mEditText.getText()));
395        assertEquals("resume suggestion on backspace", -1,
396                BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
397        mLatinIME.onUpdateSelection(0, 0, typedLength, typedLength, -1, -1);
398        type(Constants.CODE_DELETE);
399        assertEquals("resume suggestion on backspace", 4,
400                BaseInputConnection.getComposingSpanStart(mEditText.getText()));
401        assertEquals("resume suggestion on backspace", 8,
402                BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
403    }
404
405    private void helperTestComposing(final String wordToType, final boolean shouldBeComposing) {
406        mEditText.setText("");
407        type(wordToType);
408        assertEquals("start composing inside text", shouldBeComposing ? 0 : -1,
409                BaseInputConnection.getComposingSpanStart(mEditText.getText()));
410        assertEquals("start composing inside text", shouldBeComposing ? wordToType.length() : -1,
411                BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
412    }
413
414    public void testStartComposing() {
415        // Should start composing on a letter
416        helperTestComposing("a", true);
417        type("  "); // To reset the composing state
418        // Should not start composing on quote
419        helperTestComposing("'", false);
420        type("  ");
421        helperTestComposing("'-", false);
422        type("  ");
423        // Should not start composing on dash
424        helperTestComposing("-", false);
425        type("  ");
426        helperTestComposing("-'", false);
427        type("  ");
428        helperTestComposing("a-", true);
429        type("  ");
430        helperTestComposing("a'", true);
431    }
432    // TODO: Add some tests for non-BMP characters
433
434    public void testAutoCorrectByUserHistory() {
435        final String WORD_TO_BE_CORRECTED = "qpmx";
436        final String NOT_CORRECTED_RESULT = "qpmx ";
437        final String DESIRED_WORD = "qpmz";
438        final String CORRECTED_RESULT = "qpmz ";
439        final int typeCountNotToAutocorrect = 1;
440        final int typeCountToAutoCorrect = 16;
441        int startIndex = 0;
442        int endIndex = 0;
443
444        for (int i = 0; i < typeCountNotToAutocorrect; i++) {
445            type(DESIRED_WORD);
446            type(Constants.CODE_SPACE);
447        }
448        startIndex = mEditText.getText().length();
449        type(WORD_TO_BE_CORRECTED);
450        type(Constants.CODE_SPACE);
451        endIndex = mEditText.getText().length();
452        assertEquals("not auto-corrected by user history", NOT_CORRECTED_RESULT,
453                mEditText.getText().subSequence(startIndex, endIndex).toString());
454        for (int i = typeCountNotToAutocorrect; i < typeCountToAutoCorrect; i++) {
455            type(DESIRED_WORD);
456            type(Constants.CODE_SPACE);
457        }
458        startIndex = mEditText.getText().length();
459        type(WORD_TO_BE_CORRECTED);
460        type(Constants.CODE_SPACE);
461        endIndex = mEditText.getText().length();
462        assertEquals("auto-corrected by user history",
463                CORRECTED_RESULT, mEditText.getText().subSequence(startIndex, endIndex).toString());
464    }
465
466    public void testPredictionsAfterSpace() {
467        final String WORD_TO_TYPE = "Barack ";
468        type(WORD_TO_TYPE);
469        sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
470        runMessages();
471        // Test the first prediction is displayed
472        final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
473        assertEquals("predictions after space", "Obama",
474                suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null);
475    }
476
477    public void testPredictionsWithDoubleSpaceToPeriod() {
478        mLatinIME.clearPersonalizedDictionariesForTest();
479        final String WORD_TO_TYPE = "Barack ";
480        type(WORD_TO_TYPE);
481        sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
482        runMessages();
483        // No need to test here, testPredictionsAfterSpace is testing it already
484        type(" ");
485        sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
486        runMessages();
487        // Test the predictions have been cleared
488        SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
489        assertEquals("predictions cleared after double-space-to-period", suggestedWords.size(), 0);
490        type(Constants.CODE_DELETE);
491        sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
492        runMessages();
493        // Test the first prediction is displayed
494        suggestedWords = mLatinIME.getSuggestedWordsForTest();
495        assertEquals("predictions after cancel double-space-to-period", "Obama",
496                suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null);
497    }
498
499    public void testPredictionsAfterManualPick() {
500        final String WORD_TO_TYPE = "Barack";
501        type(WORD_TO_TYPE);
502        // Choose the auto-correction. For "Barack", the auto-correction should be "Barack".
503        pickSuggestionManually(WORD_TO_TYPE);
504        sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
505        runMessages();
506        // Test the first prediction is displayed
507        final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
508        assertEquals("predictions after manual pick", "Obama",
509                suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null);
510    }
511
512    public void testPredictionsAfterPeriod() {
513        mLatinIME.clearPersonalizedDictionariesForTest();
514        final String WORD_TO_TYPE = "Barack. ";
515        type(WORD_TO_TYPE);
516        sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
517        runMessages();
518        SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
519        assertEquals("No prediction after period after inputting once.", 0, suggestedWords.size());
520
521        type(WORD_TO_TYPE);
522        sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
523        runMessages();
524        suggestedWords = mLatinIME.getSuggestedWordsForTest();
525        assertEquals("Beginning-of-Sentence prediction after inputting 2 times.", "Barack",
526                suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null);
527    }
528
529    public void testPredictionsAfterRecorrection() {
530        final String PREFIX = "A ";
531        final String WORD_TO_TYPE = "Barack";
532        final String FIRST_NON_TYPED_SUGGESTION = "Barrack";
533        final int endOfPrefix = PREFIX.length();
534        final int endOfWord = endOfPrefix + WORD_TO_TYPE.length();
535        final int endOfSuggestion = endOfPrefix + FIRST_NON_TYPED_SUGGESTION.length();
536        final int indexForManualCursor = endOfPrefix + 3; // +3 because it's after "Bar" in "Barack"
537        type(PREFIX);
538        mLatinIME.onUpdateSelection(0, 0, endOfPrefix, endOfPrefix, -1, -1);
539        type(WORD_TO_TYPE);
540        pickSuggestionManually(FIRST_NON_TYPED_SUGGESTION);
541        mLatinIME.onUpdateSelection(endOfPrefix, endOfPrefix, endOfSuggestion, endOfSuggestion,
542                -1, -1);
543        runMessages();
544        type(" ");
545        mLatinIME.onUpdateSelection(endOfSuggestion, endOfSuggestion,
546                endOfSuggestion + 1, endOfSuggestion + 1, -1, -1);
547        sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
548        runMessages();
549        // Simulate a manual cursor move
550        mInputConnection.setSelection(indexForManualCursor, indexForManualCursor);
551        mLatinIME.onUpdateSelection(endOfSuggestion + 1, endOfSuggestion + 1,
552                indexForManualCursor, indexForManualCursor, -1, -1);
553        sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
554        runMessages();
555        pickSuggestionManually(WORD_TO_TYPE);
556        mLatinIME.onUpdateSelection(indexForManualCursor, indexForManualCursor,
557                endOfWord, endOfWord, -1, -1);
558        sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
559        runMessages();
560        // Test the first prediction is displayed
561        final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
562        assertEquals("predictions after recorrection", "Obama",
563                suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null);
564    }
565
566    public void testComposingMultipleBackspace() {
567        final String WORD_TO_TYPE = "radklro";
568        final int TIMES_TO_TYPE = 3;
569        final int TIMES_TO_BACKSPACE = 8;
570        type(WORD_TO_TYPE);
571        type(Constants.CODE_DELETE);
572        type(Constants.CODE_DELETE);
573        type(Constants.CODE_DELETE);
574        type(WORD_TO_TYPE);
575        type(Constants.CODE_DELETE);
576        type(Constants.CODE_DELETE);
577        type(WORD_TO_TYPE);
578        type(Constants.CODE_DELETE);
579        type(Constants.CODE_DELETE);
580        type(Constants.CODE_DELETE);
581        assertEquals("composing with multiple backspace",
582                WORD_TO_TYPE.length() * TIMES_TO_TYPE - TIMES_TO_BACKSPACE,
583                mEditText.getText().length());
584    }
585
586    public void testManySingleQuotes() {
587        final String WORD_TO_AUTOCORRECT = "i";
588        final String WORD_AUTOCORRECTED = "I";
589        final String QUOTES = "''''''''''''''''''''";
590        final String WORD_TO_TYPE = WORD_TO_AUTOCORRECT + QUOTES + " ";
591        final String EXPECTED_RESULT = WORD_AUTOCORRECTED + QUOTES + " ";
592        type(WORD_TO_TYPE);
593        assertEquals("auto-correct with many trailing single quotes", EXPECTED_RESULT,
594                mEditText.getText().toString());
595    }
596
597    public void testManySingleQuotesOneByOne() {
598        final String WORD_TO_AUTOCORRECT = "i";
599        final String WORD_AUTOCORRECTED = "I";
600        final String QUOTES = "''''''''''''''''''''";
601        final String WORD_TO_TYPE = WORD_TO_AUTOCORRECT + QUOTES + " ";
602        final String EXPECTED_RESULT = WORD_AUTOCORRECTED + QUOTES + " ";
603
604        for (int i = 0; i < WORD_TO_TYPE.length(); ++i) {
605            type(WORD_TO_TYPE.substring(i, i+1));
606            sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
607            runMessages();
608        }
609        assertEquals("type many trailing single quotes one by one", EXPECTED_RESULT,
610                mEditText.getText().toString());
611    }
612
613    public void testTypingSingleQuotesOneByOne() {
614        final String WORD_TO_TYPE = "it's ";
615        final String EXPECTED_RESULT = WORD_TO_TYPE;
616        for (int i = 0; i < WORD_TO_TYPE.length(); ++i) {
617            type(WORD_TO_TYPE.substring(i, i+1));
618            sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
619            runMessages();
620        }
621        assertEquals("type words letter by letter", EXPECTED_RESULT,
622                mEditText.getText().toString());
623    }
624
625    public void testSwitchLanguages() {
626        final String WORD_TO_TYPE_FIRST_PART = "com";
627        final String WORD_TO_TYPE_SECOND_PART = "md";
628        final String EXPECTED_RESULT = "comme";
629        changeLanguage("en");
630        type(WORD_TO_TYPE_FIRST_PART);
631        changeLanguage("fr");
632        runMessages();
633        type(WORD_TO_TYPE_SECOND_PART);
634        sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
635        runMessages();
636        final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
637        assertEquals("Suggestions updated after switching languages",
638                    EXPECTED_RESULT, suggestedWords.size() > 0 ? suggestedWords.getWord(1) : null);
639    }
640}
641