1/* 2 * Copyright (C) 2010 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.keyboard.internal; 18 19import static com.android.inputmethod.keyboard.Keyboard.CODE_OUTPUT_TEXT; 20import static com.android.inputmethod.keyboard.Keyboard.CODE_UNSPECIFIED; 21import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED; 22 23import android.test.AndroidTestCase; 24 25import com.android.inputmethod.keyboard.Keyboard; 26 27import java.util.Arrays; 28import java.util.Locale; 29 30public class KeySpecParserTests extends AndroidTestCase { 31 private final KeyboardCodesSet mCodesSet = new KeyboardCodesSet(); 32 private final KeyboardTextsSet mTextsSet = new KeyboardTextsSet(); 33 34 private static final String CODE_SETTINGS = "!code/key_settings"; 35 private static final String ICON_SETTINGS = "!icon/settings_key"; 36 private static final String CODE_SETTINGS_UPPERCASE = CODE_SETTINGS.toUpperCase(); 37 private static final String ICON_SETTINGS_UPPERCASE = ICON_SETTINGS.toUpperCase(); 38 private static final String CODE_NON_EXISTING = "!code/non_existing"; 39 private static final String ICON_NON_EXISTING = "!icon/non_existing"; 40 41 private int mCodeSettings; 42 private int mCodeActionNext; 43 private int mSettingsIconId; 44 45 @Override 46 protected void setUp() throws Exception { 47 super.setUp(); 48 49 final String language = Locale.ENGLISH.getLanguage(); 50 mCodesSet.setLanguage(language); 51 mTextsSet.setLanguage(language); 52 mTextsSet.loadStringResources(getContext()); 53 54 mCodeSettings = KeySpecParser.parseCode( 55 CODE_SETTINGS, mCodesSet, CODE_UNSPECIFIED); 56 mCodeActionNext = KeySpecParser.parseCode( 57 "!code/key_action_next", mCodesSet, CODE_UNSPECIFIED); 58 mSettingsIconId = KeySpecParser.getIconId(ICON_SETTINGS); 59 } 60 61 private void assertParser(String message, String moreKeySpec, String expectedLabel, 62 String expectedOutputText, int expectedIcon, int expectedCode) { 63 final String labelResolved = KeySpecParser.resolveTextReference(moreKeySpec, mTextsSet); 64 final MoreKeySpec spec = new MoreKeySpec(labelResolved, false /* needsToUpperCase */, 65 Locale.US, mCodesSet); 66 assertEquals(message + " [label]", expectedLabel, spec.mLabel); 67 assertEquals(message + " [ouptputText]", expectedOutputText, spec.mOutputText); 68 assertEquals(message + " [icon]", 69 KeyboardIconsSet.getIconName(expectedIcon), 70 KeyboardIconsSet.getIconName(spec.mIconId)); 71 assertEquals(message + " [code]", 72 Keyboard.printableCode(expectedCode), 73 Keyboard.printableCode(spec.mCode)); 74 } 75 76 private void assertParserError(String message, String moreKeySpec, String expectedLabel, 77 String expectedOutputText, int expectedIcon, int expectedCode) { 78 try { 79 assertParser(message, moreKeySpec, expectedLabel, expectedOutputText, expectedIcon, 80 expectedCode); 81 fail(message); 82 } catch (Exception pcpe) { 83 // success. 84 } 85 } 86 87 // \U001d11e: MUSICAL SYMBOL G CLEF 88 private static final String PAIR1 = "\ud834\udd1e"; 89 private static final int CODE1 = PAIR1.codePointAt(0); 90 // \U001d122: MUSICAL SYMBOL F CLEF 91 private static final String PAIR2 = "\ud834\udd22"; 92 private static final int CODE2 = PAIR2.codePointAt(0); 93 // \U002f8a6: CJK COMPATIBILITY IDEOGRAPH-2F8A6; variant character of \u6148. 94 private static final String PAIR3 = "\ud87e\udca6"; 95 private static final String SURROGATE1 = PAIR1 + PAIR2; 96 private static final String SURROGATE2 = PAIR1 + PAIR2 + PAIR3; 97 98 public void testSingleLetter() { 99 assertParser("Single letter", "a", 100 "a", null, ICON_UNDEFINED, 'a'); 101 assertParser("Single surrogate", PAIR1, 102 PAIR1, null, ICON_UNDEFINED, CODE1); 103 assertParser("Single escaped bar", "\\|", 104 "|", null, ICON_UNDEFINED, '|'); 105 assertParser("Single escaped escape", "\\\\", 106 "\\", null, ICON_UNDEFINED, '\\'); 107 assertParser("Single comma", ",", 108 ",", null, ICON_UNDEFINED, ','); 109 assertParser("Single escaped comma", "\\,", 110 ",", null, ICON_UNDEFINED, ','); 111 assertParser("Single escaped letter", "\\a", 112 "a", null, ICON_UNDEFINED, 'a'); 113 assertParser("Single escaped surrogate", "\\" + PAIR2, 114 PAIR2, null, ICON_UNDEFINED, CODE2); 115 assertParser("Single bang", "!", 116 "!", null, ICON_UNDEFINED, '!'); 117 assertParser("Single escaped bang", "\\!", 118 "!", null, ICON_UNDEFINED, '!'); 119 assertParser("Single output text letter", "a|a", 120 "a", null, ICON_UNDEFINED, 'a'); 121 assertParser("Single surrogate pair outputText", "G Clef|" + PAIR1, 122 "G Clef", null, ICON_UNDEFINED, CODE1); 123 assertParser("Single letter with outputText", "a|abc", 124 "a", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 125 assertParser("Single letter with surrogate outputText", "a|" + SURROGATE1, 126 "a", SURROGATE1, ICON_UNDEFINED, CODE_OUTPUT_TEXT); 127 assertParser("Single surrogate with outputText", PAIR3 + "|abc", 128 PAIR3, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 129 assertParser("Single letter with escaped outputText", "a|a\\|c", 130 "a", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 131 assertParser("Single letter with escaped surrogate outputText", 132 "a|" + PAIR1 + "\\|" + PAIR2, 133 "a", PAIR1 + "|" + PAIR2, ICON_UNDEFINED, CODE_OUTPUT_TEXT); 134 assertParser("Single letter with comma outputText", "a|a,b", 135 "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 136 assertParser("Single letter with escaped comma outputText", "a|a\\,b", 137 "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 138 assertParser("Single letter with outputText starts with bang", "a|!bc", 139 "a", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 140 assertParser("Single letter with surrogate outputText starts with bang", "a|!" + SURROGATE2, 141 "a", "!" + SURROGATE2, ICON_UNDEFINED, CODE_OUTPUT_TEXT); 142 assertParser("Single letter with outputText contains bang", "a|a!c", 143 "a", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 144 assertParser("Single letter with escaped bang outputText", "a|\\!bc", 145 "a", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 146 assertParser("Single escaped escape with single outputText", "\\\\|\\\\", 147 "\\", null, ICON_UNDEFINED, '\\'); 148 assertParser("Single escaped bar with single outputText", "\\||\\|", 149 "|", null, ICON_UNDEFINED, '|'); 150 assertParser("Single letter with code", "a|" + CODE_SETTINGS, 151 "a", null, ICON_UNDEFINED, mCodeSettings); 152 } 153 154 public void testLabel() { 155 assertParser("Simple label", "abc", 156 "abc", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 157 assertParser("Simple surrogate label", SURROGATE1, 158 SURROGATE1, SURROGATE1, ICON_UNDEFINED, CODE_OUTPUT_TEXT); 159 assertParser("Label with escaped bar", "a\\|c", 160 "a|c", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 161 assertParser("Surrogate label with escaped bar", PAIR1 + "\\|" + PAIR2, 162 PAIR1 + "|" + PAIR2, PAIR1 + "|" + PAIR2, 163 ICON_UNDEFINED, CODE_OUTPUT_TEXT); 164 assertParser("Label with escaped escape", "a\\\\c", 165 "a\\c", "a\\c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 166 assertParser("Label with comma", "a,c", 167 "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 168 assertParser("Label with escaped comma", "a\\,c", 169 "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 170 assertParser("Label starts with bang", "!bc", 171 "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 172 assertParser("Surrogate label starts with bang", "!" + SURROGATE1, 173 "!" + SURROGATE1, "!" + SURROGATE1, ICON_UNDEFINED, CODE_OUTPUT_TEXT); 174 assertParser("Label contains bang", "a!c", 175 "a!c", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 176 assertParser("Label with escaped bang", "\\!bc", 177 "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 178 assertParser("Label with escaped letter", "\\abc", 179 "abc", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 180 assertParser("Label with outputText", "abc|def", 181 "abc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 182 assertParser("Label with comma and outputText", "a,c|def", 183 "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 184 assertParser("Escaped comma label with outputText", "a\\,c|def", 185 "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 186 assertParser("Escaped label with outputText", "a\\|c|def", 187 "a|c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 188 assertParser("Label with escaped bar outputText", "abc|d\\|f", 189 "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 190 assertParser("Escaped escape label with outputText", "a\\\\|def", 191 "a\\", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 192 assertParser("Label starts with bang and outputText", "!bc|def", 193 "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 194 assertParser("Label contains bang label and outputText", "a!c|def", 195 "a!c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 196 assertParser("Escaped bang label with outputText", "\\!bc|def", 197 "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 198 assertParser("Label with comma outputText", "abc|a,b", 199 "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 200 assertParser("Label with escaped comma outputText", "abc|a\\,b", 201 "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 202 assertParser("Label with outputText starts with bang", "abc|!bc", 203 "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 204 assertParser("Label with outputText contains bang", "abc|a!c", 205 "abc", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 206 assertParser("Label with escaped bang outputText", "abc|\\!bc", 207 "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 208 assertParser("Label with escaped bar outputText", "abc|d\\|f", 209 "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 210 assertParser("Escaped bar label with escaped bar outputText", "a\\|c|d\\|f", 211 "a|c", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 212 assertParser("Label with code", "abc|" + CODE_SETTINGS, 213 "abc", null, ICON_UNDEFINED, mCodeSettings); 214 assertParser("Escaped label with code", "a\\|c|" + CODE_SETTINGS, 215 "a|c", null, ICON_UNDEFINED, mCodeSettings); 216 } 217 218 public void testIconAndCode() { 219 assertParser("Icon with outputText", ICON_SETTINGS + "|abc", 220 null, "abc", mSettingsIconId, CODE_OUTPUT_TEXT); 221 assertParser("Icon with outputText starts with bang", ICON_SETTINGS + "|!bc", 222 null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT); 223 assertParser("Icon with outputText contains bang", ICON_SETTINGS + "|a!c", 224 null, "a!c", mSettingsIconId, CODE_OUTPUT_TEXT); 225 assertParser("Icon with escaped bang outputText", ICON_SETTINGS + "|\\!bc", 226 null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT); 227 assertParser("Label starts with bang and code", "!bc|" + CODE_SETTINGS, 228 "!bc", null, ICON_UNDEFINED, mCodeSettings); 229 assertParser("Label contains bang and code", "a!c|" + CODE_SETTINGS, 230 "a!c", null, ICON_UNDEFINED, mCodeSettings); 231 assertParser("Escaped bang label with code", "\\!bc|" + CODE_SETTINGS, 232 "!bc", null, ICON_UNDEFINED, mCodeSettings); 233 assertParser("Icon with code", ICON_SETTINGS + "|" + CODE_SETTINGS, 234 null, null, mSettingsIconId, mCodeSettings); 235 } 236 237 public void testResourceReference() { 238 assertParser("Settings as more key", "!text/settings_as_more_key", 239 null, null, mSettingsIconId, mCodeSettings); 240 241 assertParser("Action next as more key", "!text/label_next_key|!code/key_action_next", 242 "Next", null, ICON_UNDEFINED, mCodeActionNext); 243 244 assertParser("Popular domain", 245 "!text/keylabel_for_popular_domain|!text/keylabel_for_popular_domain ", 246 ".com", ".com ", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 247 } 248 249 public void testFormatError() { 250 assertParserError("Empty spec", "", null, 251 null, ICON_UNDEFINED, CODE_UNSPECIFIED); 252 assertParserError("Empty label with outputText", "|a", 253 null, "a", ICON_UNDEFINED, CODE_UNSPECIFIED); 254 assertParserError("Empty label with code", "|" + CODE_SETTINGS, 255 null, null, ICON_UNDEFINED, mCodeSettings); 256 assertParserError("Empty outputText with label", "a|", 257 "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); 258 assertParserError("Empty outputText with icon", ICON_SETTINGS + "|", 259 null, null, mSettingsIconId, CODE_UNSPECIFIED); 260 assertParserError("Empty icon and code", "|", 261 null, null, ICON_UNDEFINED, CODE_UNSPECIFIED); 262 assertParserError("Icon without code", ICON_SETTINGS, 263 null, null, mSettingsIconId, CODE_UNSPECIFIED); 264 assertParserError("Non existing icon", ICON_NON_EXISTING + "|abc", 265 null, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 266 assertParserError("Non existing code", "abc|" + CODE_NON_EXISTING, 267 "abc", null, ICON_UNDEFINED, CODE_UNSPECIFIED); 268 assertParserError("Third bar at end", "a|b|", 269 "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); 270 assertParserError("Multiple bar", "a|b|c", 271 "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); 272 assertParserError("Multiple bar with label and code", "a|" + CODE_SETTINGS + "|c", 273 "a", null, ICON_UNDEFINED, mCodeSettings); 274 assertParserError("Multiple bar with icon and outputText", ICON_SETTINGS + "|b|c", 275 null, null, mSettingsIconId, CODE_UNSPECIFIED); 276 assertParserError("Multiple bar with icon and code", 277 ICON_SETTINGS + "|" + CODE_SETTINGS + "|c", 278 null, null, mSettingsIconId, mCodeSettings); 279 } 280 281 public void testUselessUpperCaseSpecifier() { 282 assertParser("Single letter with CODE", "a|" + CODE_SETTINGS_UPPERCASE, 283 "a", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 284 assertParser("Label with CODE", "abc|" + CODE_SETTINGS_UPPERCASE, 285 "abc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 286 assertParser("Escaped label with CODE", "a\\|c|" + CODE_SETTINGS_UPPERCASE, 287 "a|c", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 288 assertParser("ICON with outputText", ICON_SETTINGS_UPPERCASE + "|abc", 289 "!ICON/SETTINGS_KEY", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 290 assertParser("ICON with outputText starts with bang", ICON_SETTINGS_UPPERCASE + "|!bc", 291 "!ICON/SETTINGS_KEY", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 292 assertParser("ICON with outputText contains bang", ICON_SETTINGS_UPPERCASE + "|a!c", 293 "!ICON/SETTINGS_KEY", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 294 assertParser("ICON with escaped bang outputText", ICON_SETTINGS_UPPERCASE + "|\\!bc", 295 "!ICON/SETTINGS_KEY", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 296 assertParser("Label starts with bang and CODE", "!bc|" + CODE_SETTINGS_UPPERCASE, 297 "!bc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 298 assertParser("Label contains bang and CODE", "a!c|" + CODE_SETTINGS_UPPERCASE, 299 "a!c", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 300 assertParser("Escaped bang label with CODE", "\\!bc|" + CODE_SETTINGS_UPPERCASE, 301 "!bc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 302 assertParser("ICON with CODE", ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE, 303 "!ICON/SETTINGS_KEY", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 304 assertParser("SETTINGS AS MORE KEY", "!TEXT/SETTINGS_AS_MORE_KEY", 305 "!TEXT/SETTINGS_AS_MORE_KEY", "!TEXT/SETTINGS_AS_MORE_KEY", ICON_UNDEFINED, 306 CODE_OUTPUT_TEXT); 307 assertParser("ACTION NEXT AS MORE KEY", "!TEXT/LABEL_NEXT_KEY|!CODE/KEY_ACTION_NEXT", 308 "!TEXT/LABEL_NEXT_KEY", "!CODE/KEY_ACTION_NEXT", ICON_UNDEFINED, 309 CODE_OUTPUT_TEXT); 310 assertParser("POPULAR DOMAIN", 311 "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN|!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN ", 312 "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN", "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN ", 313 ICON_UNDEFINED, CODE_OUTPUT_TEXT); 314 assertParserError("Empty label with CODE", "|" + CODE_SETTINGS_UPPERCASE, 315 null, null, ICON_UNDEFINED, mCodeSettings); 316 assertParserError("Empty outputText with ICON", ICON_SETTINGS_UPPERCASE + "|", 317 null, null, mSettingsIconId, CODE_UNSPECIFIED); 318 assertParser("ICON without code", ICON_SETTINGS_UPPERCASE, 319 "!ICON/SETTINGS_KEY", "!ICON/SETTINGS_KEY", ICON_UNDEFINED, CODE_OUTPUT_TEXT); 320 assertParserError("Multiple bar with label and CODE", "a|" + CODE_SETTINGS_UPPERCASE + "|c", 321 "a", null, ICON_UNDEFINED, mCodeSettings); 322 assertParserError("Multiple bar with ICON and outputText", ICON_SETTINGS_UPPERCASE + "|b|c", 323 null, null, mSettingsIconId, CODE_UNSPECIFIED); 324 assertParserError("Multiple bar with ICON and CODE", 325 ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE + "|c", 326 null, null, mSettingsIconId, mCodeSettings); 327 } 328 329 private static void assertArrayEquals(String message, Object[] expected, Object[] actual) { 330 if (expected == actual) { 331 return; 332 } 333 if (expected == null || actual == null) { 334 assertEquals(message, Arrays.toString(expected), Arrays.toString(actual)); 335 return; 336 } 337 if (expected.length != actual.length) { 338 assertEquals(message + " [length]", Arrays.toString(expected), Arrays.toString(actual)); 339 return; 340 } 341 for (int i = 0; i < expected.length; i++) { 342 assertEquals(message + " [" + i + "]", 343 Arrays.toString(expected), Arrays.toString(actual)); 344 } 345 } 346 347 private static void assertInsertAdditionalMoreKeys(String message, String[] moreKeys, 348 String[] additionalMoreKeys, String[] expected) { 349 final String[] actual = 350 KeySpecParser.insertAdditionalMoreKeys( moreKeys, additionalMoreKeys); 351 assertArrayEquals(message, expected, actual); 352 } 353 354 public void testEmptyEntry() { 355 assertInsertAdditionalMoreKeys("null more keys and null additons", 356 null, 357 null, 358 null); 359 assertInsertAdditionalMoreKeys("null more keys and empty additons", 360 null, 361 new String[0], 362 null); 363 assertInsertAdditionalMoreKeys("empty more keys and null additons", 364 new String[0], 365 null, 366 null); 367 assertInsertAdditionalMoreKeys("empty more keys and empty additons", 368 new String[0], 369 new String[0], 370 null); 371 372 assertInsertAdditionalMoreKeys("filter out empty more keys", 373 new String[] { null, "a", "", "b", null }, 374 null, 375 new String[] { "a", "b" }); 376 assertInsertAdditionalMoreKeys("filter out empty additons", 377 new String[] { "a", "%", "b", "%", "c", "%", "d" }, 378 new String[] { null, "A", "", "B", null }, 379 new String[] { "a", "A", "b", "B", "c", "d" }); 380 } 381 382 public void testInsertAdditionalMoreKeys() { 383 // Escaped marker. 384 assertInsertAdditionalMoreKeys("escaped marker", 385 new String[] { "\\%", "%-)" }, 386 new String[] { "1", "2" }, 387 new String[] { "1", "2", "\\%", "%-)" }); 388 389 // 0 more key. 390 assertInsertAdditionalMoreKeys("null & null", null, null, null); 391 assertInsertAdditionalMoreKeys("null & 1 additon", 392 null, 393 new String[] { "1" }, 394 new String[] { "1" }); 395 assertInsertAdditionalMoreKeys("null & 2 additons", 396 null, 397 new String[] { "1", "2" }, 398 new String[] { "1", "2" }); 399 400 // 0 additional more key. 401 assertInsertAdditionalMoreKeys("1 more key & null", 402 new String[] { "A" }, 403 null, 404 new String[] { "A" }); 405 assertInsertAdditionalMoreKeys("2 more keys & null", 406 new String[] { "A", "B" }, 407 null, 408 new String[] { "A", "B" }); 409 410 // No marker. 411 assertInsertAdditionalMoreKeys("1 more key & 1 addtional & no marker", 412 new String[] { "A" }, 413 new String[] { "1" }, 414 new String[] { "1", "A" }); 415 assertInsertAdditionalMoreKeys("1 more key & 2 addtionals & no marker", 416 new String[] { "A" }, 417 new String[] { "1", "2" }, 418 new String[] { "1", "2", "A" }); 419 assertInsertAdditionalMoreKeys("2 more keys & 1 addtional & no marker", 420 new String[] { "A", "B" }, 421 new String[] { "1" }, 422 new String[] { "1", "A", "B" }); 423 assertInsertAdditionalMoreKeys("2 more keys & 2 addtionals & no marker", 424 new String[] { "A", "B" }, 425 new String[] { "1", "2" }, 426 new String[] { "1", "2", "A", "B" }); 427 428 // 1 marker. 429 assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at head", 430 new String[] { "%", "A" }, 431 new String[] { "1" }, 432 new String[] { "1", "A" }); 433 assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at tail", 434 new String[] { "A", "%" }, 435 new String[] { "1" }, 436 new String[] { "A", "1" }); 437 assertInsertAdditionalMoreKeys("2 more keys & 1 additon & marker at middle", 438 new String[] { "A", "%", "B" }, 439 new String[] { "1" }, 440 new String[] { "A", "1", "B" }); 441 442 // 1 marker & excess additional more keys. 443 assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at head", 444 new String[] { "%", "A", "B" }, 445 new String[] { "1", "2" }, 446 new String[] { "1", "A", "B", "2" }); 447 assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at tail", 448 new String[] { "A", "B", "%" }, 449 new String[] { "1", "2" }, 450 new String[] { "A", "B", "1", "2" }); 451 assertInsertAdditionalMoreKeys("2 more keys & 2 additons & marker at middle", 452 new String[] { "A", "%", "B" }, 453 new String[] { "1", "2" }, 454 new String[] { "A", "1", "B", "2" }); 455 456 // 2 markers. 457 assertInsertAdditionalMoreKeys("0 more key & 2 addtional & 2 markers", 458 new String[] { "%", "%" }, 459 new String[] { "1", "2" }, 460 new String[] { "1", "2" }); 461 assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at head", 462 new String[] { "%", "%", "A" }, 463 new String[] { "1", "2" }, 464 new String[] { "1", "2", "A" }); 465 assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at tail", 466 new String[] { "A", "%", "%" }, 467 new String[] { "1", "2" }, 468 new String[] { "A", "1", "2" }); 469 assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at middle", 470 new String[] { "A", "%", "%", "B" }, 471 new String[] { "1", "2" }, 472 new String[] { "A", "1", "2", "B" }); 473 assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & middle", 474 new String[] { "%", "A", "%", "B" }, 475 new String[] { "1", "2" }, 476 new String[] { "1", "A", "2", "B" }); 477 assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & tail", 478 new String[] { "%", "A", "B", "%" }, 479 new String[] { "1", "2" }, 480 new String[] { "1", "A", "B", "2" }); 481 assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at middle & tail", 482 new String[] { "A", "%", "B", "%" }, 483 new String[] { "1", "2" }, 484 new String[] { "A", "1", "B", "2" }); 485 486 // 2 markers & excess additional more keys. 487 assertInsertAdditionalMoreKeys("0 more key & 2 additons & 2 markers", 488 new String[] { "%", "%" }, 489 new String[] { "1", "2", "3" }, 490 new String[] { "1", "2", "3" }); 491 assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at head", 492 new String[] { "%", "%", "A" }, 493 new String[] { "1", "2", "3" }, 494 new String[] { "1", "2", "A", "3" }); 495 assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at tail", 496 new String[] { "A", "%", "%" }, 497 new String[] { "1", "2", "3" }, 498 new String[] { "A", "1", "2", "3" }); 499 assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at middle", 500 new String[] { "A", "%", "%", "B" }, 501 new String[] { "1", "2", "3" }, 502 new String[] { "A", "1", "2", "B", "3" }); 503 assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & middle", 504 new String[] { "%", "A", "%", "B" }, 505 new String[] { "1", "2", "3" }, 506 new String[] { "1", "A", "2", "B", "3" }); 507 assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & tail", 508 new String[] { "%", "A", "B", "%" }, 509 new String[] { "1", "2", "3" }, 510 new String[] { "1", "A", "B", "2", "3" }); 511 assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at middle & tail", 512 new String[] { "A", "%", "B", "%" }, 513 new String[] { "1", "2", "3" }, 514 new String[] { "A", "1", "B", "2", "3" }); 515 516 // 0 addtional more key and excess markers. 517 assertInsertAdditionalMoreKeys("0 more key & null & excess marker", 518 new String[] { "%" }, 519 null, 520 null); 521 assertInsertAdditionalMoreKeys("1 more key & null & excess marker at head", 522 new String[] { "%", "A" }, 523 null, 524 new String[] { "A" }); 525 assertInsertAdditionalMoreKeys("1 more key & null & excess marker at tail", 526 new String[] { "A", "%" }, 527 null, 528 new String[] { "A" }); 529 assertInsertAdditionalMoreKeys("2 more keys & null & excess marker at middle", 530 new String[] { "A", "%", "B" }, 531 null, 532 new String[] { "A", "B" }); 533 assertInsertAdditionalMoreKeys("2 more keys & null & excess markers", 534 new String[] { "%", "A", "%", "B", "%" }, 535 null, 536 new String[] { "A", "B" }); 537 538 // Excess markers. 539 assertInsertAdditionalMoreKeys("0 more key & 1 additon & excess marker", 540 new String[] { "%", "%" }, 541 new String[] { "1" }, 542 new String[] { "1" }); 543 assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at head", 544 new String[] { "%", "%", "A" }, 545 new String[] { "1" }, 546 new String[] { "1", "A" }); 547 assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at tail", 548 new String[] { "A", "%", "%" }, 549 new String[] { "1" }, 550 new String[] { "A", "1" }); 551 assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess marker at middle", 552 new String[] { "A", "%", "%", "B" }, 553 new String[] { "1" }, 554 new String[] { "A", "1", "B" }); 555 assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess markers", 556 new String[] { "%", "A", "%", "B", "%" }, 557 new String[] { "1" }, 558 new String[] { "1", "A", "B" }); 559 assertInsertAdditionalMoreKeys("2 more keys & 2 additons & excess markers", 560 new String[] { "%", "A", "%", "B", "%" }, 561 new String[] { "1", "2" }, 562 new String[] { "1", "A", "2", "B" }); 563 assertInsertAdditionalMoreKeys("2 more keys & 3 additons & excess markers", 564 new String[] { "%", "A", "%", "%", "B", "%" }, 565 new String[] { "1", "2", "3" }, 566 new String[] { "1", "A", "2", "3", "B" }); 567 } 568 569 private static final String HAS_LABEL = "!hasLabel!"; 570 private static final String NEEDS_DIVIDER = "!needsDividers!"; 571 private static final String AUTO_COLUMN_ORDER = "!autoColumnOrder!"; 572 private static final String FIXED_COLUMN_ORDER = "!fixedColumnOrder!"; 573 574 private static void assertGetBooleanValue(String message, String key, String[] moreKeys, 575 String[] expected, boolean expectedValue) { 576 final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length); 577 final boolean actualValue = KeySpecParser.getBooleanValue(actual, key); 578 assertEquals(message + " [value]", expectedValue, actualValue); 579 assertArrayEquals(message, expected, actual); 580 } 581 582 public void testGetBooleanValue() { 583 assertGetBooleanValue("Has label", HAS_LABEL, 584 new String[] { HAS_LABEL, "a", "b", "c" }, 585 new String[] { null, "a", "b", "c" }, true); 586 // Upper case specification will not work. 587 assertGetBooleanValue("HAS LABEL", HAS_LABEL, 588 new String[] { HAS_LABEL.toUpperCase(), "a", "b", "c" }, 589 new String[] { "!HASLABEL!", "a", "b", "c" }, false); 590 591 assertGetBooleanValue("No has label", HAS_LABEL, 592 new String[] { "a", "b", "c" }, 593 new String[] { "a", "b", "c" }, false); 594 assertGetBooleanValue("No has label with fixed clumn order", HAS_LABEL, 595 new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, 596 new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, false); 597 598 // Upper case specification will not work. 599 assertGetBooleanValue("Multiple has label", HAS_LABEL, 600 new String[] { 601 "a", HAS_LABEL.toUpperCase(), "b", "c", HAS_LABEL, "d" }, 602 new String[] { 603 "a", "!HASLABEL!", "b", "c", null, "d" }, true); 604 // Upper case specification will not work. 605 assertGetBooleanValue("Multiple has label with needs dividers", HAS_LABEL, 606 new String[] { 607 "a", HAS_LABEL, "b", NEEDS_DIVIDER, HAS_LABEL.toUpperCase(), "d" }, 608 new String[] { 609 "a", null, "b", NEEDS_DIVIDER, "!HASLABEL!", "d" }, true); 610 } 611 612 private static void assertGetIntValue(String message, String key, int defaultValue, 613 String[] moreKeys, String[] expected, int expectedValue) { 614 final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length); 615 final int actualValue = KeySpecParser.getIntValue(actual, key, defaultValue); 616 assertEquals(message + " [value]", expectedValue, actualValue); 617 assertArrayEquals(message, expected, actual); 618 } 619 620 public void testGetIntValue() { 621 assertGetIntValue("Fixed column order 3", FIXED_COLUMN_ORDER, -1, 622 new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, 623 new String[] { null, "a", "b", "c" }, 3); 624 // Upper case specification will not work. 625 assertGetIntValue("FIXED COLUMN ORDER 3", FIXED_COLUMN_ORDER, -1, 626 new String[] { FIXED_COLUMN_ORDER.toUpperCase() + "3", "a", "b", "c" }, 627 new String[] { "!FIXEDCOLUMNORDER!3", "a", "b", "c" }, -1); 628 629 assertGetIntValue("No fixed column order", FIXED_COLUMN_ORDER, -1, 630 new String[] { "a", "b", "c" }, 631 new String[] { "a", "b", "c" }, -1); 632 assertGetIntValue("No fixed column order with auto column order", FIXED_COLUMN_ORDER, -1, 633 new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" }, 634 new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" }, -1); 635 636 assertGetIntValue("Multiple fixed column order 3,5", FIXED_COLUMN_ORDER, -1, 637 new String[] { FIXED_COLUMN_ORDER + "3", "a", FIXED_COLUMN_ORDER + "5", "b" }, 638 new String[] { null, "a", null, "b" }, 3); 639 // Upper case specification will not work. 640 assertGetIntValue("Multiple fixed column order 5,3 with has label", FIXED_COLUMN_ORDER, -1, 641 new String[] { 642 FIXED_COLUMN_ORDER.toUpperCase() + "5", HAS_LABEL, "a", 643 FIXED_COLUMN_ORDER + "3", "b" }, 644 new String[] { "!FIXEDCOLUMNORDER!5", HAS_LABEL, "a", null, "b" }, 3); 645 } 646} 647