1/* 2 * Copyright (C) 2010 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.keyboard.internal; 18 19import android.app.Instrumentation; 20import android.content.Context; 21import android.content.res.Resources; 22import android.test.InstrumentationTestCase; 23import android.test.suitebuilder.annotation.MediumTest; 24 25import com.android.inputmethod.latin.utils.CollectionUtils; 26import com.android.inputmethod.latin.utils.RunInLocale; 27 28import java.lang.reflect.Field; 29import java.util.ArrayList; 30import java.util.Arrays; 31import java.util.Locale; 32 33@MediumTest 34public class KeySpecParserSplitTests extends InstrumentationTestCase { 35 private static final Locale TEST_LOCALE = Locale.ENGLISH; 36 final KeyboardTextsSet mTextsSet = new KeyboardTextsSet(); 37 38 @Override 39 protected void setUp() throws Exception { 40 super.setUp(); 41 42 final Instrumentation instrumentation = getInstrumentation(); 43 final Context targetContext = instrumentation.getTargetContext(); 44 mTextsSet.setLanguage(TEST_LOCALE.getLanguage()); 45 new RunInLocale<Void>() { 46 @Override 47 protected Void job(final Resources res) { 48 mTextsSet.loadStringResources(targetContext); 49 return null; 50 } 51 }.runInLocale(targetContext.getResources(), TEST_LOCALE); 52 final String[] testResourceNames = getAllResourceIdNames( 53 com.android.inputmethod.latin.tests.R.string.class); 54 mTextsSet.loadStringResourcesInternal(instrumentation.getContext(), testResourceNames, 55 // This dummy raw resource is needed to be able to load string resources from a test 56 // APK successfully. 57 com.android.inputmethod.latin.tests.R.raw.dummy_resource_for_testing); 58 } 59 60 private static String[] getAllResourceIdNames(final Class<?> resourceIdClass) { 61 final ArrayList<String> names = CollectionUtils.newArrayList(); 62 for (final Field field : resourceIdClass.getFields()) { 63 if (field.getType() == Integer.TYPE) { 64 names.add(field.getName()); 65 } 66 } 67 return names.toArray(new String[names.size()]); 68 } 69 70 private static <T> void assertArrayEquals(final String message, final T[] expected, 71 final T[] actual) { 72 if (expected == actual) { 73 return; 74 } 75 if (expected == null || actual == null) { 76 assertEquals(message, Arrays.toString(expected), Arrays.toString(actual)); 77 return; 78 } 79 if (expected.length != actual.length) { 80 assertEquals(message + " [length]", Arrays.toString(expected), Arrays.toString(actual)); 81 return; 82 } 83 for (int i = 0; i < expected.length; i++) { 84 final T e = expected[i]; 85 final T a = actual[i]; 86 if (e == a) { 87 continue; 88 } 89 assertEquals(message + " [" + i + "]", e, a); 90 } 91 } 92 93 private void assertTextArray(final String message, final String value, 94 final String ... expectedArray) { 95 final String resolvedActual = KeySpecParser.resolveTextReference(value, mTextsSet); 96 final String[] actual = KeySpecParser.splitKeySpecs(resolvedActual); 97 final String[] expected = (expectedArray.length == 0) ? null : expectedArray; 98 assertArrayEquals(message, expected, actual); 99 } 100 101 private void assertError(final String message, final String value, final String ... expected) { 102 try { 103 assertTextArray(message, value, expected); 104 fail(message); 105 } catch (Exception pcpe) { 106 // success. 107 } 108 } 109 110 // \U001d11e: MUSICAL SYMBOL G CLEF 111 private static final String PAIR1 = "\ud834\udd1e"; 112 // \U001d122: MUSICAL SYMBOL F CLEF 113 private static final String PAIR2 = "\ud834\udd22"; 114 // \U002f8a6: CJK COMPATIBILITY IDEOGRAPH-2F8A6; variant character of \u6148. 115 private static final String PAIR3 = "\ud87e\udca6"; 116 private static final String SURROGATE1 = PAIR1 + PAIR2; 117 private static final String SURROGATE2 = PAIR1 + PAIR2 + PAIR3; 118 119 public void testSplitZero() { 120 assertTextArray("Empty string", ""); 121 assertTextArray("Empty entry", ","); 122 assertTextArray("Empty entry at beginning", ",a", "a"); 123 assertTextArray("Empty entry at end", "a,", "a"); 124 assertTextArray("Empty entry at middle", "a,,b", "a", "b"); 125 assertTextArray("Empty entries with escape", ",a,b\\,c,,d,", "a", "b\\,c", "d"); 126 } 127 128 public void testSplitSingle() { 129 assertTextArray("Single char", "a", "a"); 130 assertTextArray("Surrogate pair", PAIR1, PAIR1); 131 assertTextArray("Single escape", "\\", "\\"); 132 assertTextArray("Space", " ", " "); 133 assertTextArray("Single label", "abc", "abc"); 134 assertTextArray("Single surrogate pairs label", SURROGATE2, SURROGATE2); 135 assertTextArray("Spaces", " ", " "); 136 assertTextArray("Spaces in label", "a b c", "a b c"); 137 assertTextArray("Spaces at beginning of label", " abc", " abc"); 138 assertTextArray("Spaces at end of label", "abc ", "abc "); 139 assertTextArray("Label surrounded by spaces", " abc ", " abc "); 140 assertTextArray("Surrogate pair surrounded by space", 141 " " + PAIR1 + " ", 142 " " + PAIR1 + " "); 143 assertTextArray("Surrogate pair within characters", 144 "ab" + PAIR2 + "cd", 145 "ab" + PAIR2 + "cd"); 146 assertTextArray("Surrogate pairs within characters", 147 "ab" + SURROGATE1 + "cd", 148 "ab" + SURROGATE1 + "cd"); 149 150 assertTextArray("Incomplete resource reference 1", "text", "text"); 151 assertTextArray("Incomplete resource reference 2", "!text", "!text"); 152 assertTextArray("Incomplete RESOURCE REFERENCE 2", "!TEXT", "!TEXT"); 153 assertTextArray("Incomplete resource reference 3", "text/", "text/"); 154 assertTextArray("Incomplete resource reference 4", "!" + SURROGATE2, "!" + SURROGATE2); 155 } 156 157 public void testSplitSingleEscaped() { 158 assertTextArray("Escaped char", "\\a", "\\a"); 159 assertTextArray("Escaped surrogate pair", "\\" + PAIR1, "\\" + PAIR1); 160 assertTextArray("Escaped comma", "\\,", "\\,"); 161 assertTextArray("Escaped comma escape", "a\\,\\", "a\\,\\"); 162 assertTextArray("Escaped escape", "\\\\", "\\\\"); 163 assertTextArray("Escaped label", "a\\bc", "a\\bc"); 164 assertTextArray("Escaped surrogate", "a\\" + PAIR1 + "c", "a\\" + PAIR1 + "c"); 165 assertTextArray("Escaped label at beginning", "\\abc", "\\abc"); 166 assertTextArray("Escaped surrogate at beginning", "\\" + SURROGATE2, "\\" + SURROGATE2); 167 assertTextArray("Escaped label at end", "abc\\", "abc\\"); 168 assertTextArray("Escaped surrogate at end", SURROGATE2 + "\\", SURROGATE2 + "\\"); 169 assertTextArray("Escaped label with comma", "a\\,c", "a\\,c"); 170 assertTextArray("Escaped surrogate with comma", 171 PAIR1 + "\\," + PAIR2, PAIR1 + "\\," + PAIR2); 172 assertTextArray("Escaped label with comma at beginning", "\\,bc", "\\,bc"); 173 assertTextArray("Escaped surrogate with comma at beginning", 174 "\\," + SURROGATE1, "\\," + SURROGATE1); 175 assertTextArray("Escaped label with comma at end", "ab\\,", "ab\\,"); 176 assertTextArray("Escaped surrogate with comma at end", 177 SURROGATE2 + "\\,", SURROGATE2 + "\\,"); 178 assertTextArray("Escaped label with successive", "\\,\\\\bc", "\\,\\\\bc"); 179 assertTextArray("Escaped surrogate with successive", 180 "\\,\\\\" + SURROGATE1, "\\,\\\\" + SURROGATE1); 181 assertTextArray("Escaped label with escape", "a\\\\c", "a\\\\c"); 182 assertTextArray("Escaped surrogate with escape", 183 PAIR1 + "\\\\" + PAIR2, PAIR1 + "\\\\" + PAIR2); 184 185 assertTextArray("Escaped !text", "\\!text", "\\!text"); 186 assertTextArray("Escaped !text/", "\\!text/", "\\!text/"); 187 assertTextArray("Escaped !TEXT/", "\\!TEXT/", "\\!TEXT/"); 188 assertTextArray("Escaped !text/name", "\\!text/empty_string", "\\!text/empty_string"); 189 assertTextArray("Escaped !TEXT/NAME", "\\!TEXT/EMPTY_STRING", "\\!TEXT/EMPTY_STRING"); 190 } 191 192 public void testSplitMulti() { 193 assertTextArray("Multiple chars", "a,b,c", "a", "b", "c"); 194 assertTextArray("Multiple chars", "a,b,\\c", "a", "b", "\\c"); 195 assertTextArray("Multiple chars and escape at beginning and end", 196 "\\a,b,\\c\\", "\\a", "b", "\\c\\"); 197 assertTextArray("Multiple surrogates", PAIR1 + "," + PAIR2 + "," + PAIR3, 198 PAIR1, PAIR2, PAIR3); 199 assertTextArray("Multiple chars surrounded by spaces", " a , b , c ", " a ", " b ", " c "); 200 assertTextArray("Multiple labels", "abc,def,ghi", "abc", "def", "ghi"); 201 assertTextArray("Multiple surrogated", SURROGATE1 + "," + SURROGATE2, 202 SURROGATE1, SURROGATE2); 203 assertTextArray("Multiple labels surrounded by spaces", " abc , def , ghi ", 204 " abc ", " def ", " ghi "); 205 } 206 207 public void testSplitMultiEscaped() { 208 assertTextArray("Multiple chars with comma", "a,\\,,c", "a", "\\,", "c"); 209 assertTextArray("Multiple chars with comma surrounded by spaces", " a , \\, , c ", 210 " a ", " \\, ", " c "); 211 assertTextArray("Multiple labels with escape", 212 "\\abc,d\\ef,gh\\i", "\\abc", "d\\ef", "gh\\i"); 213 assertTextArray("Multiple labels with escape surrounded by spaces", 214 " \\abc , d\\ef , gh\\i ", " \\abc ", " d\\ef ", " gh\\i "); 215 assertTextArray("Multiple labels with comma and escape", 216 "ab\\\\,d\\\\\\,,g\\,i", "ab\\\\", "d\\\\\\,", "g\\,i"); 217 assertTextArray("Multiple labels with comma and escape surrounded by spaces", 218 " ab\\\\ , d\\\\\\, , g\\,i ", " ab\\\\ ", " d\\\\\\, ", " g\\,i "); 219 220 assertTextArray("Multiple escaped !text", "\\!,\\!text/empty_string", 221 "\\!", "\\!text/empty_string"); 222 assertTextArray("Multiple escaped !TEXT", "\\!,\\!TEXT/EMPTY_STRING", 223 "\\!", "\\!TEXT/EMPTY_STRING"); 224 } 225 226 public void testSplitResourceError() { 227 assertError("Incomplete resource name", "!text/", "!text/"); 228 assertError("Non existing resource", "!text/non_existing"); 229 } 230 231 public void testSplitResourceZero() { 232 assertTextArray("Empty string", 233 "!text/empty_string"); 234 } 235 236 public void testSplitResourceSingle() { 237 assertTextArray("Single char", 238 "!text/single_char", "a"); 239 assertTextArray("Space", 240 "!text/space", " "); 241 assertTextArray("Single label", 242 "!text/single_label", "abc"); 243 assertTextArray("Spaces", 244 "!text/spaces", " "); 245 assertTextArray("Spaces in label", 246 "!text/spaces_in_label", "a b c"); 247 assertTextArray("Spaces at beginning of label", 248 "!text/spaces_at_beginning_of_label", " abc"); 249 assertTextArray("Spaces at end of label", 250 "!text/spaces_at_end_of_label", "abc "); 251 assertTextArray("label surrounded by spaces", 252 "!text/label_surrounded_by_spaces", " abc "); 253 254 assertTextArray("Escape and single char", 255 "\\\\!text/single_char", "\\\\a"); 256 } 257 258 public void testSplitResourceSingleEscaped() { 259 assertTextArray("Escaped char", 260 "!text/escaped_char", "\\a"); 261 assertTextArray("Escaped comma", 262 "!text/escaped_comma", "\\,"); 263 assertTextArray("Escaped comma escape", 264 "!text/escaped_comma_escape", "a\\,\\"); 265 assertTextArray("Escaped escape", 266 "!text/escaped_escape", "\\\\"); 267 assertTextArray("Escaped label", 268 "!text/escaped_label", "a\\bc"); 269 assertTextArray("Escaped label at beginning", 270 "!text/escaped_label_at_beginning", "\\abc"); 271 assertTextArray("Escaped label at end", 272 "!text/escaped_label_at_end", "abc\\"); 273 assertTextArray("Escaped label with comma", 274 "!text/escaped_label_with_comma", "a\\,c"); 275 assertTextArray("Escaped label with comma at beginning", 276 "!text/escaped_label_with_comma_at_beginning", "\\,bc"); 277 assertTextArray("Escaped label with comma at end", 278 "!text/escaped_label_with_comma_at_end", "ab\\,"); 279 assertTextArray("Escaped label with successive", 280 "!text/escaped_label_with_successive", "\\,\\\\bc"); 281 assertTextArray("Escaped label with escape", 282 "!text/escaped_label_with_escape", "a\\\\c"); 283 } 284 285 public void testSplitResourceMulti() { 286 assertTextArray("Multiple chars", 287 "!text/multiple_chars", "a", "b", "c"); 288 assertTextArray("Multiple chars surrounded by spaces", 289 "!text/multiple_chars_surrounded_by_spaces", 290 " a ", " b ", " c "); 291 assertTextArray("Multiple labels", 292 "!text/multiple_labels", "abc", "def", "ghi"); 293 assertTextArray("Multiple labels surrounded by spaces", 294 "!text/multiple_labels_surrounded_by_spaces", " abc ", " def ", " ghi "); 295 } 296 297 public void testSplitResourcetMultiEscaped() { 298 assertTextArray("Multiple chars with comma", 299 "!text/multiple_chars_with_comma", 300 "a", "\\,", "c"); 301 assertTextArray("Multiple chars with comma surrounded by spaces", 302 "!text/multiple_chars_with_comma_surrounded_by_spaces", 303 " a ", " \\, ", " c "); 304 assertTextArray("Multiple labels with escape", 305 "!text/multiple_labels_with_escape", 306 "\\abc", "d\\ef", "gh\\i"); 307 assertTextArray("Multiple labels with escape surrounded by spaces", 308 "!text/multiple_labels_with_escape_surrounded_by_spaces", 309 " \\abc ", " d\\ef ", " gh\\i "); 310 assertTextArray("Multiple labels with comma and escape", 311 "!text/multiple_labels_with_comma_and_escape", 312 "ab\\\\", "d\\\\\\,", "g\\,i"); 313 assertTextArray("Multiple labels with comma and escape surrounded by spaces", 314 "!text/multiple_labels_with_comma_and_escape_surrounded_by_spaces", 315 " ab\\\\ ", " d\\\\\\, ", " g\\,i "); 316 } 317 318 public void testSplitMultipleResources() { 319 assertTextArray("Literals and resources", 320 "1,!text/multiple_chars,z", "1", "a", "b", "c", "z"); 321 assertTextArray("Literals and resources and escape at end", 322 "\\1,!text/multiple_chars,z\\", "\\1", "a", "b", "c", "z\\"); 323 assertTextArray("Multiple single resource chars and labels", 324 "!text/single_char,!text/single_label,!text/escaped_comma", 325 "a", "abc", "\\,"); 326 assertTextArray("Multiple single resource chars and labels 2", 327 "!text/single_char,!text/single_label,!text/escaped_comma_escape", 328 "a", "abc", "a\\,\\"); 329 assertTextArray("Multiple multiple resource chars and labels", 330 "!text/multiple_chars,!text/multiple_labels,!text/multiple_chars_with_comma", 331 "a", "b", "c", "abc", "def", "ghi", "a", "\\,", "c"); 332 assertTextArray("Concatenated resources", 333 "!text/multiple_chars!text/multiple_labels!text/multiple_chars_with_comma", 334 "a", "b", "cabc", "def", "ghia", "\\,", "c"); 335 assertTextArray("Concatenated resource and literal", 336 "abc!text/multiple_labels", 337 "abcabc", "def", "ghi"); 338 } 339 340 public void testSplitIndirectReference() { 341 assertTextArray("Indirect", 342 "!text/indirect_string", "a", "b", "c"); 343 assertTextArray("Indirect with literal", 344 "1,!text/indirect_string_with_literal,2", "1", "x", "a", "b", "c", "y", "2"); 345 assertTextArray("Indirect2", 346 "!text/indirect2_string", "a", "b", "c"); 347 } 348 349 public void testSplitInfiniteIndirectReference() { 350 assertError("Infinite indirection", 351 "1,!text/infinite_indirection,2", "1", "infinite", "<infinite>", "loop", "2"); 352 } 353 354 public void testLabelReferece() { 355 assertTextArray("Label time am", "!text/label_time_am", "AM"); 356 357 assertTextArray("More keys for am pm", "!text/more_keys_for_am_pm", 358 "!fixedColumnOrder!2", "!hasLabels!", "AM", "PM"); 359 360 assertTextArray("Settings as more key", "!text/settings_as_more_key", 361 "!icon/settings_key|!code/key_settings"); 362 363 assertTextArray("Indirect naviagte actions as more key", 364 "!text/indirect_navigate_actions_as_more_key", 365 "!fixedColumnOrder!2", 366 "!hasLabels!", "Prev|!code/key_action_previous", 367 "!hasLabels!", "Next|!code/key_action_next"); 368 } 369 370 public void testUselessUpperCaseSpecifier() { 371 assertTextArray("EMPTY STRING", 372 "!TEXT/EMPTY_STRING", "!TEXT/EMPTY_STRING"); 373 374 assertTextArray("SINGLE CHAR", 375 "!TEXT/SINGLE_CHAR", "!TEXT/SINGLE_CHAR"); 376 assertTextArray("Escape and SINGLE CHAR", 377 "\\\\!TEXT/SINGLE_CHAR", "\\\\!TEXT/SINGLE_CHAR"); 378 379 assertTextArray("MULTIPLE CHARS", 380 "!TEXT/MULTIPLE_CHARS", "!TEXT/MULTIPLE_CHARS"); 381 382 assertTextArray("Literals and RESOURCES", 383 "1,!TEXT/MULTIPLE_CHARS,z", "1", "!TEXT/MULTIPLE_CHARS", "z"); 384 assertTextArray("Multiple single RESOURCE chars and LABELS 2", 385 "!TEXT/SINGLE_CHAR,!TEXT/SINGLE_LABEL,!TEXT/ESCAPED_COMMA_ESCAPE", 386 "!TEXT/SINGLE_CHAR", "!TEXT/SINGLE_LABEL", "!TEXT/ESCAPED_COMMA_ESCAPE"); 387 388 assertTextArray("INDIRECT", 389 "!TEXT/INDIRECT_STRING", "!TEXT/INDIRECT_STRING"); 390 assertTextArray("INDIRECT with literal", 391 "1,!TEXT/INDIRECT_STRING_WITH_LITERAL,2", 392 "1", "!TEXT/INDIRECT_STRING_WITH_LITERAL", "2"); 393 assertTextArray("INDIRECT2", 394 "!TEXT/INDIRECT2_STRING", "!TEXT/INDIRECT2_STRING"); 395 396 assertTextArray("Upper indirect", 397 "!text/upper_indirect_string", "!TEXT/MULTIPLE_CHARS"); 398 assertTextArray("Upper indirect with literal", 399 "1,!text/upper_indirect_string_with_literal,2", 400 "1", "x", "!TEXT/MULTIPLE_CHARS", "y", "2"); 401 assertTextArray("Upper indirect2", 402 "!text/upper_indirect2_string", "!TEXT/UPPER_INDIRECT_STRING"); 403 404 assertTextArray("UPPER INDIRECT", 405 "!TEXT/upper_INDIRECT_STRING", "!TEXT/upper_INDIRECT_STRING"); 406 assertTextArray("Upper INDIRECT with literal", 407 "1,!TEXT/upper_INDIRECT_STRING_WITH_LITERAL,2", 408 "1", "!TEXT/upper_INDIRECT_STRING_WITH_LITERAL", "2"); 409 assertTextArray("Upper INDIRECT2", 410 "!TEXT/upper_INDIRECT2_STRING", "!TEXT/upper_INDIRECT2_STRING"); 411 412 assertTextArray("INFINITE INDIRECTION", 413 "1,!TEXT/INFINITE_INDIRECTION,2", "1", "!TEXT/INFINITE_INDIRECTION", "2"); 414 415 assertTextArray("Upper infinite indirection", 416 "1,!text/upper_infinite_indirection,2", 417 "1", "infinite", "!TEXT/INFINITE_INDIRECTION", "loop", "2"); 418 assertTextArray("Upper INFINITE INDIRECTION", 419 "1,!TEXT/UPPER_INFINITE_INDIRECTION,2", 420 "1", "!TEXT/UPPER_INFINITE_INDIRECTION", "2"); 421 422 assertTextArray("LABEL TIME AM", "!TEXT/LABEL_TIME_AM", "!TEXT/LABEL_TIME_AM"); 423 assertTextArray("MORE KEYS FOR AM OM", "!TEXT/MORE_KEYS_FOR_AM_PM", 424 "!TEXT/MORE_KEYS_FOR_AM_PM"); 425 assertTextArray("SETTINGS AS MORE KEY", "!TEXT/SETTINGS_AS_MORE_KEY", 426 "!TEXT/SETTINGS_AS_MORE_KEY"); 427 assertTextArray("INDIRECT NAVIGATE ACTIONS AS MORE KEY", 428 "!TEXT/INDIRECT_NAVIGATE_ACTIONS_AS_MORE_KEY", 429 "!TEXT/INDIRECT_NAVIGATE_ACTIONS_AS_MORE_KEY"); 430 } 431} 432