KeySpecParserTests.java revision 0a3362d26474cbd60bf870be7ad1413359e4fad6
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;
26import com.android.inputmethod.keyboard.internal.KeySpecParser.MoreKeySpec;
27
28import java.util.Arrays;
29import java.util.Locale;
30
31public 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