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
17package com.android.inputmethod.keyboard.internal;
18
19import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED;
20import static com.android.inputmethod.latin.common.Constants.CODE_UNSPECIFIED;
21
22import android.test.suitebuilder.annotation.SmallTest;
23
24import com.android.inputmethod.latin.common.Constants;
25
26import java.util.Arrays;
27import java.util.Locale;
28
29@SmallTest
30public final class MoreKeySpecTests extends KeySpecParserTestsBase {
31    @Override
32    protected void assertParser(final String message, final String moreKeySpec,
33            final String expectedLabel, final String expectedOutputText, final int expectedIconId,
34            final int expectedCode) {
35        final String labelResolved = mTextsSet.resolveTextReference(moreKeySpec);
36        final MoreKeySpec spec = new MoreKeySpec(
37                labelResolved, false /* needsToUpperCase */, Locale.US);
38        assertEquals(message + " [label]", expectedLabel, spec.mLabel);
39        assertEquals(message + " [ouptputText]", expectedOutputText, spec.mOutputText);
40        assertEquals(message + " [icon]",
41                KeyboardIconsSet.getIconName(expectedIconId),
42                KeyboardIconsSet.getIconName(spec.mIconId));
43        assertEquals(message + " [code]",
44                Constants.printableCode(expectedCode),
45                Constants.printableCode(spec.mCode));
46    }
47
48    // TODO: Move this method to {@link KeySpecParserBase}.
49    public void testEmptySpec() {
50        assertParserError("Null spec", null,
51                null, null, ICON_UNDEFINED, CODE_UNSPECIFIED);
52        assertParserError("Empty spec", "",
53                null, null, ICON_UNDEFINED, CODE_UNSPECIFIED);
54    }
55
56    private static void assertArrayEquals(final String message, final Object[] expected,
57            final Object[] actual) {
58        if (expected == actual) {
59            return;
60        }
61        if (expected == null || actual == null) {
62            assertEquals(message, Arrays.toString(expected), Arrays.toString(actual));
63            return;
64        }
65        if (expected.length != actual.length) {
66            assertEquals(message + " [length]", Arrays.toString(expected), Arrays.toString(actual));
67            return;
68        }
69        for (int i = 0; i < expected.length; i++) {
70            assertEquals(message + " [" + i + "]",
71                    Arrays.toString(expected), Arrays.toString(actual));
72        }
73    }
74
75    private static void assertInsertAdditionalMoreKeys(final String message,
76            final String[] moreKeys, final String[] additionalMoreKeys, final String[] expected) {
77        final String[] actual = MoreKeySpec.insertAdditionalMoreKeys(moreKeys, additionalMoreKeys);
78        assertArrayEquals(message, expected, actual);
79    }
80
81    @SuppressWarnings("static-method")
82    public void testEmptyEntry() {
83        assertInsertAdditionalMoreKeys("null more keys and null additons",
84                null,
85                null,
86                null);
87        assertInsertAdditionalMoreKeys("null more keys and empty additons",
88                null,
89                new String[0],
90                null);
91        assertInsertAdditionalMoreKeys("empty more keys and null additons",
92                new String[0],
93                null,
94                null);
95        assertInsertAdditionalMoreKeys("empty more keys and empty additons",
96                new String[0],
97                new String[0],
98                null);
99
100        assertInsertAdditionalMoreKeys("filter out empty more keys",
101                new String[] { null, "a", "", "b", null },
102                null,
103                new String[] { "a", "b" });
104        assertInsertAdditionalMoreKeys("filter out empty additons",
105                new String[] { "a", "%", "b", "%", "c", "%", "d" },
106                new String[] { null, "A", "", "B", null },
107                new String[] { "a", "A", "b", "B", "c", "d" });
108    }
109
110    @SuppressWarnings("static-method")
111    public void testInsertAdditionalMoreKeys() {
112        // Escaped marker.
113        assertInsertAdditionalMoreKeys("escaped marker",
114                new String[] { "\\%", "%-)" },
115                new String[] { "1", "2" },
116                new String[] { "1", "2", "\\%", "%-)" });
117
118        // 0 more key.
119        assertInsertAdditionalMoreKeys("null & null", null, null, null);
120        assertInsertAdditionalMoreKeys("null & 1 additon",
121                null,
122                new String[] { "1" },
123                new String[] { "1" });
124        assertInsertAdditionalMoreKeys("null & 2 additons",
125                null,
126                new String[] { "1", "2" },
127                new String[] { "1", "2" });
128
129        // 0 additional more key.
130        assertInsertAdditionalMoreKeys("1 more key & null",
131                new String[] { "A" },
132                null,
133                new String[] { "A" });
134        assertInsertAdditionalMoreKeys("2 more keys & null",
135                new String[] { "A", "B" },
136                null,
137                new String[] { "A", "B" });
138
139        // No marker.
140        assertInsertAdditionalMoreKeys("1 more key & 1 addtional & no marker",
141                new String[] { "A" },
142                new String[] { "1" },
143                new String[] { "1", "A" });
144        assertInsertAdditionalMoreKeys("1 more key & 2 addtionals & no marker",
145                new String[] { "A" },
146                new String[] { "1", "2" },
147                new String[] { "1", "2", "A" });
148        assertInsertAdditionalMoreKeys("2 more keys & 1 addtional & no marker",
149                new String[] { "A", "B" },
150                new String[] { "1" },
151                new String[] { "1", "A", "B" });
152        assertInsertAdditionalMoreKeys("2 more keys & 2 addtionals & no marker",
153                new String[] { "A", "B" },
154                new String[] { "1", "2" },
155                new String[] { "1", "2", "A", "B" });
156
157        // 1 marker.
158        assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at head",
159                new String[] { "%", "A" },
160                new String[] { "1" },
161                new String[] { "1", "A" });
162        assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at tail",
163                new String[] { "A", "%" },
164                new String[] { "1" },
165                new String[] { "A", "1" });
166        assertInsertAdditionalMoreKeys("2 more keys & 1 additon & marker at middle",
167                new String[] { "A", "%", "B" },
168                new String[] { "1" },
169                new String[] { "A", "1", "B" });
170
171        // 1 marker & excess additional more keys.
172        assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at head",
173                new String[] { "%", "A", "B" },
174                new String[] { "1", "2" },
175                new String[] { "1", "A", "B", "2" });
176        assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at tail",
177                new String[] { "A", "B", "%" },
178                new String[] { "1", "2" },
179                new String[] { "A", "B", "1", "2" });
180        assertInsertAdditionalMoreKeys("2 more keys & 2 additons & marker at middle",
181                new String[] { "A", "%", "B" },
182                new String[] { "1", "2" },
183                new String[] { "A", "1", "B", "2" });
184
185        // 2 markers.
186        assertInsertAdditionalMoreKeys("0 more key & 2 addtional & 2 markers",
187                new String[] { "%", "%" },
188                new String[] { "1", "2" },
189                new String[] { "1", "2" });
190        assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at head",
191                new String[] { "%", "%", "A" },
192                new String[] { "1", "2" },
193                new String[] { "1", "2", "A" });
194        assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at tail",
195                new String[] { "A", "%", "%" },
196                new String[] { "1", "2" },
197                new String[] { "A", "1", "2" });
198        assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at middle",
199                new String[] { "A", "%", "%", "B" },
200                new String[] { "1", "2" },
201                new String[] { "A", "1", "2", "B" });
202        assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & middle",
203                new String[] { "%", "A", "%", "B" },
204                new String[] { "1", "2" },
205                new String[] { "1", "A", "2", "B" });
206        assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & tail",
207                new String[] { "%", "A", "B", "%" },
208                new String[] { "1", "2" },
209                new String[] { "1", "A", "B", "2" });
210        assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at middle & tail",
211                new String[] { "A", "%", "B", "%" },
212                new String[] { "1", "2" },
213                new String[] { "A", "1", "B", "2" });
214
215        // 2 markers & excess additional more keys.
216        assertInsertAdditionalMoreKeys("0 more key & 2 additons & 2 markers",
217                new String[] { "%", "%" },
218                new String[] { "1", "2", "3" },
219                new String[] { "1", "2", "3" });
220        assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at head",
221                new String[] { "%", "%", "A" },
222                new String[] { "1", "2", "3" },
223                new String[] { "1", "2", "A", "3" });
224        assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at tail",
225                new String[] { "A", "%", "%" },
226                new String[] { "1", "2", "3" },
227                new String[] { "A", "1", "2", "3" });
228        assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at middle",
229                new String[] { "A", "%", "%", "B" },
230                new String[] { "1", "2", "3" },
231                new String[] { "A", "1", "2", "B", "3" });
232        assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & middle",
233                new String[] { "%", "A", "%", "B" },
234                new String[] { "1", "2", "3" },
235                new String[] { "1", "A", "2", "B", "3" });
236        assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & tail",
237                new String[] { "%", "A", "B", "%" },
238                new String[] { "1", "2", "3" },
239                new String[] { "1", "A", "B", "2", "3" });
240        assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at middle & tail",
241                new String[] { "A", "%", "B", "%" },
242                new String[] { "1", "2", "3" },
243                new String[] { "A", "1", "B", "2", "3" });
244
245        // 0 addtional more key and excess markers.
246        assertInsertAdditionalMoreKeys("0 more key & null & excess marker",
247                new String[] { "%" },
248                null,
249                null);
250        assertInsertAdditionalMoreKeys("1 more key & null & excess marker at head",
251                new String[] { "%", "A" },
252                null,
253                new String[] { "A" });
254        assertInsertAdditionalMoreKeys("1 more key & null & excess marker at tail",
255                new String[] { "A", "%" },
256                null,
257                new String[] { "A" });
258        assertInsertAdditionalMoreKeys("2 more keys & null & excess marker at middle",
259                new String[] { "A", "%", "B" },
260                null,
261                new String[] { "A", "B" });
262        assertInsertAdditionalMoreKeys("2 more keys & null & excess markers",
263                new String[] { "%", "A", "%", "B", "%" },
264                null,
265                new String[] { "A", "B" });
266
267        // Excess markers.
268        assertInsertAdditionalMoreKeys("0 more key & 1 additon & excess marker",
269                new String[] { "%", "%" },
270                new String[] { "1" },
271                new String[] { "1" });
272        assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at head",
273                new String[] { "%", "%", "A" },
274                new String[] { "1" },
275                new String[] { "1", "A" });
276        assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at tail",
277                new String[] { "A", "%", "%" },
278                new String[] { "1" },
279                new String[] { "A", "1" });
280        assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess marker at middle",
281                new String[] { "A", "%", "%", "B" },
282                new String[] { "1" },
283                new String[] { "A", "1", "B" });
284        assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess markers",
285                new String[] { "%", "A", "%", "B", "%" },
286                new String[] { "1" },
287                new String[] { "1", "A", "B" });
288        assertInsertAdditionalMoreKeys("2 more keys & 2 additons & excess markers",
289                new String[] { "%", "A", "%", "B", "%" },
290                new String[] { "1", "2" },
291                new String[] { "1", "A", "2", "B" });
292        assertInsertAdditionalMoreKeys("2 more keys & 3 additons & excess markers",
293                new String[] { "%", "A", "%", "%", "B", "%" },
294                new String[] { "1", "2", "3" },
295                new String[] { "1", "A", "2", "3", "B" });
296    }
297
298    private static final String HAS_LABEL = "!hasLabel!";
299    private static final String NEEDS_DIVIDER = "!needsDividers!";
300    private static final String AUTO_COLUMN_ORDER = "!autoColumnOrder!";
301    private static final String FIXED_COLUMN_ORDER = "!fixedColumnOrder!";
302
303    private static void assertGetBooleanValue(final String message, final String key,
304            final String[] moreKeys, final String[] expected, final boolean expectedValue) {
305        final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length);
306        final boolean actualValue = MoreKeySpec.getBooleanValue(actual, key);
307        assertEquals(message + " [value]", expectedValue, actualValue);
308        assertArrayEquals(message, expected, actual);
309    }
310
311    @SuppressWarnings("static-method")
312    public void testGetBooleanValue() {
313        assertGetBooleanValue("Has label", HAS_LABEL,
314                new String[] { HAS_LABEL, "a", "b", "c" },
315                new String[] { null, "a", "b", "c" }, true);
316        // Upper case specification will not work.
317        assertGetBooleanValue("HAS LABEL", HAS_LABEL,
318                new String[] { HAS_LABEL.toUpperCase(Locale.ROOT), "a", "b", "c" },
319                new String[] { "!HASLABEL!", "a", "b", "c" }, false);
320
321        assertGetBooleanValue("No has label", HAS_LABEL,
322                new String[] { "a", "b", "c" },
323                new String[] { "a", "b", "c" }, false);
324        assertGetBooleanValue("No has label with fixed clumn order", HAS_LABEL,
325                new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" },
326                new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, false);
327
328        // Upper case specification will not work.
329        assertGetBooleanValue("Multiple has label", HAS_LABEL,
330                new String[] {
331                    "a", HAS_LABEL.toUpperCase(Locale.ROOT), "b", "c", HAS_LABEL, "d" },
332                new String[] {
333                    "a", "!HASLABEL!", "b", "c", null, "d" }, true);
334        // Upper case specification will not work.
335        assertGetBooleanValue("Multiple has label with needs dividers", HAS_LABEL,
336                new String[] {
337                    "a", HAS_LABEL, "b", NEEDS_DIVIDER, HAS_LABEL.toUpperCase(Locale.ROOT), "d" },
338                new String[] {
339                    "a", null, "b", NEEDS_DIVIDER, "!HASLABEL!", "d" }, true);
340    }
341
342    private static void assertGetIntValue(final String message, final String key,
343            final int defaultValue, final String[] moreKeys, final String[] expected,
344            final int expectedValue) {
345        final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length);
346        final int actualValue = MoreKeySpec.getIntValue(actual, key, defaultValue);
347        assertEquals(message + " [value]", expectedValue, actualValue);
348        assertArrayEquals(message, expected, actual);
349    }
350
351    @SuppressWarnings("static-method")
352    public void testGetIntValue() {
353        assertGetIntValue("Fixed column order 3", FIXED_COLUMN_ORDER, -1,
354                new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" },
355                new String[] { null, "a", "b", "c" }, 3);
356        // Upper case specification will not work.
357        assertGetIntValue("FIXED COLUMN ORDER 3", FIXED_COLUMN_ORDER, -1,
358                new String[] { FIXED_COLUMN_ORDER.toUpperCase(Locale.ROOT) + "3", "a", "b", "c" },
359                new String[] { "!FIXEDCOLUMNORDER!3", "a", "b", "c" }, -1);
360
361        assertGetIntValue("No fixed column order", FIXED_COLUMN_ORDER, -1,
362                new String[] { "a", "b", "c" },
363                new String[] { "a", "b", "c" }, -1);
364        assertGetIntValue("No fixed column order with auto column order", FIXED_COLUMN_ORDER, -1,
365                new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" },
366                new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" }, -1);
367
368        assertGetIntValue("Multiple fixed column order 3,5", FIXED_COLUMN_ORDER, -1,
369                new String[] { FIXED_COLUMN_ORDER + "3", "a", FIXED_COLUMN_ORDER + "5", "b" },
370                new String[] { null, "a", null, "b" }, 3);
371        // Upper case specification will not work.
372        assertGetIntValue("Multiple fixed column order 5,3 with has label", FIXED_COLUMN_ORDER, -1,
373                new String[] {
374                    FIXED_COLUMN_ORDER.toUpperCase(Locale.ROOT) + "5", HAS_LABEL, "a",
375                    FIXED_COLUMN_ORDER + "3", "b" },
376                new String[] { "!FIXEDCOLUMNORDER!5", HAS_LABEL, "a", null, "b" }, 3);
377    }
378}
379