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