KeySpecParserTestsBase.java revision df39eb696152954cca5bdac4cdc4ea6650db889f
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.inputmethod.keyboard.internal;
18
19import static com.android.inputmethod.keyboard.internal.KeyboardCodesSet.PREFIX_CODE;
20import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED;
21import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.PREFIX_ICON;
22import static com.android.inputmethod.latin.Constants.CODE_OUTPUT_TEXT;
23import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED;
24
25import android.test.AndroidTestCase;
26
27import java.util.Locale;
28
29abstract class KeySpecParserTestsBase extends AndroidTestCase {
30    private final static Locale TEST_LOCALE = Locale.ENGLISH;
31    protected final KeyboardTextsSet mTextsSet = new KeyboardTextsSet();
32
33    private static final String CODE_SETTINGS_NAME = "key_settings";
34    private static final String CODE_SETTINGS = PREFIX_CODE + CODE_SETTINGS_NAME;
35    private static final String ICON_SETTINGS_NAME = "settings_key";
36    private static final String ICON_SETTINGS = PREFIX_ICON + ICON_SETTINGS_NAME;
37    private static final String CODE_SETTINGS_UPPERCASE = CODE_SETTINGS.toUpperCase(Locale.ROOT);
38    private static final String ICON_SETTINGS_UPPERCASE = ICON_SETTINGS.toUpperCase(Locale.ROOT);
39    private static final String CODE_NON_EXISTING = PREFIX_CODE + "non_existing";
40    private static final String ICON_NON_EXISTING = PREFIX_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        mTextsSet.setLocale(TEST_LOCALE, getContext());
51        mCodeSettings = KeyboardCodesSet.getCode(CODE_SETTINGS_NAME);
52        mCodeActionNext = KeyboardCodesSet.getCode("key_action_next");
53        mSettingsIconId = KeyboardIconsSet.getIconId(ICON_SETTINGS_NAME);
54    }
55
56    abstract protected void assertParser(final String message, final String keySpec,
57            final String expectedLabel, final String expectedOutputText, final int expectedIcon,
58            final int expectedCode);
59
60    protected void assertParserError(final String message, final String keySpec,
61            final String expectedLabel, final String expectedOutputText, final int expectedIconId,
62            final int expectedCode) {
63        try {
64            assertParser(message, keySpec, expectedLabel, expectedOutputText, expectedIconId,
65                    expectedCode);
66            fail(message);
67        } catch (Exception pcpe) {
68            // success.
69        }
70    }
71
72    // \U001d11e: MUSICAL SYMBOL G CLEF
73    private static final String SURROGATE_PAIR1 = "\ud834\udd1e";
74    private static final int SURROGATE_CODE1 = SURROGATE_PAIR1.codePointAt(0);
75    // \U001d122: MUSICAL SYMBOL F CLEF
76    private static final String SURROGATE_PAIR2 = "\ud834\udd22";
77    private static final int SURROGATE_CODE2 = SURROGATE_PAIR2.codePointAt(0);
78    // \U002f8a6: CJK COMPATIBILITY IDEOGRAPH-2F8A6; variant character of \u6148.
79    private static final String SURROGATE_PAIR3 = "\ud87e\udca6";
80    private static final String SURROGATE_PAIRS4 = SURROGATE_PAIR1 + SURROGATE_PAIR2;
81    private static final String SURROGATE_PAIRS5 = SURROGATE_PAIRS4 + SURROGATE_PAIR3;
82
83    public void testSingleLetter() {
84        assertParser("Single letter", "a",
85                "a", null, ICON_UNDEFINED, 'a');
86        assertParser("Single surrogate", SURROGATE_PAIR1,
87                SURROGATE_PAIR1, null, ICON_UNDEFINED, SURROGATE_CODE1);
88        assertParser("Sole vertical bar", "|",
89                "|", null, ICON_UNDEFINED, '|');
90        assertParser("Single escaped vertical bar", "\\|",
91                "|", null, ICON_UNDEFINED, '|');
92        assertParser("Single escaped escape", "\\\\",
93                "\\", null, ICON_UNDEFINED, '\\');
94        assertParser("Single comma", ",",
95                ",", null, ICON_UNDEFINED, ',');
96        assertParser("Single escaped comma", "\\,",
97                ",", null, ICON_UNDEFINED, ',');
98        assertParser("Single escaped letter", "\\a",
99                "a", null, ICON_UNDEFINED, 'a');
100        assertParser("Single escaped surrogate", "\\" + SURROGATE_PAIR2,
101                SURROGATE_PAIR2, null, ICON_UNDEFINED, SURROGATE_CODE2);
102        assertParser("Single bang", "!",
103                "!", null, ICON_UNDEFINED, '!');
104        assertParser("Single escaped bang", "\\!",
105                "!", null, ICON_UNDEFINED, '!');
106        assertParser("Single output text letter", "a|a",
107                "a", null, ICON_UNDEFINED, 'a');
108        assertParser("Single surrogate pair outputText", "G Clef|" + SURROGATE_PAIR1,
109                "G Clef", null, ICON_UNDEFINED, SURROGATE_CODE1);
110        assertParser("Single letter with outputText", "a|abc",
111                "a", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
112        assertParser("Single letter with surrogate outputText", "a|" + SURROGATE_PAIRS4,
113                "a", SURROGATE_PAIRS4, ICON_UNDEFINED, CODE_OUTPUT_TEXT);
114        assertParser("Single surrogate with outputText", SURROGATE_PAIR3 + "|abc",
115                SURROGATE_PAIR3, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
116        assertParser("Single letter with escaped outputText", "a|a\\|c",
117                "a", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
118        assertParser("Single letter with escaped surrogate outputText",
119                "a|" + SURROGATE_PAIR1 + "\\|" + SURROGATE_PAIR2,
120                "a", SURROGATE_PAIR1 + "|" + SURROGATE_PAIR2, ICON_UNDEFINED, CODE_OUTPUT_TEXT);
121        assertParser("Single letter with comma outputText", "a|a,b",
122                "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
123        assertParser("Single letter with escaped comma outputText", "a|a\\,b",
124                "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
125        assertParser("Single letter with outputText starts with bang", "a|!bc",
126                "a", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
127        assertParser("Single letter with surrogate outputText starts with bang",
128                "a|!" + SURROGATE_PAIRS5,
129                "a", "!" + SURROGATE_PAIRS5, ICON_UNDEFINED, CODE_OUTPUT_TEXT);
130        assertParser("Single letter with outputText contains bang", "a|a!c",
131                "a", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
132        assertParser("Single letter with escaped bang outputText", "a|\\!bc",
133                "a", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
134        assertParser("Single escaped escape with single outputText", "\\\\|\\\\",
135                "\\", null, ICON_UNDEFINED, '\\');
136        assertParser("Single escaped bar with single outputText", "\\||\\|",
137                "|", null, ICON_UNDEFINED, '|');
138        assertParser("Single letter with code", "a|" + CODE_SETTINGS,
139                "a", null, ICON_UNDEFINED, mCodeSettings);
140    }
141
142    public void testLabel() {
143        assertParser("Simple label", "abc",
144                "abc", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
145        assertParser("Simple surrogate label", SURROGATE_PAIRS4,
146                SURROGATE_PAIRS4, SURROGATE_PAIRS4, ICON_UNDEFINED, CODE_OUTPUT_TEXT);
147        assertParser("Label with escaped bar", "a\\|c",
148                "a|c", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
149        assertParser("Surrogate label with escaped bar", SURROGATE_PAIR1 + "\\|" + SURROGATE_PAIR2,
150                SURROGATE_PAIR1 + "|" + SURROGATE_PAIR2, SURROGATE_PAIR1 + "|" + SURROGATE_PAIR2,
151                ICON_UNDEFINED, CODE_OUTPUT_TEXT);
152        assertParser("Label with escaped escape", "a\\\\c",
153                "a\\c", "a\\c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
154        assertParser("Label with comma", "a,c",
155                "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
156        assertParser("Label with escaped comma", "a\\,c",
157                "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
158        assertParser("Label starts with bang", "!bc",
159                "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
160        assertParser("Surrogate label starts with bang", "!" + SURROGATE_PAIRS4,
161                "!" + SURROGATE_PAIRS4, "!" + SURROGATE_PAIRS4, ICON_UNDEFINED, CODE_OUTPUT_TEXT);
162        assertParser("Label contains bang", "a!c",
163                "a!c", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
164        assertParser("Label with escaped bang", "\\!bc",
165                "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
166        assertParser("Label with escaped letter", "\\abc",
167                "abc", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
168        assertParser("Label with outputText", "abc|def",
169                "abc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
170        assertParser("Label with comma and outputText", "a,c|def",
171                "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
172        assertParser("Escaped comma label with outputText", "a\\,c|def",
173                "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
174        assertParser("Escaped label with outputText", "a\\|c|def",
175                "a|c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
176        assertParser("Label with escaped bar outputText", "abc|d\\|f",
177                "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
178        assertParser("Escaped escape label with outputText", "a\\\\|def",
179                "a\\", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
180        assertParser("Label starts with bang and outputText", "!bc|def",
181                "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
182        assertParser("Label contains bang label and outputText", "a!c|def",
183                "a!c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
184        assertParser("Escaped bang label with outputText", "\\!bc|def",
185                "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
186        assertParser("Label with comma outputText", "abc|a,b",
187                "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
188        assertParser("Label with escaped comma outputText", "abc|a\\,b",
189                "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
190        assertParser("Label with outputText starts with bang", "abc|!bc",
191                "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
192        assertParser("Label with outputText contains bang", "abc|a!c",
193                "abc", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
194        assertParser("Label with escaped bang outputText", "abc|\\!bc",
195                "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
196        assertParser("Label with escaped bar outputText", "abc|d\\|f",
197                "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
198        assertParser("Escaped bar label with escaped bar outputText", "a\\|c|d\\|f",
199                "a|c", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
200        assertParser("Label with code", "abc|" + CODE_SETTINGS,
201                "abc", null, ICON_UNDEFINED, mCodeSettings);
202        assertParser("Escaped label with code", "a\\|c|" + CODE_SETTINGS,
203                "a|c", null, ICON_UNDEFINED, mCodeSettings);
204    }
205
206    public void testCodes() {
207        assertParser("Hexadecimal code", "a|0x1000",
208                "a", null, ICON_UNDEFINED, 0x1000);
209        assertParserError("Illegal hexadecimal code", "a|0x100X",
210                "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED);
211        assertParser("Escaped hexadecimal code 1", "a|\\0x1000",
212                "a", "0x1000", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
213        assertParser("Escaped hexadecimal code 2", "a|0\\x1000",
214                "a", "0x1000", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
215        assertParser("Escaped hexadecimal code 2", "a|0\\x1000",
216                "a", "0x1000", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
217        assertParserError("Illegally escaped hexadecimal code", "a|0x1\\000",
218                "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED);
219        // This is a workaround to have a key that has a supplementary code point. We can't put a
220        // string in resource as a XML entity of a supplementary code point or a surrogate pair.
221        // TODO: Should pass this test.
222//        assertParser("Hexadecimal supplementary code", String.format("a|0x%06x", SURROGATE_CODE2),
223//                SURROGATE_PAIR2, null, ICON_UNDEFINED, SURROGATE_CODE2);
224        assertParser("Zero is treated as output text", "a|0",
225                "a", null, ICON_UNDEFINED, '0');
226        assertParser("Digit is treated as output text", "a|3",
227                "a", null, ICON_UNDEFINED, '3');
228        assertParser("Decimal number is treated as an output text", "a|2014",
229                "a", "2014", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
230    }
231
232    public void testIcons() {
233        assertParser("Icon with single letter", ICON_SETTINGS + "|a",
234                null, null, mSettingsIconId, 'a');
235        assertParser("Icon with outputText", ICON_SETTINGS + "|abc",
236                null, "abc", mSettingsIconId, CODE_OUTPUT_TEXT);
237        assertParser("Icon with outputText starts with bang", ICON_SETTINGS + "|!bc",
238                null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT);
239        assertParser("Icon with outputText contains bang", ICON_SETTINGS + "|a!c",
240                null, "a!c", mSettingsIconId, CODE_OUTPUT_TEXT);
241        assertParser("Icon with escaped bang outputText", ICON_SETTINGS + "|\\!bc",
242                null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT);
243        assertParser("Label starts with bang and code", "!bc|" + CODE_SETTINGS,
244                "!bc", null, ICON_UNDEFINED, mCodeSettings);
245        assertParser("Label contains bang and code", "a!c|" + CODE_SETTINGS,
246                "a!c", null, ICON_UNDEFINED, mCodeSettings);
247        assertParser("Escaped bang label with code", "\\!bc|" + CODE_SETTINGS,
248                "!bc", null, ICON_UNDEFINED, mCodeSettings);
249        assertParser("Icon with code", ICON_SETTINGS + "|" + CODE_SETTINGS,
250                null, null, mSettingsIconId, mCodeSettings);
251    }
252
253    public void testResourceReference() {
254        assertParser("Settings as more key", "!text/settings_as_more_key",
255                null, null, mSettingsIconId, mCodeSettings);
256
257        assertParser("Action next as more key", "!text/label_next_key|!code/key_action_next",
258                "Next", null, ICON_UNDEFINED, mCodeActionNext);
259
260        assertParser("Popular domain",
261                "!text/keylabel_for_popular_domain|!text/keylabel_for_popular_domain ",
262                ".com", ".com ", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
263    }
264
265    public void testFormatError() {
266        assertParserError("Empty label with outputText", "|a",
267                null, "a", ICON_UNDEFINED, CODE_UNSPECIFIED);
268        assertParserError("Empty label with code", "|" + CODE_SETTINGS,
269                null, null, ICON_UNDEFINED, mCodeSettings);
270        assertParserError("Empty outputText with label", "a|",
271                "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED);
272        assertParserError("Empty outputText with icon", ICON_SETTINGS + "|",
273                null, null, mSettingsIconId, CODE_UNSPECIFIED);
274        assertParserError("Icon without code", ICON_SETTINGS,
275                null, null, mSettingsIconId, CODE_UNSPECIFIED);
276        assertParserError("Non existing icon", ICON_NON_EXISTING + "|abc",
277                null, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
278        assertParserError("Non existing code", "abc|" + CODE_NON_EXISTING,
279                "abc", null, ICON_UNDEFINED, CODE_UNSPECIFIED);
280        assertParserError("Third bar at end", "a|b|",
281                "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED);
282        assertParserError("Multiple bar", "a|b|c",
283                "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED);
284        assertParserError("Multiple bar with label and code", "a|" + CODE_SETTINGS + "|c",
285                "a", null, ICON_UNDEFINED, mCodeSettings);
286        assertParserError("Multiple bar with icon and outputText", ICON_SETTINGS + "|b|c",
287                null, null, mSettingsIconId, CODE_UNSPECIFIED);
288        assertParserError("Multiple bar with icon and code",
289                ICON_SETTINGS + "|" + CODE_SETTINGS + "|c",
290                null, null, mSettingsIconId, mCodeSettings);
291    }
292
293    public void testUselessUpperCaseSpecifier() {
294        assertParser("Single letter with CODE", "a|" + CODE_SETTINGS_UPPERCASE,
295                "a", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
296        assertParser("Label with CODE", "abc|" + CODE_SETTINGS_UPPERCASE,
297                "abc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
298        assertParser("Escaped label with CODE", "a\\|c|" + CODE_SETTINGS_UPPERCASE,
299                "a|c", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
300        assertParser("ICON with outputText", ICON_SETTINGS_UPPERCASE + "|abc",
301                "!ICON/SETTINGS_KEY", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
302        assertParser("ICON with outputText starts with bang", ICON_SETTINGS_UPPERCASE + "|!bc",
303                "!ICON/SETTINGS_KEY", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
304        assertParser("ICON with outputText contains bang", ICON_SETTINGS_UPPERCASE + "|a!c",
305                "!ICON/SETTINGS_KEY", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
306        assertParser("ICON with escaped bang outputText", ICON_SETTINGS_UPPERCASE + "|\\!bc",
307                "!ICON/SETTINGS_KEY", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
308        assertParser("Label starts with bang and CODE", "!bc|" + CODE_SETTINGS_UPPERCASE,
309                "!bc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
310        assertParser("Label contains bang and CODE", "a!c|" + CODE_SETTINGS_UPPERCASE,
311                "a!c", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
312        assertParser("Escaped bang label with CODE", "\\!bc|" + CODE_SETTINGS_UPPERCASE,
313                "!bc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
314        assertParser("ICON with CODE", ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE,
315                "!ICON/SETTINGS_KEY", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
316        assertParser("SETTINGS AS MORE KEY", "!TEXT/SETTINGS_AS_MORE_KEY",
317                "!TEXT/SETTINGS_AS_MORE_KEY", "!TEXT/SETTINGS_AS_MORE_KEY", ICON_UNDEFINED,
318                CODE_OUTPUT_TEXT);
319        assertParser("ACTION NEXT AS MORE KEY", "!TEXT/LABEL_NEXT_KEY|!CODE/KEY_ACTION_NEXT",
320                "!TEXT/LABEL_NEXT_KEY", "!CODE/KEY_ACTION_NEXT", ICON_UNDEFINED,
321                CODE_OUTPUT_TEXT);
322        assertParser("POPULAR DOMAIN",
323                "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN|!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN ",
324                "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN", "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN ",
325                ICON_UNDEFINED, CODE_OUTPUT_TEXT);
326        assertParserError("Empty label with CODE", "|" + CODE_SETTINGS_UPPERCASE,
327                null, null, ICON_UNDEFINED, mCodeSettings);
328        assertParserError("Empty outputText with ICON", ICON_SETTINGS_UPPERCASE + "|",
329                null, null, mSettingsIconId, CODE_UNSPECIFIED);
330        assertParser("ICON without code", ICON_SETTINGS_UPPERCASE,
331                "!ICON/SETTINGS_KEY", "!ICON/SETTINGS_KEY", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
332        assertParserError("Multiple bar with label and CODE", "a|" + CODE_SETTINGS_UPPERCASE + "|c",
333                "a", null, ICON_UNDEFINED, mCodeSettings);
334        assertParserError("Multiple bar with ICON and outputText", ICON_SETTINGS_UPPERCASE + "|b|c",
335                null, null, mSettingsIconId, CODE_UNSPECIFIED);
336        assertParserError("Multiple bar with ICON and CODE",
337                ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE + "|c",
338                null, null, mSettingsIconId, mCodeSettings);
339    }
340}
341