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 static android.test.MoreAsserts.assertNotEqual;
     20 
     21 import android.test.suitebuilder.annotation.LargeTest;
     22 import android.text.TextUtils;
     23 import android.view.inputmethod.BaseInputConnection;
     24 
     25 import com.android.inputmethod.latin.common.Constants;
     26 import com.android.inputmethod.latin.define.DecoderSpecificConstants;
     27 import com.android.inputmethod.latin.settings.Settings;
     28 
     29 @LargeTest
     30 public class InputLogicTests extends InputTestsBase {
     31 
     32     private boolean mNextWordPrediction;
     33 
     34     @Override
     35     public void setUp() throws Exception {
     36         super.setUp();
     37         mNextWordPrediction = getBooleanPreference(Settings.PREF_BIGRAM_PREDICTIONS, true);
     38     }
     39 
     40     @Override
     41     public void tearDown() throws Exception {
     42         setBooleanPreference(Settings.PREF_BIGRAM_PREDICTIONS, mNextWordPrediction, true);
     43         super.tearDown();
     44     }
     45 
     46     public void testTypeWord() {
     47         final String WORD_TO_TYPE = "abcd";
     48         type(WORD_TO_TYPE);
     49         assertEquals("type word", WORD_TO_TYPE, mEditText.getText().toString());
     50     }
     51 
     52     public void testPickSuggestionThenBackspace() {
     53         final String WORD_TO_TYPE = "this";
     54         final String EXPECTED_RESULT = "thi";
     55         type(WORD_TO_TYPE);
     56         pickSuggestionManually(WORD_TO_TYPE);
     57         sendUpdateForCursorMoveTo(WORD_TO_TYPE.length());
     58         type(Constants.CODE_DELETE);
     59         assertEquals("press suggestion then backspace", EXPECTED_RESULT,
     60                 mEditText.getText().toString());
     61     }
     62 
     63     public void testPickAutoCorrectionThenBackspace() {
     64         final String WORD_TO_TYPE = "tgis";
     65         final String WORD_TO_PICK = "this";
     66         final String EXPECTED_RESULT = "thi";
     67         type(WORD_TO_TYPE);
     68         // Choose the auto-correction. For "tgis", the auto-correction should be "this".
     69         pickSuggestionManually(WORD_TO_PICK);
     70         sendUpdateForCursorMoveTo(WORD_TO_TYPE.length());
     71         assertEquals("pick typed word over auto-correction then backspace", WORD_TO_PICK,
     72                 mEditText.getText().toString());
     73         type(Constants.CODE_DELETE);
     74         assertEquals("pick typed word over auto-correction then backspace", EXPECTED_RESULT,
     75                 mEditText.getText().toString());
     76     }
     77 
     78     public void testPickTypedWordOverAutoCorrectionThenBackspace() {
     79         final String WORD_TO_TYPE = "tgis";
     80         final String EXPECTED_RESULT = "tgi";
     81         type(WORD_TO_TYPE);
     82         // Choose the typed word.
     83         pickSuggestionManually(WORD_TO_TYPE);
     84         sendUpdateForCursorMoveTo(WORD_TO_TYPE.length());
     85         assertEquals("pick typed word over auto-correction then backspace", WORD_TO_TYPE,
     86                 mEditText.getText().toString());
     87         type(Constants.CODE_DELETE);
     88         assertEquals("pick typed word over auto-correction then backspace", EXPECTED_RESULT,
     89                 mEditText.getText().toString());
     90     }
     91 
     92     public void testPickDifferentSuggestionThenBackspace() {
     93         final String WORD_TO_TYPE = "tgis";
     94         final String WORD_TO_PICK = "thus";
     95         final String EXPECTED_RESULT = "thu";
     96         type(WORD_TO_TYPE);
     97         // Choose the second suggestion, which should be "thus" when "tgis" is typed.
     98         pickSuggestionManually(WORD_TO_PICK);
     99         sendUpdateForCursorMoveTo(WORD_TO_TYPE.length());
    100         assertEquals("pick different suggestion then backspace", WORD_TO_PICK,
    101                 mEditText.getText().toString());
    102         type(Constants.CODE_DELETE);
    103         assertEquals("pick different suggestion then backspace", EXPECTED_RESULT,
    104                 mEditText.getText().toString());
    105     }
    106 
    107     public void testDeleteSelection() {
    108         final String STRING_TO_TYPE = "some text delete me some text";
    109         final int typedLength = STRING_TO_TYPE.length();
    110         final int SELECTION_START = 10;
    111         final int SELECTION_END = 19;
    112         final String EXPECTED_RESULT = "some text  some text";
    113         type(STRING_TO_TYPE);
    114         // Don't use the sendUpdateForCursorMove* family of methods here because they
    115         // don't handle selections.
    116         // Send once to simulate the cursor actually responding to the move caused by typing.
    117         // This is necessary because LatinIME is bookkeeping to avoid confusing a real cursor
    118         // move with a move triggered by LatinIME inputting stuff.
    119         mLatinIME.onUpdateSelection(0, 0, typedLength, typedLength, -1, -1);
    120         mInputConnection.setSelection(SELECTION_START, SELECTION_END);
    121         // And now we simulate the user actually selecting some text.
    122         mLatinIME.onUpdateSelection(typedLength, typedLength,
    123                 SELECTION_START, SELECTION_END, -1, -1);
    124         type(Constants.CODE_DELETE);
    125         assertEquals("delete selection", EXPECTED_RESULT, mEditText.getText().toString());
    126     }
    127 
    128     public void testDeleteSelectionTwice() {
    129         final String STRING_TO_TYPE = "some text delete me some text";
    130         final int typedLength = STRING_TO_TYPE.length();
    131         final int SELECTION_START = 10;
    132         final int SELECTION_END = 19;
    133         final String EXPECTED_RESULT = "some text some text";
    134         type(STRING_TO_TYPE);
    135         // Don't use the sendUpdateForCursorMove* family of methods here because they
    136         // don't handle selections.
    137         // Send once to simulate the cursor actually responding to the move caused by typing.
    138         // This is necessary because LatinIME is bookkeeping to avoid confusing a real cursor
    139         // move with a move triggered by LatinIME inputting stuff.
    140         mLatinIME.onUpdateSelection(0, 0, typedLength, typedLength, -1, -1);
    141         mInputConnection.setSelection(SELECTION_START, SELECTION_END);
    142         // And now we simulate the user actually selecting some text.
    143         mLatinIME.onUpdateSelection(typedLength, typedLength,
    144                 SELECTION_START, SELECTION_END, -1, -1);
    145         type(Constants.CODE_DELETE);
    146         type(Constants.CODE_DELETE);
    147         assertEquals("delete selection twice", EXPECTED_RESULT, mEditText.getText().toString());
    148     }
    149 
    150     public void testAutoCorrect() {
    151         final String STRING_TO_TYPE = "tgis ";
    152         final String EXPECTED_RESULT = "this ";
    153         type(STRING_TO_TYPE);
    154         assertEquals("simple auto-correct", EXPECTED_RESULT, mEditText.getText().toString());
    155     }
    156 
    157     public void testAutoCorrectWithQuote() {
    158         final String STRING_TO_TYPE = "didn' ";
    159         final String EXPECTED_RESULT = "didn't ";
    160         type(STRING_TO_TYPE);
    161         assertEquals("auto-correct with quote", EXPECTED_RESULT, mEditText.getText().toString());
    162     }
    163 
    164     public void testAutoCorrectWithPeriod() {
    165         final String STRING_TO_TYPE = "tgis.";
    166         final String EXPECTED_RESULT = "this.";
    167         type(STRING_TO_TYPE);
    168         assertEquals("auto-correct with period", EXPECTED_RESULT, mEditText.getText().toString());
    169     }
    170 
    171     public void testAutoCorrectWithPeriodThenRevert() {
    172         final String STRING_TO_TYPE = "tgis.";
    173         final String EXPECTED_RESULT = "tgis.";
    174         type(STRING_TO_TYPE);
    175         sendUpdateForCursorMoveTo(STRING_TO_TYPE.length());
    176         type(Constants.CODE_DELETE);
    177         assertEquals("auto-correct with period then revert", EXPECTED_RESULT,
    178                 mEditText.getText().toString());
    179     }
    180 
    181     public void testAutoCorrectWithSpaceThenRevert() {
    182         // Backspacing to cancel the "tgis"->"this" autocorrection should result in
    183         // a "phantom space": if the user presses space immediately after,
    184         // only one space will be inserted in total.
    185         final String STRING_TO_TYPE = "tgis ";
    186         final String EXPECTED_RESULT = "tgis";
    187         type(STRING_TO_TYPE);
    188         sendUpdateForCursorMoveTo(STRING_TO_TYPE.length());
    189         type(Constants.CODE_DELETE);
    190         assertEquals("auto-correct with space then revert", EXPECTED_RESULT,
    191                 mEditText.getText().toString());
    192     }
    193 
    194     public void testAutoCorrectWithSpaceThenRevertThenTypeMore() {
    195         final String STRING_TO_TYPE_FIRST = "tgis ";
    196         final String STRING_TO_TYPE_SECOND = "a";
    197         final String EXPECTED_RESULT = "tgis a";
    198         type(STRING_TO_TYPE_FIRST);
    199         sendUpdateForCursorMoveTo(STRING_TO_TYPE_FIRST.length());
    200         type(Constants.CODE_DELETE);
    201 
    202         type(STRING_TO_TYPE_SECOND);
    203         sendUpdateForCursorMoveTo(STRING_TO_TYPE_FIRST.length() - 1
    204                 + STRING_TO_TYPE_SECOND.length());
    205         assertEquals("auto-correct with space then revert then type more", EXPECTED_RESULT,
    206                 mEditText.getText().toString());
    207     }
    208 
    209     public void testAutoCorrectToSelfDoesNotRevert() {
    210         final String STRING_TO_TYPE = "this ";
    211         final String EXPECTED_RESULT = "this";
    212         type(STRING_TO_TYPE);
    213         sendUpdateForCursorMoveTo(STRING_TO_TYPE.length());
    214         type(Constants.CODE_DELETE);
    215         assertEquals("auto-correct with space does not revert", EXPECTED_RESULT,
    216                 mEditText.getText().toString());
    217     }
    218 
    219     public void testDoubleSpace() {
    220         // U+1F607 is an emoji
    221         final String[] STRINGS_TO_TYPE =
    222                 new String[] { "this   ", "a+  ", "\u1F607  ", "..  ", ")  ", "(  ", "%  " };
    223         final String[] EXPECTED_RESULTS =
    224                 new String[] { "this.  ", "a+. ", "\u1F607. ", "..  ", "). ", "(  ", "%. " };
    225         verifyDoubleSpace(STRINGS_TO_TYPE, EXPECTED_RESULTS);
    226     }
    227 
    228     public void testDoubleSpaceHindi() {
    229         changeLanguage("hi");
    230         // U+1F607 is an emoji
    231         final String[] STRINGS_TO_TYPE =
    232                 new String[] { "this   ", "a+  ", "\u1F607  ", "||  ", ")  ", "(  ", "%  " };
    233         final String[] EXPECTED_RESULTS =
    234                 new String[] { "this|  ", "a+| ", "\u1F607| ", "||  ", ")| ", "(  ", "%| " };
    235         verifyDoubleSpace(STRINGS_TO_TYPE, EXPECTED_RESULTS);
    236     }
    237 
    238     private void verifyDoubleSpace(String[] stringsToType, String[] expectedResults) {
    239         // Set default pref just in case
    240         setBooleanPreference(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true, true);
    241         for (int i = 0; i < stringsToType.length; ++i) {
    242             mEditText.setText("");
    243             type(stringsToType[i]);
    244             assertEquals("double space processing", expectedResults[i],
    245                     mEditText.getText().toString());
    246         }
    247     }
    248 
    249     public void testCancelDoubleSpaceEnglish() {
    250         final String STRING_TO_TYPE = "this  ";
    251         final String EXPECTED_RESULT = "this ";
    252         type(STRING_TO_TYPE);
    253         type(Constants.CODE_DELETE);
    254         assertEquals("double space make a period", EXPECTED_RESULT, mEditText.getText().toString());
    255     }
    256 
    257     public void testCancelDoubleSpaceHindi() {
    258         changeLanguage("hi");
    259         final String STRING_TO_TYPE = "this  ";
    260         final String EXPECTED_RESULT = "this ";
    261         type(STRING_TO_TYPE);
    262         type(Constants.CODE_DELETE);
    263         assertEquals("double space make a period", EXPECTED_RESULT, mEditText.getText().toString());
    264     }
    265 
    266     private void testDoubleSpacePeriodWithSettings(final boolean expectsPeriod,
    267             final Object... settingsKeysValues) {
    268         final Object[] oldSettings = new Object[settingsKeysValues.length / 2];
    269         final String STRING_WITHOUT_PERIOD = "this  ";
    270         final String STRING_WITH_PERIOD = "this. ";
    271         final String EXPECTED_RESULT = expectsPeriod ? STRING_WITH_PERIOD : STRING_WITHOUT_PERIOD;
    272         try {
    273             for (int i = 0; i < settingsKeysValues.length; i += 2) {
    274                 if (settingsKeysValues[i + 1] instanceof String) {
    275                     oldSettings[i / 2] = setStringPreference((String)settingsKeysValues[i],
    276                             (String)settingsKeysValues[i + 1], "0");
    277                 } else {
    278                     oldSettings[i / 2] = setBooleanPreference((String)settingsKeysValues[i],
    279                             (Boolean)settingsKeysValues[i + 1], false);
    280                 }
    281             }
    282             mLatinIME.loadSettings();
    283             mEditText.setText("");
    284             type(STRING_WITHOUT_PERIOD);
    285             assertEquals("double-space-to-period with specific settings "
    286                     + TextUtils.join(" ", settingsKeysValues),
    287                     EXPECTED_RESULT, mEditText.getText().toString());
    288         } finally {
    289             // Restore old settings
    290             for (int i = 0; i < settingsKeysValues.length; i += 2) {
    291                 if (null == oldSettings[i / 2]) {
    292                     break;
    293                 } if (oldSettings[i / 2] instanceof String) {
    294                     setStringPreference((String)settingsKeysValues[i], (String)oldSettings[i / 2],
    295                             "");
    296                 } else {
    297                     setBooleanPreference((String)settingsKeysValues[i], (Boolean)oldSettings[i / 2],
    298                             false);
    299                 }
    300             }
    301         }
    302     }
    303 
    304     public void testDoubleSpacePeriod() {
    305         // Reset settings to default, else these tests will go flaky.
    306         setBooleanPreference(Settings.PREF_SHOW_SUGGESTIONS, true, true);
    307         setBooleanPreference(Settings.PREF_AUTO_CORRECTION, true, true);
    308         setBooleanPreference(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true, true);
    309         testDoubleSpacePeriodWithSettings(true);
    310         // "Suggestion visibility" to off
    311         testDoubleSpacePeriodWithSettings(true, Settings.PREF_SHOW_SUGGESTIONS, false);
    312         // "Suggestion visibility" to on
    313         testDoubleSpacePeriodWithSettings(true, Settings.PREF_SHOW_SUGGESTIONS, true);
    314 
    315         // "Double-space period" to "off"
    316         testDoubleSpacePeriodWithSettings(false, Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, false);
    317 
    318         // "Auto-correction" to "off"
    319         testDoubleSpacePeriodWithSettings(true, Settings.PREF_AUTO_CORRECTION, false);
    320         // "Auto-correction" to "on"
    321         testDoubleSpacePeriodWithSettings(true, Settings.PREF_AUTO_CORRECTION, true);
    322 
    323         // "Suggestion visibility" to "always hide" and "Auto-correction" to "off"
    324         testDoubleSpacePeriodWithSettings(true, Settings.PREF_SHOW_SUGGESTIONS, false,
    325                 Settings.PREF_AUTO_CORRECTION, false);
    326         // "Suggestion visibility" to "always hide" and "Auto-correction" to "off"
    327         testDoubleSpacePeriodWithSettings(false, Settings.PREF_SHOW_SUGGESTIONS, false,
    328                 Settings.PREF_AUTO_CORRECTION, false,
    329                 Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, false);
    330     }
    331 
    332     public void testBackspaceAtStartAfterAutocorrect() {
    333         final String STRING_TO_TYPE = "tgis ";
    334         final int typedLength = STRING_TO_TYPE.length();
    335         final String EXPECTED_RESULT = "this ";
    336         final int NEW_CURSOR_POSITION = 0;
    337         type(STRING_TO_TYPE);
    338         sendUpdateForCursorMoveTo(typedLength);
    339         mInputConnection.setSelection(NEW_CURSOR_POSITION, NEW_CURSOR_POSITION);
    340         sendUpdateForCursorMoveTo(NEW_CURSOR_POSITION);
    341         type(Constants.CODE_DELETE);
    342         assertEquals("auto correct then move cursor to start of line then backspace",
    343                 EXPECTED_RESULT, mEditText.getText().toString());
    344     }
    345 
    346     public void testAutoCorrectThenMoveCursorThenBackspace() {
    347         final String STRING_TO_TYPE = "and tgis ";
    348         final int typedLength = STRING_TO_TYPE.length();
    349         final String EXPECTED_RESULT = "andthis ";
    350         final int NEW_CURSOR_POSITION = STRING_TO_TYPE.indexOf('t');
    351         type(STRING_TO_TYPE);
    352         sendUpdateForCursorMoveTo(typedLength);
    353         mInputConnection.setSelection(NEW_CURSOR_POSITION, NEW_CURSOR_POSITION);
    354         sendUpdateForCursorMoveTo(NEW_CURSOR_POSITION);
    355         type(Constants.CODE_DELETE);
    356         assertEquals("auto correct then move cursor then backspace",
    357                 EXPECTED_RESULT, mEditText.getText().toString());
    358     }
    359 
    360     public void testNoSpaceAfterManualPick() {
    361         final String WORD_TO_TYPE = "this";
    362         final String EXPECTED_RESULT = WORD_TO_TYPE;
    363         type(WORD_TO_TYPE);
    364         pickSuggestionManually(WORD_TO_TYPE);
    365         assertEquals("no space after manual pick", EXPECTED_RESULT,
    366                 mEditText.getText().toString());
    367     }
    368 
    369     public void testManualPickThenType() {
    370         final String WORD1_TO_TYPE = "this";
    371         final String WORD2_TO_TYPE = "is";
    372         final String EXPECTED_RESULT = "this is";
    373         type(WORD1_TO_TYPE);
    374         pickSuggestionManually(WORD1_TO_TYPE);
    375         type(WORD2_TO_TYPE);
    376         assertEquals("manual pick then type", EXPECTED_RESULT, mEditText.getText().toString());
    377     }
    378 
    379     public void testManualPickThenSeparator() {
    380         final String WORD1_TO_TYPE = "this";
    381         final String WORD2_TO_TYPE = "!";
    382         final String EXPECTED_RESULT = "this!";
    383         type(WORD1_TO_TYPE);
    384         pickSuggestionManually(WORD1_TO_TYPE);
    385         type(WORD2_TO_TYPE);
    386         assertEquals("manual pick then separator", EXPECTED_RESULT, mEditText.getText().toString());
    387     }
    388 
    389     // This test matches testClusteringPunctuationForFrench.
    390     // In some non-English languages, ! and ? are clustering punctuation signs.
    391     public void testClusteringPunctuation() {
    392         final String WORD1_TO_TYPE = "test";
    393         final String WORD2_TO_TYPE = "!!?!:!";
    394         final String EXPECTED_RESULT = "test!!?!:!";
    395         type(WORD1_TO_TYPE);
    396         pickSuggestionManually(WORD1_TO_TYPE);
    397         type(WORD2_TO_TYPE);
    398         assertEquals("clustering punctuation", EXPECTED_RESULT, mEditText.getText().toString());
    399     }
    400 
    401     public void testManualPickThenStripperThenPick() {
    402         final String WORD_TO_TYPE = "this";
    403         final String STRIPPER = "\n";
    404         final String EXPECTED_RESULT = "this\nthis";
    405         type(WORD_TO_TYPE);
    406         pickSuggestionManually(WORD_TO_TYPE);
    407         type(STRIPPER);
    408         type(WORD_TO_TYPE);
    409         pickSuggestionManually(WORD_TO_TYPE);
    410         assertEquals("manual pick then \\n then manual pick", EXPECTED_RESULT,
    411                 mEditText.getText().toString());
    412     }
    413 
    414     public void testManualPickThenSpaceThenType() {
    415         final String WORD1_TO_TYPE = "this";
    416         final String WORD2_TO_TYPE = " is";
    417         final String EXPECTED_RESULT = "this is";
    418         type(WORD1_TO_TYPE);
    419         pickSuggestionManually(WORD1_TO_TYPE);
    420         type(WORD2_TO_TYPE);
    421         assertEquals("manual pick then space then type", EXPECTED_RESULT,
    422                 mEditText.getText().toString());
    423     }
    424 
    425     public void testManualPickThenManualPick() {
    426         final String WORD1_TO_TYPE = "this";
    427         final String WORD2_TO_PICK = "is";
    428         final String EXPECTED_RESULT = "this is";
    429         type(WORD1_TO_TYPE);
    430         pickSuggestionManually(WORD1_TO_TYPE);
    431         // Here we fake picking a word through bigram prediction.
    432         pickSuggestionManually(WORD2_TO_PICK);
    433         assertEquals("manual pick then manual pick", EXPECTED_RESULT,
    434                 mEditText.getText().toString());
    435     }
    436 
    437     public void testDeleteWholeComposingWord() {
    438         final String WORD_TO_TYPE = "this";
    439         type(WORD_TO_TYPE);
    440         for (int i = 0; i < WORD_TO_TYPE.length(); ++i) {
    441             type(Constants.CODE_DELETE);
    442         }
    443         assertEquals("delete whole composing word", "", mEditText.getText().toString());
    444     }
    445 
    446     public void testResumeSuggestionOnBackspace() {
    447         final String STRING_TO_TYPE = "and this ";
    448         final int typedLength = STRING_TO_TYPE.length();
    449         type(STRING_TO_TYPE);
    450         assertEquals("resume suggestion on backspace", -1,
    451                 BaseInputConnection.getComposingSpanStart(mEditText.getText()));
    452         assertEquals("resume suggestion on backspace", -1,
    453                 BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
    454         sendUpdateForCursorMoveTo(typedLength);
    455         type(Constants.CODE_DELETE);
    456         assertEquals("resume suggestion on backspace", 4,
    457                 BaseInputConnection.getComposingSpanStart(mEditText.getText()));
    458         assertEquals("resume suggestion on backspace", 8,
    459                 BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
    460     }
    461 
    462     private void helperTestComposing(final String wordToType, final boolean shouldBeComposing) {
    463         mEditText.setText("");
    464         type(wordToType);
    465         assertEquals("start composing inside text", shouldBeComposing ? 0 : -1,
    466                 BaseInputConnection.getComposingSpanStart(mEditText.getText()));
    467         assertEquals("start composing inside text", shouldBeComposing ? wordToType.length() : -1,
    468                 BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
    469     }
    470 
    471     public void testStartComposing() {
    472         // Should start composing on a letter
    473         helperTestComposing("a", true);
    474         type("  "); // To reset the composing state
    475         // Should not start composing on quote
    476         helperTestComposing("'", false);
    477         type("  ");
    478         helperTestComposing("'-", false);
    479         type("  ");
    480         // Should not start composing on dash
    481         helperTestComposing("-", false);
    482         type("  ");
    483         helperTestComposing("-'", false);
    484         type("  ");
    485         helperTestComposing("a-", true);
    486         type("  ");
    487         helperTestComposing("a'", true);
    488     }
    489 
    490     // TODO: Add some tests for non-BMP characters
    491 
    492     public void testAutoCorrectByUserHistory() {
    493         type("qpmz");
    494         type(Constants.CODE_SPACE);
    495 
    496         int startIndex = mEditText.getText().length();
    497         type("qpmx");
    498         type(Constants.CODE_SPACE);
    499         int endIndex = mEditText.getText().length();
    500         assertEquals("auto-corrected by user history",
    501                 "qpmz ", mEditText.getText().subSequence(startIndex, endIndex).toString());
    502     }
    503 
    504     public void testPredictionsAfterSpace() {
    505         final String WORD_TO_TYPE = "Barack ";
    506         type(WORD_TO_TYPE);
    507         sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
    508         runMessages();
    509         // Test the first prediction is displayed
    510         final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
    511         assertEquals("predictions after space", "Obama",
    512                 suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null);
    513     }
    514 
    515     public void testPredictionsWithDoubleSpaceToPeriod() {
    516         mLatinIME.clearPersonalizedDictionariesForTest();
    517         final String WORD_TO_TYPE = "Barack  ";
    518         type(WORD_TO_TYPE);
    519         sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
    520         runMessages();
    521 
    522         type(Constants.CODE_DELETE);
    523         sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
    524         runMessages();
    525 
    526         SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
    527         suggestedWords = mLatinIME.getSuggestedWordsForTest();
    528         assertEquals("predictions after cancel double-space-to-period", "Obama",
    529                 mLatinIME.getSuggestedWordsForTest().getWord(0));
    530     }
    531 
    532     public void testPredictionsAfterManualPick() {
    533         final String WORD_TO_TYPE = "Barack";
    534         type(WORD_TO_TYPE);
    535         // Choose the auto-correction. For "Barack", the auto-correction should be "Barack".
    536         pickSuggestionManually(WORD_TO_TYPE);
    537         sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
    538         runMessages();
    539         // Test the first prediction is displayed
    540         final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
    541         assertEquals("predictions after manual pick", "Obama",
    542                 suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null);
    543     }
    544 
    545     public void testPredictionsAfterPeriod() {
    546         mLatinIME.clearPersonalizedDictionariesForTest();
    547         final String WORD_TO_TYPE = "Barack. ";
    548         type(WORD_TO_TYPE);
    549         sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
    550         runMessages();
    551 
    552         SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
    553         assertFalse(mLatinIME.getSuggestedWordsForTest().isEmpty());
    554     }
    555 
    556     public void testPredictionsAfterRecorrection() {
    557         final String PREFIX = "A ";
    558         final String WORD_TO_TYPE = "Barack";
    559         final String FIRST_NON_TYPED_SUGGESTION = "Barrack";
    560         final int endOfPrefix = PREFIX.length();
    561         final int endOfWord = endOfPrefix + WORD_TO_TYPE.length();
    562         final int endOfSuggestion = endOfPrefix + FIRST_NON_TYPED_SUGGESTION.length();
    563         final int indexForManualCursor = endOfPrefix + 3; // +3 because it's after "Bar" in "Barack"
    564         type(PREFIX);
    565         sendUpdateForCursorMoveTo(endOfPrefix);
    566         type(WORD_TO_TYPE);
    567         pickSuggestionManually(FIRST_NON_TYPED_SUGGESTION);
    568         sendUpdateForCursorMoveTo(endOfSuggestion);
    569         runMessages();
    570         type(" ");
    571         sendUpdateForCursorMoveBy(1);
    572         sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
    573         runMessages();
    574         // Simulate a manual cursor move
    575         mInputConnection.setSelection(indexForManualCursor, indexForManualCursor);
    576         sendUpdateForCursorMoveTo(indexForManualCursor);
    577         sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
    578         runMessages();
    579         pickSuggestionManually(WORD_TO_TYPE);
    580         sendUpdateForCursorMoveTo(endOfWord);
    581         sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
    582         runMessages();
    583         // Test the first prediction is displayed
    584         final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
    585         assertEquals("predictions after recorrection", "Obama",
    586                 suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null);
    587     }
    588 
    589     public void testComposingMultipleBackspace() {
    590         final String WORD_TO_TYPE = "radklro";
    591         final int TIMES_TO_TYPE = 3;
    592         final int TIMES_TO_BACKSPACE = 8;
    593         type(WORD_TO_TYPE);
    594         type(Constants.CODE_DELETE);
    595         type(Constants.CODE_DELETE);
    596         type(Constants.CODE_DELETE);
    597         type(WORD_TO_TYPE);
    598         type(Constants.CODE_DELETE);
    599         type(Constants.CODE_DELETE);
    600         type(WORD_TO_TYPE);
    601         type(Constants.CODE_DELETE);
    602         type(Constants.CODE_DELETE);
    603         type(Constants.CODE_DELETE);
    604         assertEquals("composing with multiple backspace",
    605                 WORD_TO_TYPE.length() * TIMES_TO_TYPE - TIMES_TO_BACKSPACE,
    606                 mEditText.getText().length());
    607     }
    608 
    609     public void testManySingleQuotes() {
    610         final String WORD_TO_AUTOCORRECT = "i";
    611         final String WORD_AUTOCORRECTED = "I";
    612         final String QUOTES = "''''''''''''''''''''";
    613         final String WORD_TO_TYPE = WORD_TO_AUTOCORRECT + QUOTES + " ";
    614         final String EXPECTED_RESULT = WORD_AUTOCORRECTED + QUOTES + " ";
    615         type(WORD_TO_TYPE);
    616         assertEquals("auto-correct with many trailing single quotes", EXPECTED_RESULT,
    617                 mEditText.getText().toString());
    618     }
    619 
    620     public void testManySingleQuotesOneByOne() {
    621         final String WORD_TO_AUTOCORRECT = "i";
    622         final String WORD_AUTOCORRECTED = "I";
    623         final String QUOTES = "''''''''''''''''''''";
    624         final String WORD_TO_TYPE = WORD_TO_AUTOCORRECT + QUOTES + " ";
    625         final String EXPECTED_RESULT = WORD_AUTOCORRECTED + QUOTES + " ";
    626 
    627         for (int i = 0; i < WORD_TO_TYPE.length(); ++i) {
    628             type(WORD_TO_TYPE.substring(i, i+1));
    629             sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
    630             runMessages();
    631         }
    632         assertEquals("type many trailing single quotes one by one", EXPECTED_RESULT,
    633                 mEditText.getText().toString());
    634     }
    635 
    636     public void testTypingSingleQuotesOneByOne() {
    637         final String WORD_TO_TYPE = "it's ";
    638         final String EXPECTED_RESULT = WORD_TO_TYPE;
    639         for (int i = 0; i < WORD_TO_TYPE.length(); ++i) {
    640             type(WORD_TO_TYPE.substring(i, i+1));
    641             sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
    642             runMessages();
    643         }
    644         assertEquals("type words letter by letter", EXPECTED_RESULT,
    645                 mEditText.getText().toString());
    646     }
    647 
    648     public void testBasicGesture() {
    649         gesture("this");
    650         assertEquals("this", mEditText.getText().toString());
    651     }
    652 
    653     public void testGestureGesture() {
    654         gesture("got");
    655         gesture("milk");
    656         assertEquals("got milk", mEditText.getText().toString());
    657     }
    658 
    659     public void testGestureBackspaceGestureAgain() {
    660         gesture("this");
    661         type(Constants.CODE_DELETE);
    662         assertEquals("gesture then backspace", "", mEditText.getText().toString());
    663         gesture("this");
    664         if (DecoderSpecificConstants.SHOULD_REMOVE_PREVIOUSLY_REJECTED_SUGGESTION) {
    665             assertNotEqual("this", mEditText.getText().toString());
    666         } else {
    667             assertEquals("this", mEditText.getText().toString());
    668         }
    669     }
    670 
    671     private void typeOrGestureWordAndPutCursorInside(final boolean gesture, final String word,
    672             final int startPos) {
    673         final int END_OF_WORD = startPos + word.length();
    674         final int NEW_CURSOR_POSITION = startPos + word.length() / 2;
    675         if (gesture) {
    676             gesture(word);
    677         } else {
    678             type(word);
    679         }
    680         sendUpdateForCursorMoveTo(END_OF_WORD);
    681         runMessages();
    682         sendUpdateForCursorMoveTo(NEW_CURSOR_POSITION);
    683         sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
    684         runMessages();
    685     }
    686 
    687     private void typeWordAndPutCursorInside(final String word, final int startPos) {
    688         typeOrGestureWordAndPutCursorInside(false /* gesture */, word, startPos);
    689     }
    690 
    691     private void gestureWordAndPutCursorInside(final String word, final int startPos) {
    692         typeOrGestureWordAndPutCursorInside(true /* gesture */, word, startPos);
    693     }
    694 
    695     private void ensureComposingSpanPos(final String message, final int from, final int to) {
    696         assertEquals(message, from, BaseInputConnection.getComposingSpanStart(mEditText.getText()));
    697         assertEquals(message, to, BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
    698     }
    699 
    700     public void testTypeWithinComposing() {
    701         final String WORD_TO_TYPE = "something";
    702         final String EXPECTED_RESULT = "some thing";
    703         typeWordAndPutCursorInside(WORD_TO_TYPE, 0 /* startPos */);
    704         type(" ");
    705         ensureComposingSpanPos("space while in the middle of a word cancels composition", -1, -1);
    706         assertEquals("space in the middle of a composing word", EXPECTED_RESULT,
    707                 mEditText.getText().toString());
    708         int cursorPos = sendUpdateForCursorMoveToEndOfLine();
    709         runMessages();
    710         type(" ");
    711         assertEquals("mbo", "some thing ", mEditText.getText().toString());
    712         typeWordAndPutCursorInside(WORD_TO_TYPE, cursorPos + 1 /* startPos */);
    713         type(Constants.CODE_DELETE);
    714         ensureComposingSpanPos("delete while in the middle of a word cancels composition", -1, -1);
    715     }
    716 
    717     public void testTypeWithinGestureComposing() {
    718         final String WORD_TO_TYPE = "something";
    719         final String EXPECTED_RESULT = "some thing";
    720         gestureWordAndPutCursorInside(WORD_TO_TYPE, 0 /* startPos */);
    721         type(" ");
    722         ensureComposingSpanPos("space while in the middle of a word cancels composition", -1, -1);
    723         assertEquals("space in the middle of a composing word", EXPECTED_RESULT,
    724                 mEditText.getText().toString());
    725         int cursorPos = sendUpdateForCursorMoveToEndOfLine();
    726         runMessages();
    727         type(" ");
    728         typeWordAndPutCursorInside(WORD_TO_TYPE, cursorPos + 1 /* startPos */);
    729         type(Constants.CODE_DELETE);
    730         sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
    731         ensureComposingSpanPos("delete while in the middle of a word cancels composition", -1, -1);
    732     }
    733 
    734     public void testManualPickThenSeparatorForFrench() {
    735         final String WORD1_TO_TYPE = "test";
    736         final String WORD2_TO_TYPE = "!";
    737         final String EXPECTED_RESULT = "test !";
    738         changeLanguage("fr");
    739         type(WORD1_TO_TYPE);
    740         pickSuggestionManually(WORD1_TO_TYPE);
    741         type(WORD2_TO_TYPE);
    742         assertEquals("manual pick then separator for French", EXPECTED_RESULT,
    743                 mEditText.getText().toString());
    744     }
    745 
    746     public void testClusteringPunctuationForFrench() {
    747         final String WORD1_TO_TYPE = "test";
    748         final String WORD2_TO_TYPE = "!!?!:!";
    749         // In English, the expected result would be "test!!?!:!"
    750         final String EXPECTED_RESULT = "test !!?! : !";
    751         changeLanguage("fr");
    752         type(WORD1_TO_TYPE);
    753         pickSuggestionManually(WORD1_TO_TYPE);
    754         type(WORD2_TO_TYPE);
    755         assertEquals("clustering punctuation for French", EXPECTED_RESULT,
    756                 mEditText.getText().toString());
    757     }
    758 
    759     public void testWordThenSpaceThenPunctuationFromStripTwice() {
    760         setBooleanPreference(Settings.PREF_BIGRAM_PREDICTIONS, false, true);
    761 
    762         final String WORD_TO_TYPE = "test ";
    763         final String PUNCTUATION_FROM_STRIP = "!";
    764         final String EXPECTED_RESULT = "test!! ";
    765         type(WORD_TO_TYPE);
    766         sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
    767         runMessages();
    768         assertTrue("type word then type space should display punctuation strip",
    769                 mLatinIME.getSuggestedWordsForTest().isPunctuationSuggestions());
    770         pickSuggestionManually(PUNCTUATION_FROM_STRIP);
    771         pickSuggestionManually(PUNCTUATION_FROM_STRIP);
    772         assertEquals(EXPECTED_RESULT, mEditText.getText().toString());
    773     }
    774 
    775     public void testWordThenSpaceDisplaysPredictions() {
    776         final String WORD_TO_TYPE = "Barack ";
    777         final String EXPECTED_RESULT = "Obama";
    778         type(WORD_TO_TYPE);
    779         sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
    780         runMessages();
    781         final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
    782         assertEquals("type word then type space yields predictions for French",
    783                 EXPECTED_RESULT, suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null);
    784     }
    785 }
    786