InputLogicTests.java revision bb15f92d4f80677587fae87fa2dd7a29ec465b4c
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17package com.android.inputmethod.latin; 18 19import android.content.Context; 20import android.content.Intent; 21import android.content.SharedPreferences; 22import android.preference.PreferenceManager; 23import android.test.ServiceTestCase; 24import android.text.InputType; 25import android.util.Log; 26import android.view.LayoutInflater; 27import android.view.ViewGroup; 28import android.view.View; 29import android.view.inputmethod.BaseInputConnection; 30import android.view.inputmethod.EditorInfo; 31import android.view.inputmethod.InputConnection; 32import android.widget.FrameLayout; 33import android.widget.TextView; 34 35import com.android.inputmethod.keyboard.Keyboard; 36import com.android.inputmethod.keyboard.KeyboardActionListener; 37import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService; // for proximity info 38import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo; 39 40import java.util.Arrays; 41import java.util.HashMap; 42 43public class InputLogicTests extends ServiceTestCase<LatinIME> { 44 45 private static final String PREF_DEBUG_MODE = "debug_mode"; 46 47 private LatinIME mLatinIME; 48 private TextView mTextView; 49 private InputConnection mInputConnection; 50 private HashMap<Integer, int[]> mProximity; 51 52 public InputLogicTests() { 53 super(LatinIME.class); 54 mProximity = createProximity(); 55 } 56 57 private static HashMap<Integer, int[]> createProximity() { 58 final HashMap<Integer, int[]> proximity = new HashMap<Integer, int[]>(); 59 final int[] testProximity = SpellCheckerProximityInfo.getProximityForScript( 60 AndroidSpellCheckerService.SCRIPT_LATIN); 61 final int ROW_SIZE = SpellCheckerProximityInfo.ROW_SIZE; 62 final int NUL = SpellCheckerProximityInfo.NUL; 63 for (int row = 0; row * ROW_SIZE < testProximity.length; ++row) { 64 final int rowBase = row * ROW_SIZE; 65 int column; 66 for (column = 1; NUL != testProximity[rowBase + column]; ++column) { 67 // Do nothing, just search for a NUL element 68 } 69 proximity.put(testProximity[row * ROW_SIZE], 70 Arrays.copyOfRange(testProximity, rowBase, rowBase + column)); 71 } 72 return proximity; 73 } 74 75 // returns the previous setting value 76 private boolean setDebugMode(final boolean mode) { 77 final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mLatinIME); 78 final boolean previousDebugSetting = prefs.getBoolean(PREF_DEBUG_MODE, false); 79 final SharedPreferences.Editor editor = prefs.edit(); 80 editor.putBoolean(PREF_DEBUG_MODE, true); 81 editor.commit(); 82 return previousDebugSetting; 83 } 84 85 @Override 86 protected void setUp() { 87 try { 88 super.setUp(); 89 } catch (Exception e) { 90 e.printStackTrace(); 91 } 92 mTextView = new TextView(getContext()); 93 mTextView.setInputType(InputType.TYPE_CLASS_TEXT); 94 mTextView.setEnabled(true); 95 setupService(); 96 mLatinIME = getService(); 97 final boolean previousDebugSetting = setDebugMode(true); 98 mLatinIME.onCreate(); 99 setDebugMode(previousDebugSetting); 100 final EditorInfo ei = new EditorInfo(); 101 ei.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT; 102 final InputConnection ic = mTextView.onCreateInputConnection(ei); 103 ei.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT; 104 final LayoutInflater inflater = 105 (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 106 final ViewGroup vg = new FrameLayout(getContext()); 107 final View inputView = inflater.inflate(R.layout.input_view, vg); 108 mLatinIME.setInputView(inputView); 109 mLatinIME.onBindInput(); 110 mLatinIME.onCreateInputView(); 111 mLatinIME.onStartInputView(ei, false); 112 mLatinIME.onCreateInputMethodInterface().startInput(ic, ei); 113 mInputConnection = ic; 114 // Wait for the main dictionary to be loaded (we need it for auto-correction tests) 115 int remainingAttempts = 10; 116 while (remainingAttempts > 0 && !mLatinIME.mSuggest.hasMainDictionary()) { 117 try { 118 Thread.sleep(100); 119 } catch (InterruptedException e) { 120 // Don't do much 121 } finally { 122 --remainingAttempts; 123 } 124 } 125 if (!mLatinIME.mSuggest.hasMainDictionary()) { 126 throw new RuntimeException("Can't initialize the main dictionary"); 127 } 128 } 129 130 // type(int) and type(String): helper methods to send a code point resp. a string to LatinIME. 131 private void type(final int codePoint) { 132 // onPressKey and onReleaseKey are explicitly deactivated here, but they do happen in the 133 // code (although multitouch/slide input and other factors make the sequencing complicated). 134 // They are supposed to be entirely deconnected from the input logic from LatinIME point of 135 // view and only delegates to the parts of the code that care. So we don't include them here 136 // to keep these tests as pinpoint as possible and avoid bringing it too many dependencies, 137 // but keep them in mind if something breaks. Commenting them out as is should work. 138 //mLatinIME.onPressKey(codePoint); 139 int[] proximityKeys = mProximity.get(codePoint); 140 if (null == proximityKeys) { 141 proximityKeys = new int[] { codePoint }; 142 } 143 mLatinIME.onCodeInput(codePoint, proximityKeys, 144 KeyboardActionListener.NOT_A_TOUCH_COORDINATE, 145 KeyboardActionListener.NOT_A_TOUCH_COORDINATE); 146 //mLatinIME.onReleaseKey(codePoint, false); 147 } 148 149 private void type(final String stringToType) { 150 for (int i = 0; i < stringToType.length(); i = stringToType.offsetByCodePoints(i, 1)) { 151 type(stringToType.codePointAt(i)); 152 } 153 } 154 155 public void testTypeWord() { 156 final String WORD_TO_TYPE = "abcd"; 157 type(WORD_TO_TYPE); 158 assertEquals("type word", WORD_TO_TYPE, mTextView.getText().toString()); 159 } 160 161 public void testPickSuggestionThenBackspace() { 162 final String WORD_TO_TYPE = "this"; 163 final String EXPECTED_RESULT = "this"; 164 type(WORD_TO_TYPE); 165 mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); 166 mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1); 167 type(Keyboard.CODE_DELETE); 168 assertEquals("press suggestion then backspace", EXPECTED_RESULT, 169 mTextView.getText().toString()); 170 } 171 172 public void testPickAutoCorrectionThenBackspace() { 173 final String WORD_TO_TYPE = "tgis"; 174 final String WORD_TO_PICK = "this"; 175 final String EXPECTED_RESULT = "tgis"; 176 type(WORD_TO_TYPE); 177 // Choose the auto-correction, which is always in position 0. For "tgis", the 178 // auto-correction should be "this". 179 mLatinIME.pickSuggestionManually(0, WORD_TO_PICK); 180 mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1); 181 assertEquals("pick typed word over auto-correction then backspace", WORD_TO_PICK, 182 mTextView.getText().toString()); 183 type(Keyboard.CODE_DELETE); 184 assertEquals("pick typed word over auto-correction then backspace", EXPECTED_RESULT, 185 mTextView.getText().toString()); 186 } 187 188 public void testPickTypedWordOverAutoCorrectionThenBackspace() { 189 final String WORD_TO_TYPE = "tgis"; 190 final String EXPECTED_RESULT = "tgis"; 191 type(WORD_TO_TYPE); 192 // Choose the typed word, which should be in position 1 (because position 0 should 193 // be occupied by the "this" auto-correction, as checked by testAutoCorrect()) 194 mLatinIME.pickSuggestionManually(1, WORD_TO_TYPE); 195 mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1); 196 assertEquals("pick typed word over auto-correction then backspace", WORD_TO_TYPE, 197 mTextView.getText().toString()); 198 type(Keyboard.CODE_DELETE); 199 assertEquals("pick typed word over auto-correction then backspace", EXPECTED_RESULT, 200 mTextView.getText().toString()); 201 } 202 203 public void testPickDifferentSuggestionThenBackspace() { 204 final String WORD_TO_TYPE = "tgis"; 205 final String WORD_TO_PICK = "thus"; 206 final String EXPECTED_RESULT = "tgis"; 207 type(WORD_TO_TYPE); 208 // Choose the second suggestion, which should be in position 2 and should be "thus" 209 // when "tgis is typed. 210 mLatinIME.pickSuggestionManually(2, WORD_TO_PICK); 211 mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1); 212 assertEquals("pick different suggestion then backspace", WORD_TO_PICK, 213 mTextView.getText().toString()); 214 type(Keyboard.CODE_DELETE); 215 assertEquals("pick different suggestion then backspace", EXPECTED_RESULT, 216 mTextView.getText().toString()); 217 } 218 219 public void testDeleteSelection() { 220 final String STRING_TO_TYPE = "some text delete me some text"; 221 final int SELECTION_START = 10; 222 final int SELECTION_END = 19; 223 final String EXPECTED_RESULT = "some text some text"; 224 type(STRING_TO_TYPE); 225 // There is no IMF to call onUpdateSelection for us so we must do it by hand. 226 // Send once to simulate the cursor actually responding to the move caused by typing. 227 // This is necessary because LatinIME is bookkeeping to avoid confusing a real cursor 228 // move with a move triggered by LatinIME inputting stuff. 229 mLatinIME.onUpdateSelection(0, 0, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1); 230 mInputConnection.setSelection(SELECTION_START, SELECTION_END); 231 // And now we simulate the user actually selecting some text. 232 mLatinIME.onUpdateSelection(0, 0, SELECTION_START, SELECTION_END, -1, -1); 233 type(Keyboard.CODE_DELETE); 234 assertEquals("delete selection", EXPECTED_RESULT, mTextView.getText().toString()); 235 } 236 237 public void testAutoCorrect() { 238 final String STRING_TO_TYPE = "tgis "; 239 final String EXPECTED_RESULT = "this "; 240 type(STRING_TO_TYPE); 241 assertEquals("simple auto-correct", EXPECTED_RESULT, mTextView.getText().toString()); 242 } 243 244 public void testAutoCorrectWithPeriod() { 245 final String STRING_TO_TYPE = "tgis."; 246 final String EXPECTED_RESULT = "this."; 247 type(STRING_TO_TYPE); 248 assertEquals("auto-correct with period", EXPECTED_RESULT, mTextView.getText().toString()); 249 } 250 251 public void testAutoCorrectWithPeriodThenRevert() { 252 final String STRING_TO_TYPE = "tgis."; 253 final String EXPECTED_RESULT = "tgis."; 254 type(STRING_TO_TYPE); 255 mLatinIME.onUpdateSelection(0, 0, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1); 256 type(Keyboard.CODE_DELETE); 257 assertEquals("auto-correct with period then revert", EXPECTED_RESULT, 258 mTextView.getText().toString()); 259 } 260 261 public void testDoubleSpace() { 262 final String STRING_TO_TYPE = "this "; 263 final String EXPECTED_RESULT = "this. "; 264 type(STRING_TO_TYPE); 265 assertEquals("double space make a period", EXPECTED_RESULT, mTextView.getText().toString()); 266 } 267 268 public void testCancelDoubleSpace() { 269 final String STRING_TO_TYPE = "this "; 270 final String EXPECTED_RESULT = "this "; 271 type(STRING_TO_TYPE); 272 type(Keyboard.CODE_DELETE); 273 assertEquals("double space make a period", EXPECTED_RESULT, mTextView.getText().toString()); 274 } 275 276 public void testBackspaceAtStartAfterAutocorrect() { 277 final String STRING_TO_TYPE = "tgis "; 278 final String EXPECTED_RESULT = "this "; 279 final int NEW_CURSOR_POSITION = 0; 280 type(STRING_TO_TYPE); 281 mLatinIME.onUpdateSelection(0, 0, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1); 282 mInputConnection.setSelection(NEW_CURSOR_POSITION, NEW_CURSOR_POSITION); 283 mLatinIME.onUpdateSelection(0, 0, NEW_CURSOR_POSITION, NEW_CURSOR_POSITION, -1, -1); 284 type(Keyboard.CODE_DELETE); 285 assertEquals("auto correct then move cursor to start of line then backspace", 286 EXPECTED_RESULT, mTextView.getText().toString()); 287 } 288 289 public void testAutoCorrectThenMoveCursorThenBackspace() { 290 final String STRING_TO_TYPE = "and tgis "; 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, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1); 295 mInputConnection.setSelection(NEW_CURSOR_POSITION, NEW_CURSOR_POSITION); 296 mLatinIME.onUpdateSelection(0, 0, NEW_CURSOR_POSITION, NEW_CURSOR_POSITION, -1, -1); 297 type(Keyboard.CODE_DELETE); 298 assertEquals("auto correct then move cursor then backspace", 299 EXPECTED_RESULT, mTextView.getText().toString()); 300 } 301 302 public void testNoSpaceAfterManualPick() { 303 final String WORD_TO_TYPE = "this"; 304 final String EXPECTED_RESULT = WORD_TO_TYPE; 305 type(WORD_TO_TYPE); 306 mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); 307 assertEquals("no space after manual pick", EXPECTED_RESULT, 308 mTextView.getText().toString()); 309 } 310 311 public void testManualPickThenType() { 312 final String WORD1_TO_TYPE = "this"; 313 final String WORD2_TO_TYPE = "is"; 314 final String EXPECTED_RESULT = "this is"; 315 type(WORD1_TO_TYPE); 316 mLatinIME.pickSuggestionManually(0, WORD1_TO_TYPE); 317 type(WORD2_TO_TYPE); 318 assertEquals("manual pick then type", EXPECTED_RESULT, mTextView.getText().toString()); 319 } 320 321 public void testManualPickThenSeparator() { 322 final String WORD1_TO_TYPE = "this"; 323 final String WORD2_TO_TYPE = "!"; 324 final String EXPECTED_RESULT = "this!"; 325 type(WORD1_TO_TYPE); 326 mLatinIME.pickSuggestionManually(0, WORD1_TO_TYPE); 327 type(WORD2_TO_TYPE); 328 assertEquals("manual pick then separator", EXPECTED_RESULT, mTextView.getText().toString()); 329 } 330 331 public void testWordThenSpaceThenPunctuationFromStripTwice() { 332 final String WORD_TO_TYPE = "this "; 333 final String PUNCTUATION_FROM_STRIP = "!"; 334 final String EXPECTED_RESULT = "this!! "; 335 type(WORD_TO_TYPE); 336 mLatinIME.pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); 337 mLatinIME.pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); 338 assertEquals("type word then type space then punctuation from strip twice", EXPECTED_RESULT, 339 mTextView.getText().toString()); 340 } 341 342 public void testWordThenSpaceThenPunctuationFromKeyboardTwice() { 343 final String WORD_TO_TYPE = "this !!"; 344 final String EXPECTED_RESULT = "this !!"; 345 type(WORD_TO_TYPE); 346 assertEquals("manual pick then space then punctuation from keyboard twice", EXPECTED_RESULT, 347 mTextView.getText().toString()); 348 } 349 350 public void testManualPickThenPunctuationFromStripTwiceThenType() { 351 final String WORD1_TO_TYPE = "this"; 352 final String WORD2_TO_TYPE = "is"; 353 final String PUNCTUATION_FROM_STRIP = "!"; 354 final String EXPECTED_RESULT = "this!! is"; 355 type(WORD1_TO_TYPE); 356 mLatinIME.pickSuggestionManually(0, WORD1_TO_TYPE); 357 mLatinIME.pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); 358 mLatinIME.pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); 359 type(WORD2_TO_TYPE); 360 assertEquals("pick word then pick punctuation twice then type", EXPECTED_RESULT, 361 mTextView.getText().toString()); 362 } 363 364 public void testManualPickThenSpaceThenType() { 365 final String WORD1_TO_TYPE = "this"; 366 final String WORD2_TO_TYPE = " is"; 367 final String EXPECTED_RESULT = "this is"; 368 type(WORD1_TO_TYPE); 369 mLatinIME.pickSuggestionManually(0, WORD1_TO_TYPE); 370 type(WORD2_TO_TYPE); 371 assertEquals("manual pick then space then type", WORD1_TO_TYPE + WORD2_TO_TYPE, 372 mTextView.getText().toString()); 373 } 374 375 public void testDeleteWholeComposingWord() { 376 final String WORD_TO_TYPE = "this"; 377 type(WORD_TO_TYPE); 378 for (int i = 0; i < WORD_TO_TYPE.length(); ++i) { 379 type(Keyboard.CODE_DELETE); 380 } 381 assertEquals("delete whole composing word", "", mTextView.getText().toString()); 382 } 383 384 public void testManuallyPickedWordThenColon() { 385 final String WORD_TO_TYPE = "this"; 386 final String PUNCTUATION = ":"; 387 final String EXPECTED_RESULT = "this:"; 388 type(WORD_TO_TYPE); 389 mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); 390 type(PUNCTUATION); 391 assertEquals("manually pick word then colon", 392 EXPECTED_RESULT, mTextView.getText().toString()); 393 } 394 395 public void testManuallyPickedWordThenOpenParen() { 396 final String WORD_TO_TYPE = "this"; 397 final String PUNCTUATION = "("; 398 final String EXPECTED_RESULT = "this ("; 399 type(WORD_TO_TYPE); 400 mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); 401 type(PUNCTUATION); 402 assertEquals("manually pick word then open paren", 403 EXPECTED_RESULT, mTextView.getText().toString()); 404 } 405 406 public void testManuallyPickedWordThenCloseParen() { 407 final String WORD_TO_TYPE = "this"; 408 final String PUNCTUATION = ")"; 409 final String EXPECTED_RESULT = "this)"; 410 type(WORD_TO_TYPE); 411 mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); 412 type(PUNCTUATION); 413 assertEquals("manually pick word then close paren", 414 EXPECTED_RESULT, mTextView.getText().toString()); 415 } 416 417 public void testManuallyPickedWordThenSmiley() { 418 final String WORD_TO_TYPE = "this"; 419 final String SPECIAL_KEY = ":-)"; 420 final String EXPECTED_RESULT = "this :-)"; 421 type(WORD_TO_TYPE); 422 mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); 423 mLatinIME.onTextInput(SPECIAL_KEY); 424 assertEquals("manually pick word then press the smiley key", 425 EXPECTED_RESULT, mTextView.getText().toString()); 426 } 427 428 public void testManuallyPickedWordThenDotCom() { 429 final String WORD_TO_TYPE = "this"; 430 final String SPECIAL_KEY = ".com"; 431 final String EXPECTED_RESULT = "this.com"; 432 type(WORD_TO_TYPE); 433 mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); 434 mLatinIME.onTextInput(SPECIAL_KEY); 435 assertEquals("manually pick word then press the .com key", 436 EXPECTED_RESULT, mTextView.getText().toString()); 437 } 438 439 public void testTypeWordTypeDotThenPressDotCom() { 440 final String WORD_TO_TYPE = "this."; 441 final String SPECIAL_KEY = ".com"; 442 final String EXPECTED_RESULT = "this.com"; 443 type(WORD_TO_TYPE); 444 mLatinIME.onTextInput(SPECIAL_KEY); 445 assertEquals("type word type dot then press the .com key", 446 EXPECTED_RESULT, mTextView.getText().toString()); 447 } 448 449 // TODO: Add some tests for non-BMP characters 450} 451