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