diff options
Diffstat (limited to 'tests/src')
38 files changed, 3536 insertions, 2424 deletions
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java index afb2b0343..8e26e7fc7 100644 --- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java +++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,643 +17,39 @@ package com.android.inputmethod.keyboard.internal; import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED; -import static com.android.inputmethod.latin.Constants.CODE_OUTPUT_TEXT; import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED; -import android.content.Context; -import android.content.res.Resources; -import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.utils.RunInLocale; - -import java.util.Arrays; -import java.util.Locale; @SmallTest -public class KeySpecParserTests extends AndroidTestCase { - private final static Locale TEST_LOCALE = Locale.ENGLISH; - final KeyboardCodesSet mCodesSet = new KeyboardCodesSet(); - final KeyboardTextsSet mTextsSet = new KeyboardTextsSet(); - - private static final String CODE_SETTINGS = "!code/key_settings"; - private static final String ICON_SETTINGS = "!icon/settings_key"; - private static final String CODE_SETTINGS_UPPERCASE = CODE_SETTINGS.toUpperCase(Locale.ROOT); - private static final String ICON_SETTINGS_UPPERCASE = ICON_SETTINGS.toUpperCase(Locale.ROOT); - private static final String CODE_NON_EXISTING = "!code/non_existing"; - private static final String ICON_NON_EXISTING = "!icon/non_existing"; - - private int mCodeSettings; - private int mCodeActionNext; - private int mSettingsIconId; - +public final class KeySpecParserTests extends KeySpecParserTestsBase { @Override - protected void setUp() throws Exception { - super.setUp(); - - final String language = TEST_LOCALE.getLanguage(); - mCodesSet.setLanguage(language); - mTextsSet.setLanguage(language); - final Context context = getContext(); - new RunInLocale<Void>() { - @Override - protected Void job(final Resources res) { - mTextsSet.loadStringResources(context); - return null; - } - }.runInLocale(context.getResources(), TEST_LOCALE); - - mCodeSettings = KeySpecParser.parseCode( - CODE_SETTINGS, mCodesSet, CODE_UNSPECIFIED); - mCodeActionNext = KeySpecParser.parseCode( - "!code/key_action_next", mCodesSet, CODE_UNSPECIFIED); - mSettingsIconId = KeySpecParser.getIconId(ICON_SETTINGS); - } - - private void assertParser(String message, String moreKeySpec, String expectedLabel, - String expectedOutputText, int expectedIcon, int expectedCode) { - final String labelResolved = KeySpecParser.resolveTextReference(moreKeySpec, mTextsSet); - final MoreKeySpec spec = new MoreKeySpec(labelResolved, false /* needsToUpperCase */, - Locale.US, mCodesSet); - assertEquals(message + " [label]", expectedLabel, spec.mLabel); - assertEquals(message + " [ouptputText]", expectedOutputText, spec.mOutputText); + protected void assertParser(final String message, final String keySpec, + final String expectedLabel, final String expectedOutputText, final int expectedIcon, + final int expectedCode) { + final String keySpecResolved = mTextsSet.resolveTextReference(keySpec); + final String actualLabel = KeySpecParser.getLabel(keySpecResolved); + final String actualOutputText = KeySpecParser.getOutputText(keySpecResolved); + final int actualIcon = KeySpecParser.getIconId(keySpecResolved); + final int actualCode = KeySpecParser.getCode(keySpecResolved); + assertEquals(message + " [label]", expectedLabel, actualLabel); + assertEquals(message + " [ouptputText]", expectedOutputText, actualOutputText); assertEquals(message + " [icon]", KeyboardIconsSet.getIconName(expectedIcon), - KeyboardIconsSet.getIconName(spec.mIconId)); + KeyboardIconsSet.getIconName(actualIcon)); assertEquals(message + " [code]", Constants.printableCode(expectedCode), - Constants.printableCode(spec.mCode)); - } - - private void assertParserError(String message, String moreKeySpec, String expectedLabel, - String expectedOutputText, int expectedIcon, int expectedCode) { - try { - assertParser(message, moreKeySpec, expectedLabel, expectedOutputText, expectedIcon, - expectedCode); - fail(message); - } catch (Exception pcpe) { - // success. - } - } - - // \U001d11e: MUSICAL SYMBOL G CLEF - private static final String PAIR1 = "\ud834\udd1e"; - private static final int CODE1 = PAIR1.codePointAt(0); - // \U001d122: MUSICAL SYMBOL F CLEF - private static final String PAIR2 = "\ud834\udd22"; - private static final int CODE2 = PAIR2.codePointAt(0); - // \U002f8a6: CJK COMPATIBILITY IDEOGRAPH-2F8A6; variant character of \u6148. - private static final String PAIR3 = "\ud87e\udca6"; - private static final String SURROGATE1 = PAIR1 + PAIR2; - private static final String SURROGATE2 = PAIR1 + PAIR2 + PAIR3; - - public void testSingleLetter() { - assertParser("Single letter", "a", - "a", null, ICON_UNDEFINED, 'a'); - assertParser("Single surrogate", PAIR1, - PAIR1, null, ICON_UNDEFINED, CODE1); - assertParser("Single escaped bar", "\\|", - "|", null, ICON_UNDEFINED, '|'); - assertParser("Single escaped escape", "\\\\", - "\\", null, ICON_UNDEFINED, '\\'); - assertParser("Single comma", ",", - ",", null, ICON_UNDEFINED, ','); - assertParser("Single escaped comma", "\\,", - ",", null, ICON_UNDEFINED, ','); - assertParser("Single escaped letter", "\\a", - "a", null, ICON_UNDEFINED, 'a'); - assertParser("Single escaped surrogate", "\\" + PAIR2, - PAIR2, null, ICON_UNDEFINED, CODE2); - assertParser("Single bang", "!", - "!", null, ICON_UNDEFINED, '!'); - assertParser("Single escaped bang", "\\!", - "!", null, ICON_UNDEFINED, '!'); - assertParser("Single output text letter", "a|a", - "a", null, ICON_UNDEFINED, 'a'); - assertParser("Single surrogate pair outputText", "G Clef|" + PAIR1, - "G Clef", null, ICON_UNDEFINED, CODE1); - assertParser("Single letter with outputText", "a|abc", - "a", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with surrogate outputText", "a|" + SURROGATE1, - "a", SURROGATE1, ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single surrogate with outputText", PAIR3 + "|abc", - PAIR3, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with escaped outputText", "a|a\\|c", - "a", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with escaped surrogate outputText", - "a|" + PAIR1 + "\\|" + PAIR2, - "a", PAIR1 + "|" + PAIR2, ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with comma outputText", "a|a,b", - "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with escaped comma outputText", "a|a\\,b", - "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with outputText starts with bang", "a|!bc", - "a", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with surrogate outputText starts with bang", "a|!" + SURROGATE2, - "a", "!" + SURROGATE2, ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with outputText contains bang", "a|a!c", - "a", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with escaped bang outputText", "a|\\!bc", - "a", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single escaped escape with single outputText", "\\\\|\\\\", - "\\", null, ICON_UNDEFINED, '\\'); - assertParser("Single escaped bar with single outputText", "\\||\\|", - "|", null, ICON_UNDEFINED, '|'); - assertParser("Single letter with code", "a|" + CODE_SETTINGS, - "a", null, ICON_UNDEFINED, mCodeSettings); - } - - public void testLabel() { - assertParser("Simple label", "abc", - "abc", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Simple surrogate label", SURROGATE1, - SURROGATE1, SURROGATE1, ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped bar", "a\\|c", - "a|c", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Surrogate label with escaped bar", PAIR1 + "\\|" + PAIR2, - PAIR1 + "|" + PAIR2, PAIR1 + "|" + PAIR2, - ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped escape", "a\\\\c", - "a\\c", "a\\c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with comma", "a,c", - "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped comma", "a\\,c", - "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label starts with bang", "!bc", - "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Surrogate label starts with bang", "!" + SURROGATE1, - "!" + SURROGATE1, "!" + SURROGATE1, ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label contains bang", "a!c", - "a!c", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped bang", "\\!bc", - "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped letter", "\\abc", - "abc", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with outputText", "abc|def", - "abc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with comma and outputText", "a,c|def", - "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped comma label with outputText", "a\\,c|def", - "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped label with outputText", "a\\|c|def", - "a|c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped bar outputText", "abc|d\\|f", - "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped escape label with outputText", "a\\\\|def", - "a\\", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label starts with bang and outputText", "!bc|def", - "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label contains bang label and outputText", "a!c|def", - "a!c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped bang label with outputText", "\\!bc|def", - "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with comma outputText", "abc|a,b", - "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped comma outputText", "abc|a\\,b", - "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with outputText starts with bang", "abc|!bc", - "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with outputText contains bang", "abc|a!c", - "abc", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped bang outputText", "abc|\\!bc", - "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped bar outputText", "abc|d\\|f", - "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped bar label with escaped bar outputText", "a\\|c|d\\|f", - "a|c", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with code", "abc|" + CODE_SETTINGS, - "abc", null, ICON_UNDEFINED, mCodeSettings); - assertParser("Escaped label with code", "a\\|c|" + CODE_SETTINGS, - "a|c", null, ICON_UNDEFINED, mCodeSettings); - } - - public void testIconAndCode() { - assertParser("Icon with outputText", ICON_SETTINGS + "|abc", - null, "abc", mSettingsIconId, CODE_OUTPUT_TEXT); - assertParser("Icon with outputText starts with bang", ICON_SETTINGS + "|!bc", - null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT); - assertParser("Icon with outputText contains bang", ICON_SETTINGS + "|a!c", - null, "a!c", mSettingsIconId, CODE_OUTPUT_TEXT); - assertParser("Icon with escaped bang outputText", ICON_SETTINGS + "|\\!bc", - null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT); - assertParser("Label starts with bang and code", "!bc|" + CODE_SETTINGS, - "!bc", null, ICON_UNDEFINED, mCodeSettings); - assertParser("Label contains bang and code", "a!c|" + CODE_SETTINGS, - "a!c", null, ICON_UNDEFINED, mCodeSettings); - assertParser("Escaped bang label with code", "\\!bc|" + CODE_SETTINGS, - "!bc", null, ICON_UNDEFINED, mCodeSettings); - assertParser("Icon with code", ICON_SETTINGS + "|" + CODE_SETTINGS, - null, null, mSettingsIconId, mCodeSettings); - } - - public void testResourceReference() { - assertParser("Settings as more key", "!text/settings_as_more_key", - null, null, mSettingsIconId, mCodeSettings); - - assertParser("Action next as more key", "!text/label_next_key|!code/key_action_next", - "Next", null, ICON_UNDEFINED, mCodeActionNext); - - assertParser("Popular domain", - "!text/keylabel_for_popular_domain|!text/keylabel_for_popular_domain ", - ".com", ".com ", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + Constants.printableCode(actualCode)); } - public void testFormatError() { - assertParserError("Empty spec", "", null, - null, ICON_UNDEFINED, CODE_UNSPECIFIED); - assertParserError("Empty label with outputText", "|a", - null, "a", ICON_UNDEFINED, CODE_UNSPECIFIED); - assertParserError("Empty label with code", "|" + CODE_SETTINGS, - null, null, ICON_UNDEFINED, mCodeSettings); - assertParserError("Empty outputText with label", "a|", - "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); - assertParserError("Empty outputText with icon", ICON_SETTINGS + "|", - null, null, mSettingsIconId, CODE_UNSPECIFIED); - assertParserError("Empty icon and code", "|", + // TODO: Remove this method. + // These should throw {@link KeySpecParserError} when Key.keyLabel attribute become mandatory. + public void testEmptySpec() { + assertParser("Null spec", null, + null, null, ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParser("Empty spec", "", null, null, ICON_UNDEFINED, CODE_UNSPECIFIED); - assertParserError("Icon without code", ICON_SETTINGS, - null, null, mSettingsIconId, CODE_UNSPECIFIED); - assertParserError("Non existing icon", ICON_NON_EXISTING + "|abc", - null, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParserError("Non existing code", "abc|" + CODE_NON_EXISTING, - "abc", null, ICON_UNDEFINED, CODE_UNSPECIFIED); - assertParserError("Third bar at end", "a|b|", - "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); - assertParserError("Multiple bar", "a|b|c", - "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); - assertParserError("Multiple bar with label and code", "a|" + CODE_SETTINGS + "|c", - "a", null, ICON_UNDEFINED, mCodeSettings); - assertParserError("Multiple bar with icon and outputText", ICON_SETTINGS + "|b|c", - null, null, mSettingsIconId, CODE_UNSPECIFIED); - assertParserError("Multiple bar with icon and code", - ICON_SETTINGS + "|" + CODE_SETTINGS + "|c", - null, null, mSettingsIconId, mCodeSettings); - } - - public void testUselessUpperCaseSpecifier() { - assertParser("Single letter with CODE", "a|" + CODE_SETTINGS_UPPERCASE, - "a", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with CODE", "abc|" + CODE_SETTINGS_UPPERCASE, - "abc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped label with CODE", "a\\|c|" + CODE_SETTINGS_UPPERCASE, - "a|c", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("ICON with outputText", ICON_SETTINGS_UPPERCASE + "|abc", - "!ICON/SETTINGS_KEY", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("ICON with outputText starts with bang", ICON_SETTINGS_UPPERCASE + "|!bc", - "!ICON/SETTINGS_KEY", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("ICON with outputText contains bang", ICON_SETTINGS_UPPERCASE + "|a!c", - "!ICON/SETTINGS_KEY", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("ICON with escaped bang outputText", ICON_SETTINGS_UPPERCASE + "|\\!bc", - "!ICON/SETTINGS_KEY", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label starts with bang and CODE", "!bc|" + CODE_SETTINGS_UPPERCASE, - "!bc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label contains bang and CODE", "a!c|" + CODE_SETTINGS_UPPERCASE, - "a!c", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped bang label with CODE", "\\!bc|" + CODE_SETTINGS_UPPERCASE, - "!bc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("ICON with CODE", ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE, - "!ICON/SETTINGS_KEY", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("SETTINGS AS MORE KEY", "!TEXT/SETTINGS_AS_MORE_KEY", - "!TEXT/SETTINGS_AS_MORE_KEY", "!TEXT/SETTINGS_AS_MORE_KEY", ICON_UNDEFINED, - CODE_OUTPUT_TEXT); - assertParser("ACTION NEXT AS MORE KEY", "!TEXT/LABEL_NEXT_KEY|!CODE/KEY_ACTION_NEXT", - "!TEXT/LABEL_NEXT_KEY", "!CODE/KEY_ACTION_NEXT", ICON_UNDEFINED, - CODE_OUTPUT_TEXT); - assertParser("POPULAR DOMAIN", - "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN|!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN ", - "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN", "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN ", - ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParserError("Empty label with CODE", "|" + CODE_SETTINGS_UPPERCASE, - null, null, ICON_UNDEFINED, mCodeSettings); - assertParserError("Empty outputText with ICON", ICON_SETTINGS_UPPERCASE + "|", - null, null, mSettingsIconId, CODE_UNSPECIFIED); - assertParser("ICON without code", ICON_SETTINGS_UPPERCASE, - "!ICON/SETTINGS_KEY", "!ICON/SETTINGS_KEY", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParserError("Multiple bar with label and CODE", "a|" + CODE_SETTINGS_UPPERCASE + "|c", - "a", null, ICON_UNDEFINED, mCodeSettings); - assertParserError("Multiple bar with ICON and outputText", ICON_SETTINGS_UPPERCASE + "|b|c", - null, null, mSettingsIconId, CODE_UNSPECIFIED); - assertParserError("Multiple bar with ICON and CODE", - ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE + "|c", - null, null, mSettingsIconId, mCodeSettings); - } - - private static void assertArrayEquals(String message, Object[] expected, Object[] actual) { - if (expected == actual) { - return; - } - if (expected == null || actual == null) { - assertEquals(message, Arrays.toString(expected), Arrays.toString(actual)); - return; - } - if (expected.length != actual.length) { - assertEquals(message + " [length]", Arrays.toString(expected), Arrays.toString(actual)); - return; - } - for (int i = 0; i < expected.length; i++) { - assertEquals(message + " [" + i + "]", - Arrays.toString(expected), Arrays.toString(actual)); - } - } - - private static void assertInsertAdditionalMoreKeys(String message, String[] moreKeys, - String[] additionalMoreKeys, String[] expected) { - final String[] actual = - KeySpecParser.insertAdditionalMoreKeys( moreKeys, additionalMoreKeys); - assertArrayEquals(message, expected, actual); - } - - public void testEmptyEntry() { - assertInsertAdditionalMoreKeys("null more keys and null additons", - null, - null, - null); - assertInsertAdditionalMoreKeys("null more keys and empty additons", - null, - new String[0], - null); - assertInsertAdditionalMoreKeys("empty more keys and null additons", - new String[0], - null, - null); - assertInsertAdditionalMoreKeys("empty more keys and empty additons", - new String[0], - new String[0], - null); - - assertInsertAdditionalMoreKeys("filter out empty more keys", - new String[] { null, "a", "", "b", null }, - null, - new String[] { "a", "b" }); - assertInsertAdditionalMoreKeys("filter out empty additons", - new String[] { "a", "%", "b", "%", "c", "%", "d" }, - new String[] { null, "A", "", "B", null }, - new String[] { "a", "A", "b", "B", "c", "d" }); - } - - public void testInsertAdditionalMoreKeys() { - // Escaped marker. - assertInsertAdditionalMoreKeys("escaped marker", - new String[] { "\\%", "%-)" }, - new String[] { "1", "2" }, - new String[] { "1", "2", "\\%", "%-)" }); - - // 0 more key. - assertInsertAdditionalMoreKeys("null & null", null, null, null); - assertInsertAdditionalMoreKeys("null & 1 additon", - null, - new String[] { "1" }, - new String[] { "1" }); - assertInsertAdditionalMoreKeys("null & 2 additons", - null, - new String[] { "1", "2" }, - new String[] { "1", "2" }); - - // 0 additional more key. - assertInsertAdditionalMoreKeys("1 more key & null", - new String[] { "A" }, - null, - new String[] { "A" }); - assertInsertAdditionalMoreKeys("2 more keys & null", - new String[] { "A", "B" }, - null, - new String[] { "A", "B" }); - - // No marker. - assertInsertAdditionalMoreKeys("1 more key & 1 addtional & no marker", - new String[] { "A" }, - new String[] { "1" }, - new String[] { "1", "A" }); - assertInsertAdditionalMoreKeys("1 more key & 2 addtionals & no marker", - new String[] { "A" }, - new String[] { "1", "2" }, - new String[] { "1", "2", "A" }); - assertInsertAdditionalMoreKeys("2 more keys & 1 addtional & no marker", - new String[] { "A", "B" }, - new String[] { "1" }, - new String[] { "1", "A", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 addtionals & no marker", - new String[] { "A", "B" }, - new String[] { "1", "2" }, - new String[] { "1", "2", "A", "B" }); - - // 1 marker. - assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at head", - new String[] { "%", "A" }, - new String[] { "1" }, - new String[] { "1", "A" }); - assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at tail", - new String[] { "A", "%" }, - new String[] { "1" }, - new String[] { "A", "1" }); - assertInsertAdditionalMoreKeys("2 more keys & 1 additon & marker at middle", - new String[] { "A", "%", "B" }, - new String[] { "1" }, - new String[] { "A", "1", "B" }); - - // 1 marker & excess additional more keys. - assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at head", - new String[] { "%", "A", "B" }, - new String[] { "1", "2" }, - new String[] { "1", "A", "B", "2" }); - assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at tail", - new String[] { "A", "B", "%" }, - new String[] { "1", "2" }, - new String[] { "A", "B", "1", "2" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 additons & marker at middle", - new String[] { "A", "%", "B" }, - new String[] { "1", "2" }, - new String[] { "A", "1", "B", "2" }); - - // 2 markers. - assertInsertAdditionalMoreKeys("0 more key & 2 addtional & 2 markers", - new String[] { "%", "%" }, - new String[] { "1", "2" }, - new String[] { "1", "2" }); - assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at head", - new String[] { "%", "%", "A" }, - new String[] { "1", "2" }, - new String[] { "1", "2", "A" }); - assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at tail", - new String[] { "A", "%", "%" }, - new String[] { "1", "2" }, - new String[] { "A", "1", "2" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at middle", - new String[] { "A", "%", "%", "B" }, - new String[] { "1", "2" }, - new String[] { "A", "1", "2", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & middle", - new String[] { "%", "A", "%", "B" }, - new String[] { "1", "2" }, - new String[] { "1", "A", "2", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & tail", - new String[] { "%", "A", "B", "%" }, - new String[] { "1", "2" }, - new String[] { "1", "A", "B", "2" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at middle & tail", - new String[] { "A", "%", "B", "%" }, - new String[] { "1", "2" }, - new String[] { "A", "1", "B", "2" }); - - // 2 markers & excess additional more keys. - assertInsertAdditionalMoreKeys("0 more key & 2 additons & 2 markers", - new String[] { "%", "%" }, - new String[] { "1", "2", "3" }, - new String[] { "1", "2", "3" }); - assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at head", - new String[] { "%", "%", "A" }, - new String[] { "1", "2", "3" }, - new String[] { "1", "2", "A", "3" }); - assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at tail", - new String[] { "A", "%", "%" }, - new String[] { "1", "2", "3" }, - new String[] { "A", "1", "2", "3" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at middle", - new String[] { "A", "%", "%", "B" }, - new String[] { "1", "2", "3" }, - new String[] { "A", "1", "2", "B", "3" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & middle", - new String[] { "%", "A", "%", "B" }, - new String[] { "1", "2", "3" }, - new String[] { "1", "A", "2", "B", "3" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & tail", - new String[] { "%", "A", "B", "%" }, - new String[] { "1", "2", "3" }, - new String[] { "1", "A", "B", "2", "3" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at middle & tail", - new String[] { "A", "%", "B", "%" }, - new String[] { "1", "2", "3" }, - new String[] { "A", "1", "B", "2", "3" }); - - // 0 addtional more key and excess markers. - assertInsertAdditionalMoreKeys("0 more key & null & excess marker", - new String[] { "%" }, - null, - null); - assertInsertAdditionalMoreKeys("1 more key & null & excess marker at head", - new String[] { "%", "A" }, - null, - new String[] { "A" }); - assertInsertAdditionalMoreKeys("1 more key & null & excess marker at tail", - new String[] { "A", "%" }, - null, - new String[] { "A" }); - assertInsertAdditionalMoreKeys("2 more keys & null & excess marker at middle", - new String[] { "A", "%", "B" }, - null, - new String[] { "A", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & null & excess markers", - new String[] { "%", "A", "%", "B", "%" }, - null, - new String[] { "A", "B" }); - - // Excess markers. - assertInsertAdditionalMoreKeys("0 more key & 1 additon & excess marker", - new String[] { "%", "%" }, - new String[] { "1" }, - new String[] { "1" }); - assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at head", - new String[] { "%", "%", "A" }, - new String[] { "1" }, - new String[] { "1", "A" }); - assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at tail", - new String[] { "A", "%", "%" }, - new String[] { "1" }, - new String[] { "A", "1" }); - assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess marker at middle", - new String[] { "A", "%", "%", "B" }, - new String[] { "1" }, - new String[] { "A", "1", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess markers", - new String[] { "%", "A", "%", "B", "%" }, - new String[] { "1" }, - new String[] { "1", "A", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 additons & excess markers", - new String[] { "%", "A", "%", "B", "%" }, - new String[] { "1", "2" }, - new String[] { "1", "A", "2", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & 3 additons & excess markers", - new String[] { "%", "A", "%", "%", "B", "%" }, - new String[] { "1", "2", "3" }, - new String[] { "1", "A", "2", "3", "B" }); - } - - private static final String HAS_LABEL = "!hasLabel!"; - private static final String NEEDS_DIVIDER = "!needsDividers!"; - private static final String AUTO_COLUMN_ORDER = "!autoColumnOrder!"; - private static final String FIXED_COLUMN_ORDER = "!fixedColumnOrder!"; - - private static void assertGetBooleanValue(String message, String key, String[] moreKeys, - String[] expected, boolean expectedValue) { - final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length); - final boolean actualValue = KeySpecParser.getBooleanValue(actual, key); - assertEquals(message + " [value]", expectedValue, actualValue); - assertArrayEquals(message, expected, actual); - } - - public void testGetBooleanValue() { - assertGetBooleanValue("Has label", HAS_LABEL, - new String[] { HAS_LABEL, "a", "b", "c" }, - new String[] { null, "a", "b", "c" }, true); - // Upper case specification will not work. - assertGetBooleanValue("HAS LABEL", HAS_LABEL, - new String[] { HAS_LABEL.toUpperCase(Locale.ROOT), "a", "b", "c" }, - new String[] { "!HASLABEL!", "a", "b", "c" }, false); - - assertGetBooleanValue("No has label", HAS_LABEL, - new String[] { "a", "b", "c" }, - new String[] { "a", "b", "c" }, false); - assertGetBooleanValue("No has label with fixed clumn order", HAS_LABEL, - new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, - new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, false); - - // Upper case specification will not work. - assertGetBooleanValue("Multiple has label", HAS_LABEL, - new String[] { - "a", HAS_LABEL.toUpperCase(Locale.ROOT), "b", "c", HAS_LABEL, "d" }, - new String[] { - "a", "!HASLABEL!", "b", "c", null, "d" }, true); - // Upper case specification will not work. - assertGetBooleanValue("Multiple has label with needs dividers", HAS_LABEL, - new String[] { - "a", HAS_LABEL, "b", NEEDS_DIVIDER, HAS_LABEL.toUpperCase(Locale.ROOT), "d" }, - new String[] { - "a", null, "b", NEEDS_DIVIDER, "!HASLABEL!", "d" }, true); - } - - private static void assertGetIntValue(String message, String key, int defaultValue, - String[] moreKeys, String[] expected, int expectedValue) { - final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length); - final int actualValue = KeySpecParser.getIntValue(actual, key, defaultValue); - assertEquals(message + " [value]", expectedValue, actualValue); - assertArrayEquals(message, expected, actual); - } - - public void testGetIntValue() { - assertGetIntValue("Fixed column order 3", FIXED_COLUMN_ORDER, -1, - new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, - new String[] { null, "a", "b", "c" }, 3); - // Upper case specification will not work. - assertGetIntValue("FIXED COLUMN ORDER 3", FIXED_COLUMN_ORDER, -1, - new String[] { FIXED_COLUMN_ORDER.toUpperCase(Locale.ROOT) + "3", "a", "b", "c" }, - new String[] { "!FIXEDCOLUMNORDER!3", "a", "b", "c" }, -1); - - assertGetIntValue("No fixed column order", FIXED_COLUMN_ORDER, -1, - new String[] { "a", "b", "c" }, - new String[] { "a", "b", "c" }, -1); - assertGetIntValue("No fixed column order with auto column order", FIXED_COLUMN_ORDER, -1, - new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" }, - new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" }, -1); - - assertGetIntValue("Multiple fixed column order 3,5", FIXED_COLUMN_ORDER, -1, - new String[] { FIXED_COLUMN_ORDER + "3", "a", FIXED_COLUMN_ORDER + "5", "b" }, - new String[] { null, "a", null, "b" }, 3); - // Upper case specification will not work. - assertGetIntValue("Multiple fixed column order 5,3 with has label", FIXED_COLUMN_ORDER, -1, - new String[] { - FIXED_COLUMN_ORDER.toUpperCase(Locale.ROOT) + "5", HAS_LABEL, "a", - FIXED_COLUMN_ORDER + "3", "b" }, - new String[] { "!FIXEDCOLUMNORDER!5", HAS_LABEL, "a", null, "b" }, 3); } } diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTestsBase.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTestsBase.java new file mode 100644 index 000000000..c342533c8 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTestsBase.java @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.keyboard.internal; + +import static com.android.inputmethod.keyboard.internal.KeyboardCodesSet.PREFIX_CODE; +import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED; +import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.PREFIX_ICON; +import static com.android.inputmethod.latin.Constants.CODE_OUTPUT_TEXT; +import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED; + +import android.content.Context; +import android.content.res.Resources; +import android.test.AndroidTestCase; + +import com.android.inputmethod.latin.utils.RunInLocale; + +import java.util.Locale; + +abstract class KeySpecParserTestsBase extends AndroidTestCase { + private final static Locale TEST_LOCALE = Locale.ENGLISH; + protected final KeyboardTextsSet mTextsSet = new KeyboardTextsSet(); + + private static final String CODE_SETTINGS_NAME = "key_settings"; + private static final String CODE_SETTINGS = PREFIX_CODE + CODE_SETTINGS_NAME; + private static final String ICON_SETTINGS_NAME = "settings_key"; + private static final String ICON_SETTINGS = PREFIX_ICON + ICON_SETTINGS_NAME; + private static final String CODE_SETTINGS_UPPERCASE = CODE_SETTINGS.toUpperCase(Locale.ROOT); + private static final String ICON_SETTINGS_UPPERCASE = ICON_SETTINGS.toUpperCase(Locale.ROOT); + private static final String CODE_NON_EXISTING = PREFIX_CODE + "non_existing"; + private static final String ICON_NON_EXISTING = PREFIX_ICON + "non_existing"; + + private int mCodeSettings; + private int mCodeActionNext; + private int mSettingsIconId; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mTextsSet.setLocale(TEST_LOCALE); + final Context context = getContext(); + new RunInLocale<Void>() { + @Override + protected Void job(final Resources res) { + mTextsSet.loadStringResources(context); + return null; + } + }.runInLocale(context.getResources(), TEST_LOCALE); + + mCodeSettings = KeyboardCodesSet.getCode(CODE_SETTINGS_NAME); + mCodeActionNext = KeyboardCodesSet.getCode("key_action_next"); + mSettingsIconId = KeyboardIconsSet.getIconId(ICON_SETTINGS_NAME); + } + + abstract protected void assertParser(final String message, final String keySpec, + final String expectedLabel, final String expectedOutputText, final int expectedIcon, + final int expectedCode); + + protected void assertParserError(final String message, final String keySpec, + final String expectedLabel, final String expectedOutputText, final int expectedIconId, + final int expectedCode) { + try { + assertParser(message, keySpec, expectedLabel, expectedOutputText, expectedIconId, + expectedCode); + fail(message); + } catch (Exception pcpe) { + // success. + } + } + + // \U001d11e: MUSICAL SYMBOL G CLEF + private static final String SURROGATE_PAIR1 = "\ud834\udd1e"; + private static final int SURROGATE_CODE1 = SURROGATE_PAIR1.codePointAt(0); + // \U001d122: MUSICAL SYMBOL F CLEF + private static final String SURROGATE_PAIR2 = "\ud834\udd22"; + private static final int SURROGATE_CODE2 = SURROGATE_PAIR2.codePointAt(0); + // \U002f8a6: CJK COMPATIBILITY IDEOGRAPH-2F8A6; variant character of \u6148. + private static final String SURROGATE_PAIR3 = "\ud87e\udca6"; + private static final String SURROGATE_PAIRS4 = SURROGATE_PAIR1 + SURROGATE_PAIR2; + private static final String SURROGATE_PAIRS5 = SURROGATE_PAIRS4 + SURROGATE_PAIR3; + + public void testSingleLetter() { + assertParser("Single letter", "a", + "a", null, ICON_UNDEFINED, 'a'); + assertParser("Single surrogate", SURROGATE_PAIR1, + SURROGATE_PAIR1, null, ICON_UNDEFINED, SURROGATE_CODE1); + assertParser("Sole vertical bar", "|", + "|", null, ICON_UNDEFINED, '|'); + assertParser("Single escaped vertical bar", "\\|", + "|", null, ICON_UNDEFINED, '|'); + assertParser("Single escaped escape", "\\\\", + "\\", null, ICON_UNDEFINED, '\\'); + assertParser("Single comma", ",", + ",", null, ICON_UNDEFINED, ','); + assertParser("Single escaped comma", "\\,", + ",", null, ICON_UNDEFINED, ','); + assertParser("Single escaped letter", "\\a", + "a", null, ICON_UNDEFINED, 'a'); + assertParser("Single escaped surrogate", "\\" + SURROGATE_PAIR2, + SURROGATE_PAIR2, null, ICON_UNDEFINED, SURROGATE_CODE2); + assertParser("Single bang", "!", + "!", null, ICON_UNDEFINED, '!'); + assertParser("Single escaped bang", "\\!", + "!", null, ICON_UNDEFINED, '!'); + assertParser("Single output text letter", "a|a", + "a", null, ICON_UNDEFINED, 'a'); + assertParser("Single surrogate pair outputText", "G Clef|" + SURROGATE_PAIR1, + "G Clef", null, ICON_UNDEFINED, SURROGATE_CODE1); + assertParser("Single letter with outputText", "a|abc", + "a", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with surrogate outputText", "a|" + SURROGATE_PAIRS4, + "a", SURROGATE_PAIRS4, ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single surrogate with outputText", SURROGATE_PAIR3 + "|abc", + SURROGATE_PAIR3, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with escaped outputText", "a|a\\|c", + "a", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with escaped surrogate outputText", + "a|" + SURROGATE_PAIR1 + "\\|" + SURROGATE_PAIR2, + "a", SURROGATE_PAIR1 + "|" + SURROGATE_PAIR2, ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with comma outputText", "a|a,b", + "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with escaped comma outputText", "a|a\\,b", + "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with outputText starts with bang", "a|!bc", + "a", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with surrogate outputText starts with bang", + "a|!" + SURROGATE_PAIRS5, + "a", "!" + SURROGATE_PAIRS5, ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with outputText contains bang", "a|a!c", + "a", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with escaped bang outputText", "a|\\!bc", + "a", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single escaped escape with single outputText", "\\\\|\\\\", + "\\", null, ICON_UNDEFINED, '\\'); + assertParser("Single escaped bar with single outputText", "\\||\\|", + "|", null, ICON_UNDEFINED, '|'); + assertParser("Single letter with code", "a|" + CODE_SETTINGS, + "a", null, ICON_UNDEFINED, mCodeSettings); + } + + public void testLabel() { + assertParser("Simple label", "abc", + "abc", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Simple surrogate label", SURROGATE_PAIRS4, + SURROGATE_PAIRS4, SURROGATE_PAIRS4, ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped bar", "a\\|c", + "a|c", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Surrogate label with escaped bar", SURROGATE_PAIR1 + "\\|" + SURROGATE_PAIR2, + SURROGATE_PAIR1 + "|" + SURROGATE_PAIR2, SURROGATE_PAIR1 + "|" + SURROGATE_PAIR2, + ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped escape", "a\\\\c", + "a\\c", "a\\c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with comma", "a,c", + "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped comma", "a\\,c", + "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label starts with bang", "!bc", + "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Surrogate label starts with bang", "!" + SURROGATE_PAIRS4, + "!" + SURROGATE_PAIRS4, "!" + SURROGATE_PAIRS4, ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label contains bang", "a!c", + "a!c", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped bang", "\\!bc", + "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped letter", "\\abc", + "abc", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with outputText", "abc|def", + "abc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with comma and outputText", "a,c|def", + "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped comma label with outputText", "a\\,c|def", + "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped label with outputText", "a\\|c|def", + "a|c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped bar outputText", "abc|d\\|f", + "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped escape label with outputText", "a\\\\|def", + "a\\", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label starts with bang and outputText", "!bc|def", + "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label contains bang label and outputText", "a!c|def", + "a!c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped bang label with outputText", "\\!bc|def", + "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with comma outputText", "abc|a,b", + "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped comma outputText", "abc|a\\,b", + "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with outputText starts with bang", "abc|!bc", + "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with outputText contains bang", "abc|a!c", + "abc", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped bang outputText", "abc|\\!bc", + "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped bar outputText", "abc|d\\|f", + "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped bar label with escaped bar outputText", "a\\|c|d\\|f", + "a|c", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with code", "abc|" + CODE_SETTINGS, + "abc", null, ICON_UNDEFINED, mCodeSettings); + assertParser("Escaped label with code", "a\\|c|" + CODE_SETTINGS, + "a|c", null, ICON_UNDEFINED, mCodeSettings); + } + + public void testCodes() { + assertParser("Hexadecimal code", "a|0x1000", + "a", null, ICON_UNDEFINED, 0x1000); + assertParserError("Illegal hexadecimal code", "a|0x100X", + "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParser("Escaped hexadecimal code 1", "a|\\0x1000", + "a", "0x1000", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped hexadecimal code 2", "a|0\\x1000", + "a", "0x1000", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped hexadecimal code 2", "a|0\\x1000", + "a", "0x1000", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParserError("Illegally escaped hexadecimal code", "a|0x1\\000", + "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); + // This is a workaround to have a key that has a supplementary code point. We can't put a + // string in resource as a XML entity of a supplementary code point or a surrogate pair. + // TODO: Should pass this test. +// assertParser("Hexadecimal supplementary code", String.format("a|0x%06x", SURROGATE_CODE2), +// SURROGATE_PAIR2, null, ICON_UNDEFINED, SURROGATE_CODE2); + assertParser("Zero is treated as output text", "a|0", + "a", null, ICON_UNDEFINED, '0'); + assertParser("Digit is treated as output text", "a|3", + "a", null, ICON_UNDEFINED, '3'); + assertParser("Decimal number is treated as an output text", "a|2014", + "a", "2014", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + } + + public void testIcons() { + assertParser("Icon with single letter", ICON_SETTINGS + "|a", + null, null, mSettingsIconId, 'a'); + assertParser("Icon with outputText", ICON_SETTINGS + "|abc", + null, "abc", mSettingsIconId, CODE_OUTPUT_TEXT); + assertParser("Icon with outputText starts with bang", ICON_SETTINGS + "|!bc", + null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT); + assertParser("Icon with outputText contains bang", ICON_SETTINGS + "|a!c", + null, "a!c", mSettingsIconId, CODE_OUTPUT_TEXT); + assertParser("Icon with escaped bang outputText", ICON_SETTINGS + "|\\!bc", + null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT); + assertParser("Label starts with bang and code", "!bc|" + CODE_SETTINGS, + "!bc", null, ICON_UNDEFINED, mCodeSettings); + assertParser("Label contains bang and code", "a!c|" + CODE_SETTINGS, + "a!c", null, ICON_UNDEFINED, mCodeSettings); + assertParser("Escaped bang label with code", "\\!bc|" + CODE_SETTINGS, + "!bc", null, ICON_UNDEFINED, mCodeSettings); + assertParser("Icon with code", ICON_SETTINGS + "|" + CODE_SETTINGS, + null, null, mSettingsIconId, mCodeSettings); + } + + public void testResourceReference() { + assertParser("Settings as more key", "!text/settings_as_more_key", + null, null, mSettingsIconId, mCodeSettings); + + assertParser("Action next as more key", "!text/label_next_key|!code/key_action_next", + "Next", null, ICON_UNDEFINED, mCodeActionNext); + + assertParser("Popular domain", + "!text/keylabel_for_popular_domain|!text/keylabel_for_popular_domain ", + ".com", ".com ", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + } + + public void testFormatError() { + assertParserError("Empty label with outputText", "|a", + null, "a", ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParserError("Empty label with code", "|" + CODE_SETTINGS, + null, null, ICON_UNDEFINED, mCodeSettings); + assertParserError("Empty outputText with label", "a|", + "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParserError("Empty outputText with icon", ICON_SETTINGS + "|", + null, null, mSettingsIconId, CODE_UNSPECIFIED); + assertParserError("Icon without code", ICON_SETTINGS, + null, null, mSettingsIconId, CODE_UNSPECIFIED); + assertParserError("Non existing icon", ICON_NON_EXISTING + "|abc", + null, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParserError("Non existing code", "abc|" + CODE_NON_EXISTING, + "abc", null, ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParserError("Third bar at end", "a|b|", + "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParserError("Multiple bar", "a|b|c", + "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParserError("Multiple bar with label and code", "a|" + CODE_SETTINGS + "|c", + "a", null, ICON_UNDEFINED, mCodeSettings); + assertParserError("Multiple bar with icon and outputText", ICON_SETTINGS + "|b|c", + null, null, mSettingsIconId, CODE_UNSPECIFIED); + assertParserError("Multiple bar with icon and code", + ICON_SETTINGS + "|" + CODE_SETTINGS + "|c", + null, null, mSettingsIconId, mCodeSettings); + } + + public void testUselessUpperCaseSpecifier() { + assertParser("Single letter with CODE", "a|" + CODE_SETTINGS_UPPERCASE, + "a", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with CODE", "abc|" + CODE_SETTINGS_UPPERCASE, + "abc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped label with CODE", "a\\|c|" + CODE_SETTINGS_UPPERCASE, + "a|c", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("ICON with outputText", ICON_SETTINGS_UPPERCASE + "|abc", + "!ICON/SETTINGS_KEY", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("ICON with outputText starts with bang", ICON_SETTINGS_UPPERCASE + "|!bc", + "!ICON/SETTINGS_KEY", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("ICON with outputText contains bang", ICON_SETTINGS_UPPERCASE + "|a!c", + "!ICON/SETTINGS_KEY", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("ICON with escaped bang outputText", ICON_SETTINGS_UPPERCASE + "|\\!bc", + "!ICON/SETTINGS_KEY", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label starts with bang and CODE", "!bc|" + CODE_SETTINGS_UPPERCASE, + "!bc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label contains bang and CODE", "a!c|" + CODE_SETTINGS_UPPERCASE, + "a!c", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped bang label with CODE", "\\!bc|" + CODE_SETTINGS_UPPERCASE, + "!bc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("ICON with CODE", ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE, + "!ICON/SETTINGS_KEY", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("SETTINGS AS MORE KEY", "!TEXT/SETTINGS_AS_MORE_KEY", + "!TEXT/SETTINGS_AS_MORE_KEY", "!TEXT/SETTINGS_AS_MORE_KEY", ICON_UNDEFINED, + CODE_OUTPUT_TEXT); + assertParser("ACTION NEXT AS MORE KEY", "!TEXT/LABEL_NEXT_KEY|!CODE/KEY_ACTION_NEXT", + "!TEXT/LABEL_NEXT_KEY", "!CODE/KEY_ACTION_NEXT", ICON_UNDEFINED, + CODE_OUTPUT_TEXT); + assertParser("POPULAR DOMAIN", + "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN|!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN ", + "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN", "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN ", + ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParserError("Empty label with CODE", "|" + CODE_SETTINGS_UPPERCASE, + null, null, ICON_UNDEFINED, mCodeSettings); + assertParserError("Empty outputText with ICON", ICON_SETTINGS_UPPERCASE + "|", + null, null, mSettingsIconId, CODE_UNSPECIFIED); + assertParser("ICON without code", ICON_SETTINGS_UPPERCASE, + "!ICON/SETTINGS_KEY", "!ICON/SETTINGS_KEY", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParserError("Multiple bar with label and CODE", "a|" + CODE_SETTINGS_UPPERCASE + "|c", + "a", null, ICON_UNDEFINED, mCodeSettings); + assertParserError("Multiple bar with ICON and outputText", ICON_SETTINGS_UPPERCASE + "|b|c", + null, null, mSettingsIconId, CODE_UNSPECIFIED); + assertParserError("Multiple bar with ICON and CODE", + ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE + "|c", + null, null, mSettingsIconId, mCodeSettings); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserSplitTests.java b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java index 2eb448c82..42a94f420 100644 --- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserSplitTests.java +++ b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java @@ -31,7 +31,7 @@ import java.util.Arrays; import java.util.Locale; @MediumTest -public class KeySpecParserSplitTests extends InstrumentationTestCase { +public class MoreKeySpecSplitTests extends InstrumentationTestCase { private static final Locale TEST_LOCALE = Locale.ENGLISH; final KeyboardTextsSet mTextsSet = new KeyboardTextsSet(); @@ -41,7 +41,7 @@ public class KeySpecParserSplitTests extends InstrumentationTestCase { final Instrumentation instrumentation = getInstrumentation(); final Context targetContext = instrumentation.getTargetContext(); - mTextsSet.setLanguage(TEST_LOCALE.getLanguage()); + mTextsSet.setLocale(TEST_LOCALE); new RunInLocale<Void>() { @Override protected Void job(final Resources res) { @@ -92,8 +92,8 @@ public class KeySpecParserSplitTests extends InstrumentationTestCase { private void assertTextArray(final String message, final String value, final String ... expectedArray) { - final String resolvedActual = KeySpecParser.resolveTextReference(value, mTextsSet); - final String[] actual = KeySpecParser.splitKeySpecs(resolvedActual); + final String resolvedActual = mTextsSet.resolveTextReference(value); + final String[] actual = MoreKeySpec.splitKeySpecs(resolvedActual); final String[] expected = (expectedArray.length == 0) ? null : expectedArray; assertArrayEquals(message, expected, actual); } @@ -116,6 +116,14 @@ public class KeySpecParserSplitTests extends InstrumentationTestCase { private static final String SURROGATE1 = PAIR1 + PAIR2; private static final String SURROGATE2 = PAIR1 + PAIR2 + PAIR3; + public void testResolveNullText() { + assertNull("resolve null", mTextsSet.resolveTextReference(null)); + } + + public void testResolveEmptyText() { + assertNull("resolve empty text", mTextsSet.resolveTextReference("!text/empty_string")); + } + public void testSplitZero() { assertTextArray("Empty string", ""); assertTextArray("Empty entry", ","); diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecTests.java b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecTests.java new file mode 100644 index 000000000..6c0d74941 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecTests.java @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.keyboard.internal; + +import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED; +import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.latin.Constants; + +import java.util.Arrays; +import java.util.Locale; + +@SmallTest +public final class MoreKeySpecTests extends KeySpecParserTestsBase { + @Override + protected void assertParser(final String message, final String moreKeySpec, + final String expectedLabel, final String expectedOutputText, final int expectedIconId, + final int expectedCode) { + final String labelResolved = mTextsSet.resolveTextReference(moreKeySpec); + final MoreKeySpec spec = new MoreKeySpec( + labelResolved, false /* needsToUpperCase */, Locale.US); + assertEquals(message + " [label]", expectedLabel, spec.mLabel); + assertEquals(message + " [ouptputText]", expectedOutputText, spec.mOutputText); + assertEquals(message + " [icon]", + KeyboardIconsSet.getIconName(expectedIconId), + KeyboardIconsSet.getIconName(spec.mIconId)); + assertEquals(message + " [code]", + Constants.printableCode(expectedCode), + Constants.printableCode(spec.mCode)); + } + + // TODO: Move this method to {@link KeySpecParserBase}. + public void testEmptySpec() { + assertParserError("Null spec", null, + null, null, ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParserError("Empty spec", "", + null, null, ICON_UNDEFINED, CODE_UNSPECIFIED); + } + + private static void assertArrayEquals(final String message, final Object[] expected, + final Object[] actual) { + if (expected == actual) { + return; + } + if (expected == null || actual == null) { + assertEquals(message, Arrays.toString(expected), Arrays.toString(actual)); + return; + } + if (expected.length != actual.length) { + assertEquals(message + " [length]", Arrays.toString(expected), Arrays.toString(actual)); + return; + } + for (int i = 0; i < expected.length; i++) { + assertEquals(message + " [" + i + "]", + Arrays.toString(expected), Arrays.toString(actual)); + } + } + + private static void assertInsertAdditionalMoreKeys(final String message, + final String[] moreKeys, final String[] additionalMoreKeys, final String[] expected) { + final String[] actual = MoreKeySpec.insertAdditionalMoreKeys(moreKeys, additionalMoreKeys); + assertArrayEquals(message, expected, actual); + } + + public void testEmptyEntry() { + assertInsertAdditionalMoreKeys("null more keys and null additons", + null, + null, + null); + assertInsertAdditionalMoreKeys("null more keys and empty additons", + null, + new String[0], + null); + assertInsertAdditionalMoreKeys("empty more keys and null additons", + new String[0], + null, + null); + assertInsertAdditionalMoreKeys("empty more keys and empty additons", + new String[0], + new String[0], + null); + + assertInsertAdditionalMoreKeys("filter out empty more keys", + new String[] { null, "a", "", "b", null }, + null, + new String[] { "a", "b" }); + assertInsertAdditionalMoreKeys("filter out empty additons", + new String[] { "a", "%", "b", "%", "c", "%", "d" }, + new String[] { null, "A", "", "B", null }, + new String[] { "a", "A", "b", "B", "c", "d" }); + } + + public void testInsertAdditionalMoreKeys() { + // Escaped marker. + assertInsertAdditionalMoreKeys("escaped marker", + new String[] { "\\%", "%-)" }, + new String[] { "1", "2" }, + new String[] { "1", "2", "\\%", "%-)" }); + + // 0 more key. + assertInsertAdditionalMoreKeys("null & null", null, null, null); + assertInsertAdditionalMoreKeys("null & 1 additon", + null, + new String[] { "1" }, + new String[] { "1" }); + assertInsertAdditionalMoreKeys("null & 2 additons", + null, + new String[] { "1", "2" }, + new String[] { "1", "2" }); + + // 0 additional more key. + assertInsertAdditionalMoreKeys("1 more key & null", + new String[] { "A" }, + null, + new String[] { "A" }); + assertInsertAdditionalMoreKeys("2 more keys & null", + new String[] { "A", "B" }, + null, + new String[] { "A", "B" }); + + // No marker. + assertInsertAdditionalMoreKeys("1 more key & 1 addtional & no marker", + new String[] { "A" }, + new String[] { "1" }, + new String[] { "1", "A" }); + assertInsertAdditionalMoreKeys("1 more key & 2 addtionals & no marker", + new String[] { "A" }, + new String[] { "1", "2" }, + new String[] { "1", "2", "A" }); + assertInsertAdditionalMoreKeys("2 more keys & 1 addtional & no marker", + new String[] { "A", "B" }, + new String[] { "1" }, + new String[] { "1", "A", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 addtionals & no marker", + new String[] { "A", "B" }, + new String[] { "1", "2" }, + new String[] { "1", "2", "A", "B" }); + + // 1 marker. + assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at head", + new String[] { "%", "A" }, + new String[] { "1" }, + new String[] { "1", "A" }); + assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at tail", + new String[] { "A", "%" }, + new String[] { "1" }, + new String[] { "A", "1" }); + assertInsertAdditionalMoreKeys("2 more keys & 1 additon & marker at middle", + new String[] { "A", "%", "B" }, + new String[] { "1" }, + new String[] { "A", "1", "B" }); + + // 1 marker & excess additional more keys. + assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at head", + new String[] { "%", "A", "B" }, + new String[] { "1", "2" }, + new String[] { "1", "A", "B", "2" }); + assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at tail", + new String[] { "A", "B", "%" }, + new String[] { "1", "2" }, + new String[] { "A", "B", "1", "2" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 additons & marker at middle", + new String[] { "A", "%", "B" }, + new String[] { "1", "2" }, + new String[] { "A", "1", "B", "2" }); + + // 2 markers. + assertInsertAdditionalMoreKeys("0 more key & 2 addtional & 2 markers", + new String[] { "%", "%" }, + new String[] { "1", "2" }, + new String[] { "1", "2" }); + assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at head", + new String[] { "%", "%", "A" }, + new String[] { "1", "2" }, + new String[] { "1", "2", "A" }); + assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at tail", + new String[] { "A", "%", "%" }, + new String[] { "1", "2" }, + new String[] { "A", "1", "2" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at middle", + new String[] { "A", "%", "%", "B" }, + new String[] { "1", "2" }, + new String[] { "A", "1", "2", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & middle", + new String[] { "%", "A", "%", "B" }, + new String[] { "1", "2" }, + new String[] { "1", "A", "2", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & tail", + new String[] { "%", "A", "B", "%" }, + new String[] { "1", "2" }, + new String[] { "1", "A", "B", "2" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at middle & tail", + new String[] { "A", "%", "B", "%" }, + new String[] { "1", "2" }, + new String[] { "A", "1", "B", "2" }); + + // 2 markers & excess additional more keys. + assertInsertAdditionalMoreKeys("0 more key & 2 additons & 2 markers", + new String[] { "%", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "2", "3" }); + assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at head", + new String[] { "%", "%", "A" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "2", "A", "3" }); + assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at tail", + new String[] { "A", "%", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "A", "1", "2", "3" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at middle", + new String[] { "A", "%", "%", "B" }, + new String[] { "1", "2", "3" }, + new String[] { "A", "1", "2", "B", "3" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & middle", + new String[] { "%", "A", "%", "B" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "A", "2", "B", "3" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & tail", + new String[] { "%", "A", "B", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "A", "B", "2", "3" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at middle & tail", + new String[] { "A", "%", "B", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "A", "1", "B", "2", "3" }); + + // 0 addtional more key and excess markers. + assertInsertAdditionalMoreKeys("0 more key & null & excess marker", + new String[] { "%" }, + null, + null); + assertInsertAdditionalMoreKeys("1 more key & null & excess marker at head", + new String[] { "%", "A" }, + null, + new String[] { "A" }); + assertInsertAdditionalMoreKeys("1 more key & null & excess marker at tail", + new String[] { "A", "%" }, + null, + new String[] { "A" }); + assertInsertAdditionalMoreKeys("2 more keys & null & excess marker at middle", + new String[] { "A", "%", "B" }, + null, + new String[] { "A", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & null & excess markers", + new String[] { "%", "A", "%", "B", "%" }, + null, + new String[] { "A", "B" }); + + // Excess markers. + assertInsertAdditionalMoreKeys("0 more key & 1 additon & excess marker", + new String[] { "%", "%" }, + new String[] { "1" }, + new String[] { "1" }); + assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at head", + new String[] { "%", "%", "A" }, + new String[] { "1" }, + new String[] { "1", "A" }); + assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at tail", + new String[] { "A", "%", "%" }, + new String[] { "1" }, + new String[] { "A", "1" }); + assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess marker at middle", + new String[] { "A", "%", "%", "B" }, + new String[] { "1" }, + new String[] { "A", "1", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess markers", + new String[] { "%", "A", "%", "B", "%" }, + new String[] { "1" }, + new String[] { "1", "A", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 additons & excess markers", + new String[] { "%", "A", "%", "B", "%" }, + new String[] { "1", "2" }, + new String[] { "1", "A", "2", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & 3 additons & excess markers", + new String[] { "%", "A", "%", "%", "B", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "A", "2", "3", "B" }); + } + + private static final String HAS_LABEL = "!hasLabel!"; + private static final String NEEDS_DIVIDER = "!needsDividers!"; + private static final String AUTO_COLUMN_ORDER = "!autoColumnOrder!"; + private static final String FIXED_COLUMN_ORDER = "!fixedColumnOrder!"; + + private static void assertGetBooleanValue(final String message, final String key, + final String[] moreKeys, final String[] expected, final boolean expectedValue) { + final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length); + final boolean actualValue = MoreKeySpec.getBooleanValue(actual, key); + assertEquals(message + " [value]", expectedValue, actualValue); + assertArrayEquals(message, expected, actual); + } + + public void testGetBooleanValue() { + assertGetBooleanValue("Has label", HAS_LABEL, + new String[] { HAS_LABEL, "a", "b", "c" }, + new String[] { null, "a", "b", "c" }, true); + // Upper case specification will not work. + assertGetBooleanValue("HAS LABEL", HAS_LABEL, + new String[] { HAS_LABEL.toUpperCase(Locale.ROOT), "a", "b", "c" }, + new String[] { "!HASLABEL!", "a", "b", "c" }, false); + + assertGetBooleanValue("No has label", HAS_LABEL, + new String[] { "a", "b", "c" }, + new String[] { "a", "b", "c" }, false); + assertGetBooleanValue("No has label with fixed clumn order", HAS_LABEL, + new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, + new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, false); + + // Upper case specification will not work. + assertGetBooleanValue("Multiple has label", HAS_LABEL, + new String[] { + "a", HAS_LABEL.toUpperCase(Locale.ROOT), "b", "c", HAS_LABEL, "d" }, + new String[] { + "a", "!HASLABEL!", "b", "c", null, "d" }, true); + // Upper case specification will not work. + assertGetBooleanValue("Multiple has label with needs dividers", HAS_LABEL, + new String[] { + "a", HAS_LABEL, "b", NEEDS_DIVIDER, HAS_LABEL.toUpperCase(Locale.ROOT), "d" }, + new String[] { + "a", null, "b", NEEDS_DIVIDER, "!HASLABEL!", "d" }, true); + } + + private static void assertGetIntValue(final String message, final String key, + final int defaultValue, final String[] moreKeys, final String[] expected, + final int expectedValue) { + final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length); + final int actualValue = MoreKeySpec.getIntValue(actual, key, defaultValue); + assertEquals(message + " [value]", expectedValue, actualValue); + assertArrayEquals(message, expected, actual); + } + + public void testGetIntValue() { + assertGetIntValue("Fixed column order 3", FIXED_COLUMN_ORDER, -1, + new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, + new String[] { null, "a", "b", "c" }, 3); + // Upper case specification will not work. + assertGetIntValue("FIXED COLUMN ORDER 3", FIXED_COLUMN_ORDER, -1, + new String[] { FIXED_COLUMN_ORDER.toUpperCase(Locale.ROOT) + "3", "a", "b", "c" }, + new String[] { "!FIXEDCOLUMNORDER!3", "a", "b", "c" }, -1); + + assertGetIntValue("No fixed column order", FIXED_COLUMN_ORDER, -1, + new String[] { "a", "b", "c" }, + new String[] { "a", "b", "c" }, -1); + assertGetIntValue("No fixed column order with auto column order", FIXED_COLUMN_ORDER, -1, + new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" }, + new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" }, -1); + + assertGetIntValue("Multiple fixed column order 3,5", FIXED_COLUMN_ORDER, -1, + new String[] { FIXED_COLUMN_ORDER + "3", "a", FIXED_COLUMN_ORDER + "5", "b" }, + new String[] { null, "a", null, "b" }, 3); + // Upper case specification will not work. + assertGetIntValue("Multiple fixed column order 5,3 with has label", FIXED_COLUMN_ORDER, -1, + new String[] { + FIXED_COLUMN_ORDER.toUpperCase(Locale.ROOT) + "5", HAS_LABEL, "a", + FIXED_COLUMN_ORDER + "3", "b" }, + new String[] { "!FIXEDCOLUMNORDER!5", HAS_LABEL, "a", null, "b" }, 3); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java b/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java index 279559cfe..7908b260e 100644 --- a/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java +++ b/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java @@ -27,7 +27,7 @@ public class PointerTrackerQueueTests extends AndroidTestCase { public final int mId; public boolean mIsModifier; - public boolean mIsInSlidingKeyInput; + public boolean mIsInDraggingFinger; public long mPhantomUpEventTime = NOT_HAPPENED; public Element(int id) { @@ -40,8 +40,8 @@ public class PointerTrackerQueueTests extends AndroidTestCase { } @Override - public boolean isInSlidingKeyInput() { - return mIsInSlidingKeyInput; + public boolean isInDraggingFinger() { + return mIsInDraggingFinger; } @Override @@ -297,19 +297,19 @@ public class PointerTrackerQueueTests extends AndroidTestCase { assertEquals(Element.NOT_HAPPENED, mElement4.mPhantomUpEventTime); } - public void testIsAnyInSlidingKeyInput() { + public void testIsAnyInDraggingFinger() { Element.sPhantomUpCount = 0; - assertFalse(mQueue.isAnyInSlidingKeyInput()); + assertFalse(mQueue.isAnyInDraggingFinger()); mQueue.add(mElement1); mQueue.add(mElement2); mQueue.add(mElement3); mQueue.add(mElement4); - assertFalse(mQueue.isAnyInSlidingKeyInput()); + assertFalse(mQueue.isAnyInDraggingFinger()); - mElement3.mIsInSlidingKeyInput = true; - assertTrue(mQueue.isAnyInSlidingKeyInput()); + mElement3.mIsInDraggingFinger = true; + assertTrue(mQueue.isAnyInDraggingFinger()); assertEquals(0, Element.sPhantomUpCount); assertEquals(4, mQueue.size()); diff --git a/tests/src/com/android/inputmethod/latin/AppWorkaroundsTests.java b/tests/src/com/android/inputmethod/latin/AppWorkaroundsTests.java new file mode 100644 index 000000000..c29257d34 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/AppWorkaroundsTests.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin; + +import com.android.inputmethod.latin.settings.Settings; + +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Build.VERSION_CODES; +import android.test.suitebuilder.annotation.LargeTest; +import android.view.inputmethod.EditorInfo; + +@LargeTest +public class AppWorkaroundsTests extends InputTestsBase { + String packageNameOfAppBeforeJellyBean; + String packageNameOfAppAfterJellyBean; + + @Override + protected void setUp() throws Exception { + // NOTE: this will fail if there is no app installed that targets an SDK + // before Jelly Bean. For the moment, it's fine. + final PackageManager pm = getContext().getPackageManager(); + for (ApplicationInfo ai : pm.getInstalledApplications(0 /* flags */)) { + if (ai.targetSdkVersion < VERSION_CODES.JELLY_BEAN) { + packageNameOfAppBeforeJellyBean = ai.packageName; + } else { + packageNameOfAppAfterJellyBean = ai.packageName; + } + } + super.setUp(); + } + + // We want to test if the app package info is correctly retrieved by LatinIME. Since it + // asks this information to the package manager from the package name, and that it takes + // the package name from the EditorInfo, all we have to do it put the correct package + // name in the editor info. + // To this end, our base class InputTestsBase offers a hook for us to touch the EditorInfo. + // We override this hook to write the package name that we need. + @Override + protected EditorInfo enrichEditorInfo(final EditorInfo ei) { + if ("testBeforeJellyBeanTrue".equals(getName())) { + ei.packageName = packageNameOfAppBeforeJellyBean; + } else if ("testBeforeJellyBeanFalse".equals(getName())) { + ei.packageName = packageNameOfAppAfterJellyBean; + } + return ei; + } + + public void testBeforeJellyBeanTrue() { + assertTrue("Couldn't successfully detect this app targets < Jelly Bean (package is " + + packageNameOfAppBeforeJellyBean + ")", + Settings.getInstance().getCurrent().isBeforeJellyBean()); + } + + public void testBeforeJellyBeanFalse() { + assertFalse("Couldn't successfully detect this app targets >= Jelly Bean (package is " + + packageNameOfAppAfterJellyBean + ")", + Settings.getInstance().getCurrent().isBeforeJellyBean()); + } +}
\ No newline at end of file diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java index cd5384ea4..f4b16a7e1 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java @@ -21,7 +21,14 @@ import android.test.suitebuilder.annotation.LargeTest; import android.util.Pair; import com.android.inputmethod.latin.makedict.CodePointUtils; +import com.android.inputmethod.latin.makedict.DictDecoder; +import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.FormatSpec; +import com.android.inputmethod.latin.makedict.FusionDictionary; +import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; +import com.android.inputmethod.latin.makedict.UnsupportedFormatException; +import com.android.inputmethod.latin.utils.FileUtils; +import com.android.inputmethod.latin.utils.LocaleUtils; import java.io.File; import java.io.IOException; @@ -30,68 +37,168 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Random; +import java.util.concurrent.TimeUnit; @LargeTest public class BinaryDictionaryDecayingTests extends AndroidTestCase { private static final String TEST_DICT_FILE_EXTENSION = ".testDict"; private static final String TEST_LOCALE = "test"; - - // Note that these are corresponding definitions in native code in - // latinime::DynamicPatriciaTriePolicy. - private static final String SET_NEEDS_TO_DECAY_FOR_TESTING_KEY = - "SET_NEEDS_TO_DECAY_FOR_TESTING"; - private static final int DUMMY_PROBABILITY = 0; + private int mCurrentTime = 0; + @Override protected void setUp() throws Exception { super.setUp(); + mCurrentTime = 0; } @Override protected void tearDown() throws Exception { + stopTestModeInNativeCode(); super.tearDown(); } + private void addUnigramWord(final BinaryDictionary binaryDictionary, final String word, + final int probability) { + binaryDictionary.addUnigramWord(word, probability, "" /* shortcutTarget */, + BinaryDictionary.NOT_A_PROBABILITY /* shortcutProbability */, + false /* isNotAWord */, false /* isBlacklisted */, + mCurrentTime /* timestamp */); + } + + private void addBigramWords(final BinaryDictionary binaryDictionary, final String word0, + final String word1, final int probability) { + binaryDictionary.addBigramWords(word0, word1, probability, + mCurrentTime /* timestamp */); + } + private void forcePassingShortTime(final BinaryDictionary binaryDictionary) { - // Entries having low probability would be suppressed once in 3 GCs. - final int count = 3; - for (int i = 0; i < count; i++) { - binaryDictionary.getPropertyForTests(SET_NEEDS_TO_DECAY_FOR_TESTING_KEY); - binaryDictionary.flushWithGC(); - } + // 4 days. + final int timeToElapse = (int)TimeUnit.SECONDS.convert(4, TimeUnit.DAYS); + mCurrentTime += timeToElapse; + setCurrentTimeForTestMode(mCurrentTime); + binaryDictionary.flushWithGC(); } private void forcePassingLongTime(final BinaryDictionary binaryDictionary) { - // Currently, probabilities are decayed when GC is run. All entries that have never been - // typed in 128 GCs would be removed. - final int count = 128; - for (int i = 0; i < count; i++) { - binaryDictionary.getPropertyForTests(SET_NEEDS_TO_DECAY_FOR_TESTING_KEY); - binaryDictionary.flushWithGC(); + // 60 days. + final int timeToElapse = (int)TimeUnit.SECONDS.convert(60, TimeUnit.DAYS); + mCurrentTime += timeToElapse; + setCurrentTimeForTestMode(mCurrentTime); + binaryDictionary.flushWithGC(); + } + + private File createEmptyDictionaryAndGetFile(final String dictId, + final int formatVersion) throws IOException { + if (formatVersion == FormatSpec.VERSION4) { + return createEmptyVer4DictionaryAndGetFile(dictId); + } else { + throw new IOException("Dictionary format version " + formatVersion + + " is not supported."); } } - private File createEmptyDictionaryAndGetFile(final String filename) throws IOException { - final File file = File.createTempFile(filename, TEST_DICT_FILE_EXTENSION, + private File createEmptyVer4DictionaryAndGetFile(final String dictId) throws IOException { + final File file = File.createTempFile(dictId, TEST_DICT_FILE_EXTENSION, getContext().getCacheDir()); + FileUtils.deleteRecursively(file); Map<String, String> attributeMap = new HashMap<String, String>(); - attributeMap.put(FormatSpec.FileHeader.SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE, - FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); - attributeMap.put(FormatSpec.FileHeader.USES_FORGETTING_CURVE_ATTRIBUTE, - FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); - if (BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), - 3 /* dictVersion */, attributeMap)) { + attributeMap.put(DictionaryHeader.DICTIONARY_ID_KEY, dictId); + attributeMap.put(DictionaryHeader.DICTIONARY_VERSION_KEY, + String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()))); + attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); + attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); + if (BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, + LocaleUtils.constructLocaleFromString(TEST_LOCALE), attributeMap)) { return file; } else { - throw new IOException("Empty dictionary cannot be created."); + throw new IOException("Empty dictionary " + file.getAbsolutePath() + + " cannot be created."); + } + } + + private static int setCurrentTimeForTestMode(final int currentTime) { + return BinaryDictionary.setCurrentTimeForTest(currentTime); + } + + private static int stopTestModeInNativeCode() { + return BinaryDictionary.setCurrentTimeForTest(-1); + } + + public void testReadDictInJavaSide() { + testReadDictInJavaSide(FormatSpec.VERSION4); + } + + private void testReadDictInJavaSide(final int formatVersion) { + setCurrentTimeForTestMode(mCurrentTime); + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "ab", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "aaa", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "aaa", DUMMY_PROBABILITY); + binaryDictionary.flushWithGC(); + binaryDictionary.close(); + + final DictDecoder dictDecoder = FormatSpec.getDictDecoder(dictFile); + try { + final FusionDictionary dict = + dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */); + PtNode ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray, "a"); + assertNotNull(ptNode); + assertTrue(ptNode.isTerminal()); + assertNotNull(ptNode.getBigram("aaa")); + ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray, "ab"); + assertNotNull(ptNode); + assertTrue(ptNode.isTerminal()); + ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa"); + assertNotNull(ptNode); + assertTrue(ptNode.isTerminal()); + } catch (IOException e) { + fail("IOException while reading dictionary: " + e); + } catch (UnsupportedFormatException e) { + fail("Unsupported format: " + e); + } + dictFile.delete(); + } + + public void testControlCurrentTime() { + testControlCurrentTime(FormatSpec.VERSION4); + } + + private void testControlCurrentTime(final int formatVersion) { + final int TEST_COUNT = 1000; + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + final int startTime = stopTestModeInNativeCode(); + for (int i = 0; i < TEST_COUNT; i++) { + final int currentTime = random.nextInt(Integer.MAX_VALUE); + final int currentTimeInNativeCode = setCurrentTimeForTestMode(currentTime); + assertEquals(currentTime, currentTimeInNativeCode); } + final int endTime = stopTestModeInNativeCode(); + final int MAX_ALLOWED_ELAPSED_TIME = 10; + assertTrue(startTime <= endTime && endTime <= startTime + MAX_ALLOWED_ELAPSED_TIME); } public void testAddValidAndInvalidWords() { + testAddValidAndInvalidWords(FormatSpec.VERSION4); + } + + private void testAddValidAndInvalidWords(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -99,36 +206,35 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); - binaryDictionary.addUnigramWord("a", Dictionary.NOT_A_PROBABILITY); + addUnigramWord(binaryDictionary, "a", Dictionary.NOT_A_PROBABILITY); assertFalse(binaryDictionary.isValidWord("a")); - binaryDictionary.addUnigramWord("a", Dictionary.NOT_A_PROBABILITY); + addUnigramWord(binaryDictionary, "a", Dictionary.NOT_A_PROBABILITY); assertFalse(binaryDictionary.isValidWord("a")); - binaryDictionary.addUnigramWord("a", Dictionary.NOT_A_PROBABILITY); + addUnigramWord(binaryDictionary, "a", Dictionary.NOT_A_PROBABILITY); assertFalse(binaryDictionary.isValidWord("a")); - binaryDictionary.addUnigramWord("a", Dictionary.NOT_A_PROBABILITY); + addUnigramWord(binaryDictionary, "a", Dictionary.NOT_A_PROBABILITY); assertTrue(binaryDictionary.isValidWord("a")); - binaryDictionary.addUnigramWord("b", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY); assertTrue(binaryDictionary.isValidWord("b")); - final int unigramProbability = binaryDictionary.getFrequency("a"); - binaryDictionary.addBigramWords("a", "b", Dictionary.NOT_A_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", Dictionary.NOT_A_PROBABILITY); assertFalse(binaryDictionary.isValidBigram("a", "b")); - binaryDictionary.addBigramWords("a", "b", Dictionary.NOT_A_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", Dictionary.NOT_A_PROBABILITY); assertFalse(binaryDictionary.isValidBigram("a", "b")); - binaryDictionary.addBigramWords("a", "b", Dictionary.NOT_A_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", Dictionary.NOT_A_PROBABILITY); assertFalse(binaryDictionary.isValidBigram("a", "b")); - binaryDictionary.addBigramWords("a", "b", Dictionary.NOT_A_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", Dictionary.NOT_A_PROBABILITY); assertTrue(binaryDictionary.isValidBigram("a", "b")); - binaryDictionary.addUnigramWord("c", DUMMY_PROBABILITY); - binaryDictionary.addBigramWords("a", "c", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "c", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "c", DUMMY_PROBABILITY); assertTrue(binaryDictionary.isValidBigram("a", "c")); // Add bigrams of not valid unigrams. - binaryDictionary.addBigramWords("x", "y", Dictionary.NOT_A_PROBABILITY); + addBigramWords(binaryDictionary, "x", "y", Dictionary.NOT_A_PROBABILITY); assertFalse(binaryDictionary.isValidBigram("x", "y")); - binaryDictionary.addBigramWords("x", "y", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "x", "y", DUMMY_PROBABILITY); assertFalse(binaryDictionary.isValidBigram("x", "y")); binaryDictionary.close(); @@ -136,9 +242,13 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { } public void testDecayingProbability() { + testDecayingProbability(FormatSpec.VERSION4); + } + + private void testDecayingProbability(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -146,39 +256,44 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); assertTrue(binaryDictionary.isValidWord("a")); forcePassingShortTime(binaryDictionary); assertFalse(binaryDictionary.isValidWord("a")); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + assertTrue(binaryDictionary.isValidWord("a")); forcePassingShortTime(binaryDictionary); assertTrue(binaryDictionary.isValidWord("a")); forcePassingLongTime(binaryDictionary); assertFalse(binaryDictionary.isValidWord("a")); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("b", DUMMY_PROBABILITY); - binaryDictionary.addBigramWords("a", "b", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", DUMMY_PROBABILITY); assertTrue(binaryDictionary.isValidBigram("a", "b")); forcePassingShortTime(binaryDictionary); assertFalse(binaryDictionary.isValidBigram("a", "b")); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("b", DUMMY_PROBABILITY); - binaryDictionary.addBigramWords("a", "b", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("b", DUMMY_PROBABILITY); - binaryDictionary.addBigramWords("a", "b", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("b", DUMMY_PROBABILITY); - binaryDictionary.addBigramWords("a", "b", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("b", DUMMY_PROBABILITY); - binaryDictionary.addBigramWords("a", "b", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", DUMMY_PROBABILITY); assertTrue(binaryDictionary.isValidBigram("a", "b")); forcePassingShortTime(binaryDictionary); assertTrue(binaryDictionary.isValidBigram("a", "b")); @@ -190,6 +305,10 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { } public void testAddManyUnigramsToDecayingDict() { + testAddManyUnigramsToDecayingDict(FormatSpec.VERSION4); + } + + private void testAddManyUnigramsToDecayingDict(final int formatVersion) { final int unigramCount = 30000; final int unigramTypedCount = 100000; final int codePointSetSize = 50; @@ -198,13 +317,14 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + setCurrentTimeForTestMode(mCurrentTime); final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); final ArrayList<String> words = new ArrayList<String>(); @@ -215,32 +335,98 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { } final int maxUnigramCount = Integer.parseInt( - binaryDictionary.getPropertyForTests(BinaryDictionary.MAX_UNIGRAM_COUNT_QUERY)); + binaryDictionary.getPropertyForTest(BinaryDictionary.MAX_UNIGRAM_COUNT_QUERY)); for (int i = 0; i < unigramTypedCount; i++) { final String word = words.get(random.nextInt(words.size())); - binaryDictionary.addUnigramWord(word, DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, word, DUMMY_PROBABILITY); if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { final int unigramCountBeforeGC = - Integer.parseInt(binaryDictionary.getPropertyForTests( + Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.UNIGRAM_COUNT_QUERY)); while (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { - binaryDictionary.flushWithGC(); + forcePassingShortTime(binaryDictionary); } final int unigramCountAfterGC = - Integer.parseInt(binaryDictionary.getPropertyForTests( + Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.UNIGRAM_COUNT_QUERY)); assertTrue(unigramCountBeforeGC > unigramCountAfterGC); } } - assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTests( + assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.UNIGRAM_COUNT_QUERY)) > 0); - assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTests( + assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.UNIGRAM_COUNT_QUERY)) <= maxUnigramCount); + forcePassingLongTime(binaryDictionary); + assertEquals(0, Integer.parseInt(binaryDictionary.getPropertyForTest( + BinaryDictionary.UNIGRAM_COUNT_QUERY))); + } + + public void testOverflowUnigrams() { + testOverflowUnigrams(FormatSpec.VERSION4); + } + + private void testOverflowUnigrams(final int formatVersion) { + final int unigramCount = 20000; + final int eachUnigramTypedCount = 5; + final int strongUnigramTypedCount = 20; + final int weakUnigramTypedCount = 1; + final int codePointSetSize = 50; + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + setCurrentTimeForTestMode(mCurrentTime); + final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); + + final String strong = "strong"; + final String weak = "weak"; + for (int j = 0; j < strongUnigramTypedCount; j++) { + addUnigramWord(binaryDictionary, strong, DUMMY_PROBABILITY); + } + for (int j = 0; j < weakUnigramTypedCount; j++) { + addUnigramWord(binaryDictionary, weak, DUMMY_PROBABILITY); + } + assertTrue(binaryDictionary.isValidWord(strong)); + assertTrue(binaryDictionary.isValidWord(weak)); + + for (int i = 0; i < unigramCount; i++) { + final String word = CodePointUtils.generateWord(random, codePointSet); + for (int j = 0; j < eachUnigramTypedCount; j++) { + addUnigramWord(binaryDictionary, word, DUMMY_PROBABILITY); + } + if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { + final int unigramCountBeforeGC = + Integer.parseInt(binaryDictionary.getPropertyForTest( + BinaryDictionary.UNIGRAM_COUNT_QUERY)); + assertTrue(binaryDictionary.isValidWord(strong)); + assertTrue(binaryDictionary.isValidWord(weak)); + binaryDictionary.flushWithGC(); + final int unigramCountAfterGC = + Integer.parseInt(binaryDictionary.getPropertyForTest( + BinaryDictionary.UNIGRAM_COUNT_QUERY)); + assertTrue(unigramCountBeforeGC > unigramCountAfterGC); + assertFalse(binaryDictionary.isValidWord(weak)); + assertTrue(binaryDictionary.isValidWord(strong)); + break; + } + } } public void testAddManyBigramsToDecayingDict() { + testAddManyBigramsToDecayingDict(FormatSpec.VERSION4); + } + + private void testAddManyBigramsToDecayingDict(final int formatVersion) { final int unigramCount = 5000; final int bigramCount = 30000; final int bigramTypedCount = 100000; @@ -250,13 +436,14 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + setCurrentTimeForTestMode(mCurrentTime); final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); final ArrayList<String> words = new ArrayList<String>(); @@ -279,30 +466,112 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { } final int maxBigramCount = Integer.parseInt( - binaryDictionary.getPropertyForTests(BinaryDictionary.MAX_BIGRAM_COUNT_QUERY)); + binaryDictionary.getPropertyForTest(BinaryDictionary.MAX_BIGRAM_COUNT_QUERY)); for (int i = 0; i < bigramTypedCount; ++i) { final Pair<String, String> bigram = bigrams.get(random.nextInt(bigrams.size())); - binaryDictionary.addUnigramWord(bigram.first, DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord(bigram.second, DUMMY_PROBABILITY); - binaryDictionary.addBigramWords(bigram.first, bigram.second, DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, bigram.first, DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, bigram.second, DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, bigram.first, bigram.second, DUMMY_PROBABILITY); if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { final int bigramCountBeforeGC = - Integer.parseInt(binaryDictionary.getPropertyForTests( + Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.BIGRAM_COUNT_QUERY)); while (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { - binaryDictionary.flushWithGC(); + forcePassingShortTime(binaryDictionary); } final int bigramCountAfterGC = - Integer.parseInt(binaryDictionary.getPropertyForTests( + Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.BIGRAM_COUNT_QUERY)); assertTrue(bigramCountBeforeGC > bigramCountAfterGC); } } - assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTests( + assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.BIGRAM_COUNT_QUERY)) > 0); - assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTests( + assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.BIGRAM_COUNT_QUERY)) <= maxBigramCount); + forcePassingLongTime(binaryDictionary); + assertEquals(0, Integer.parseInt(binaryDictionary.getPropertyForTest( + BinaryDictionary.BIGRAM_COUNT_QUERY))); + } + + public void testOverflowBigrams() { + testOverflowBigrams(FormatSpec.VERSION4); + } + + private void testOverflowBigrams(final int formatVersion) { + final int bigramCount = 20000; + final int unigramCount = 1000; + final int unigramTypedCount = 20; + final int eachBigramTypedCount = 5; + final int strongBigramTypedCount = 20; + final int weakBigramTypedCount = 1; + final int codePointSetSize = 50; + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + setCurrentTimeForTestMode(mCurrentTime); + final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); + + final ArrayList<String> words = new ArrayList<String>(); + for (int i = 0; i < unigramCount; i++) { + final String word = CodePointUtils.generateWord(random, codePointSet); + words.add(word); + for (int j = 0; j < unigramTypedCount; j++) { + addUnigramWord(binaryDictionary, word, DUMMY_PROBABILITY); + } + } + final String strong = "strong"; + final String weak = "weak"; + final String target = "target"; + for (int j = 0; j < unigramTypedCount; j++) { + addUnigramWord(binaryDictionary, strong, DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, weak, DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, target, DUMMY_PROBABILITY); + } + binaryDictionary.flushWithGC(); + for (int j = 0; j < strongBigramTypedCount; j++) { + addBigramWords(binaryDictionary, strong, target, DUMMY_PROBABILITY); + } + for (int j = 0; j < weakBigramTypedCount; j++) { + addBigramWords(binaryDictionary, weak, target, DUMMY_PROBABILITY); + } + assertTrue(binaryDictionary.isValidBigram(strong, target)); + assertTrue(binaryDictionary.isValidBigram(weak, target)); + + for (int i = 0; i < bigramCount; i++) { + final int word0Index = random.nextInt(words.size()); + final String word0 = words.get(word0Index); + final int index = random.nextInt(words.size() - 1); + final int word1Index = (index >= word0Index) ? index + 1 : index; + final String word1 = words.get(word1Index); + + for (int j = 0; j < eachBigramTypedCount; j++) { + addBigramWords(binaryDictionary, word0, word1, DUMMY_PROBABILITY); + } + if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { + final int bigramCountBeforeGC = + Integer.parseInt(binaryDictionary.getPropertyForTest( + BinaryDictionary.BIGRAM_COUNT_QUERY)); + binaryDictionary.flushWithGC(); + final int bigramCountAfterGC = + Integer.parseInt(binaryDictionary.getPropertyForTest( + BinaryDictionary.BIGRAM_COUNT_QUERY)); + assertTrue(bigramCountBeforeGC > bigramCountAfterGC); + assertTrue(binaryDictionary.isValidBigram(strong, target)); + assertFalse(binaryDictionary.isValidBigram(weak, target)); + break; + } + } } } diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java index 5b8f0e977..c1adf6557 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java @@ -23,6 +23,10 @@ import android.util.Pair; import com.android.inputmethod.latin.makedict.CodePointUtils; import com.android.inputmethod.latin.makedict.FormatSpec; +import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; +import com.android.inputmethod.latin.makedict.WordProperty; +import com.android.inputmethod.latin.utils.FileUtils; +import com.android.inputmethod.latin.utils.LanguageModelParam; import java.io.File; import java.io.IOException; @@ -33,39 +37,45 @@ import java.util.Locale; import java.util.Map; import java.util.Random; +// TODO Use the seed passed as an argument for makedict test. @LargeTest public class BinaryDictionaryTests extends AndroidTestCase { private static final String TEST_DICT_FILE_EXTENSION = ".testDict"; private static final String TEST_LOCALE = "test"; - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); + private File createEmptyDictionaryAndGetFile(final String dictId, + final int formatVersion) throws IOException { + if (formatVersion == FormatSpec.VERSION4) { + return createEmptyVer4DictionaryAndGetFile(dictId); + } else { + throw new IOException("Dictionary format version " + formatVersion + + " is not supported."); + } } - private File createEmptyDictionaryAndGetFile(final String filename) throws IOException { - final File file = File.createTempFile(filename, TEST_DICT_FILE_EXTENSION, + private File createEmptyVer4DictionaryAndGetFile(final String dictId) throws IOException { + final File file = File.createTempFile(dictId, TEST_DICT_FILE_EXTENSION, getContext().getCacheDir()); + file.delete(); + file.mkdir(); Map<String, String> attributeMap = new HashMap<String, String>(); - attributeMap.put(FormatSpec.FileHeader.SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE, - FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); - if (BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), - 3 /* dictVersion */, attributeMap)) { + if (BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, + Locale.ENGLISH, attributeMap)) { return file; } else { - throw new IOException("Empty dictionary cannot be created."); + throw new IOException("Empty dictionary " + file.getAbsolutePath() + + " cannot be created."); } } public void testIsValidDictionary() { + testIsValidDictionary(FormatSpec.VERSION4); + } + + private void testIsValidDictionary(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -77,7 +87,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { binaryDictionary.close(); assertFalse("binaryDictionary must be invalid after closing.", binaryDictionary.isValidDictionary()); - dictFile.delete(); + FileUtils.deleteRecursively(dictFile); binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); @@ -86,10 +96,73 @@ public class BinaryDictionaryTests extends AndroidTestCase { binaryDictionary.close(); } + public void testAddTooLongWord() { + testAddTooLongWord(FormatSpec.VERSION4); + } + + private void testAddTooLongWord(final int formatVersion) { + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + + final StringBuffer stringBuilder = new StringBuffer(); + for (int i = 0; i < Constants.DICTIONARY_MAX_WORD_LENGTH; i++) { + stringBuilder.append('a'); + } + final String validLongWord = stringBuilder.toString(); + stringBuilder.append('a'); + final String invalidLongWord = stringBuilder.toString(); + final int probability = 100; + addUnigramWord(binaryDictionary, "aaa", probability); + addUnigramWord(binaryDictionary, validLongWord, probability); + addUnigramWord(binaryDictionary, invalidLongWord, probability); + // Too long short cut. + binaryDictionary.addUnigramWord("a", probability, invalidLongWord, + 10 /* shortcutProbability */, false /* isNotAWord */, false /* isBlacklisted */, + BinaryDictionary.NOT_A_VALID_TIMESTAMP); + addUnigramWord(binaryDictionary, "abc", probability); + final int updatedProbability = 200; + // Update. + addUnigramWord(binaryDictionary, validLongWord, updatedProbability); + addUnigramWord(binaryDictionary, invalidLongWord, updatedProbability); + addUnigramWord(binaryDictionary, "abc", updatedProbability); + + assertEquals(probability, binaryDictionary.getFrequency("aaa")); + assertEquals(updatedProbability, binaryDictionary.getFrequency(validLongWord)); + assertEquals(BinaryDictionary.NOT_A_PROBABILITY, + binaryDictionary.getFrequency(invalidLongWord)); + assertEquals(updatedProbability, binaryDictionary.getFrequency("abc")); + dictFile.delete(); + } + + private void addUnigramWord(final BinaryDictionary binaryDictionary, final String word, + final int probability) { + binaryDictionary.addUnigramWord(word, probability, "" /* shortcutTarget */, + BinaryDictionary.NOT_A_PROBABILITY /* shortcutProbability */, + false /* isNotAWord */, false /* isBlacklisted */, + BinaryDictionary.NOT_A_VALID_TIMESTAMP /* timestamp */); + } + + private void addBigramWords(final BinaryDictionary binaryDictionary, final String word0, + final String word1, final int probability) { + binaryDictionary.addBigramWords(word0, word1, probability, + BinaryDictionary.NOT_A_VALID_TIMESTAMP /* timestamp */); + } + public void testAddUnigramWord() { + testAddUnigramWord(FormatSpec.VERSION4); + } + + private void testAddUnigramWord(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -98,21 +171,21 @@ public class BinaryDictionaryTests extends AndroidTestCase { Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); final int probability = 100; - binaryDictionary.addUnigramWord("aaa", probability); + addUnigramWord(binaryDictionary, "aaa", probability); // Reallocate and create. - binaryDictionary.addUnigramWord("aab", probability); + addUnigramWord(binaryDictionary, "aab", probability); // Insert into children. - binaryDictionary.addUnigramWord("aac", probability); + addUnigramWord(binaryDictionary, "aac", probability); // Make terminal. - binaryDictionary.addUnigramWord("aa", probability); + addUnigramWord(binaryDictionary, "aa", probability); // Create children. - binaryDictionary.addUnigramWord("aaaa", probability); + addUnigramWord(binaryDictionary, "aaaa", probability); // Reallocate and make termianl. - binaryDictionary.addUnigramWord("a", probability); + addUnigramWord(binaryDictionary, "a", probability); final int updatedProbability = 200; // Update. - binaryDictionary.addUnigramWord("aaa", updatedProbability); + addUnigramWord(binaryDictionary, "aaa", updatedProbability); assertEquals(probability, binaryDictionary.getFrequency("aab")); assertEquals(probability, binaryDictionary.getFrequency("aac")); @@ -125,13 +198,17 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testRandomlyAddUnigramWord() { + testRandomlyAddUnigramWord(FormatSpec.VERSION4); + } + + private void testRandomlyAddUnigramWord(final int formatVersion) { final int wordCount = 1000; final int codePointSetSize = 50; final long seed = System.currentTimeMillis(); File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -148,7 +225,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { probabilityMap.put(word, random.nextInt(0xFF)); } for (String word : probabilityMap.keySet()) { - binaryDictionary.addUnigramWord(word, probabilityMap.get(word)); + addUnigramWord(binaryDictionary, word, probabilityMap.get(word)); } for (String word : probabilityMap.keySet()) { assertEquals(word, (int)probabilityMap.get(word), binaryDictionary.getFrequency(word)); @@ -157,9 +234,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testAddBigramWords() { + testAddBigramWords(FormatSpec.VERSION4); + } + + private void testAddBigramWords(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -170,13 +251,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { final int unigramProbability = 100; final int bigramProbability = 10; final int updatedBigramProbability = 15; - binaryDictionary.addUnigramWord("aaa", unigramProbability); - binaryDictionary.addUnigramWord("abb", unigramProbability); - binaryDictionary.addUnigramWord("bcc", unigramProbability); - binaryDictionary.addBigramWords("aaa", "abb", bigramProbability); - binaryDictionary.addBigramWords("aaa", "bcc", bigramProbability); - binaryDictionary.addBigramWords("abb", "aaa", bigramProbability); - binaryDictionary.addBigramWords("abb", "bcc", bigramProbability); + addUnigramWord(binaryDictionary, "aaa", unigramProbability); + addUnigramWord(binaryDictionary, "abb", unigramProbability); + addUnigramWord(binaryDictionary, "bcc", unigramProbability); + addBigramWords(binaryDictionary, "aaa", "abb", bigramProbability); + addBigramWords(binaryDictionary, "aaa", "bcc", bigramProbability); + addBigramWords(binaryDictionary, "abb", "aaa", bigramProbability); + addBigramWords(binaryDictionary, "abb", "bcc", bigramProbability); final int probability = binaryDictionary.calculateProbability(unigramProbability, bigramProbability); @@ -189,7 +270,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { assertEquals(probability, binaryDictionary.getBigramProbability("abb", "aaa")); assertEquals(probability, binaryDictionary.getBigramProbability("abb", "bcc")); - binaryDictionary.addBigramWords("aaa", "abb", updatedBigramProbability); + addBigramWords(binaryDictionary, "aaa", "abb", updatedBigramProbability); final int updatedProbability = binaryDictionary.calculateProbability(unigramProbability, updatedBigramProbability); assertEquals(updatedProbability, binaryDictionary.getBigramProbability("aaa", "abb")); @@ -205,22 +286,26 @@ public class BinaryDictionaryTests extends AndroidTestCase { binaryDictionary.getBigramProbability("aaa", "aaa")); // Testing bigram link. - binaryDictionary.addUnigramWord("abcde", unigramProbability); - binaryDictionary.addUnigramWord("fghij", unigramProbability); - binaryDictionary.addBigramWords("abcde", "fghij", bigramProbability); - binaryDictionary.addUnigramWord("fgh", unigramProbability); - binaryDictionary.addUnigramWord("abc", unigramProbability); - binaryDictionary.addUnigramWord("f", unigramProbability); + addUnigramWord(binaryDictionary, "abcde", unigramProbability); + addUnigramWord(binaryDictionary, "fghij", unigramProbability); + addBigramWords(binaryDictionary, "abcde", "fghij", bigramProbability); + addUnigramWord(binaryDictionary, "fgh", unigramProbability); + addUnigramWord(binaryDictionary, "abc", unigramProbability); + addUnigramWord(binaryDictionary, "f", unigramProbability); assertEquals(probability, binaryDictionary.getBigramProbability("abcde", "fghij")); assertEquals(Dictionary.NOT_A_PROBABILITY, binaryDictionary.getBigramProbability("abcde", "fgh")); - binaryDictionary.addBigramWords("abcde", "fghij", updatedBigramProbability); + addBigramWords(binaryDictionary, "abcde", "fghij", updatedBigramProbability); assertEquals(updatedProbability, binaryDictionary.getBigramProbability("abcde", "fghij")); dictFile.delete(); } public void testRandomlyAddBigramWords() { + testRandomlyAddBigramWords(FormatSpec.VERSION4); + } + + private void testRandomlyAddBigramWords(final int formatVersion) { final int wordCount = 100; final int bigramCount = 1000; final int codePointSetSize = 50; @@ -229,7 +314,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -249,7 +334,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { words.add(word); final int unigramProbability = random.nextInt(0xFF); unigramProbabilities.put(word, unigramProbability); - binaryDictionary.addUnigramWord(word, unigramProbability); + addUnigramWord(binaryDictionary, word, unigramProbability); } for (int i = 0; i < bigramCount; i++) { @@ -262,7 +347,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { bigramWords.add(bigram); final int bigramProbability = random.nextInt(0xF); bigramProbabilities.put(bigram, bigramProbability); - binaryDictionary.addBigramWords(word0, word1, bigramProbability); + addBigramWords(binaryDictionary, word0, word1, bigramProbability); } for (final Pair<String, String> bigram : bigramWords) { @@ -278,9 +363,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testRemoveBigramWords() { + testRemoveBigramWords(FormatSpec.VERSION4); + } + + private void testRemoveBigramWords(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -289,13 +378,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); final int unigramProbability = 100; final int bigramProbability = 10; - binaryDictionary.addUnigramWord("aaa", unigramProbability); - binaryDictionary.addUnigramWord("abb", unigramProbability); - binaryDictionary.addUnigramWord("bcc", unigramProbability); - binaryDictionary.addBigramWords("aaa", "abb", bigramProbability); - binaryDictionary.addBigramWords("aaa", "bcc", bigramProbability); - binaryDictionary.addBigramWords("abb", "aaa", bigramProbability); - binaryDictionary.addBigramWords("abb", "bcc", bigramProbability); + addUnigramWord(binaryDictionary, "aaa", unigramProbability); + addUnigramWord(binaryDictionary, "abb", unigramProbability); + addUnigramWord(binaryDictionary, "bcc", unigramProbability); + addBigramWords(binaryDictionary, "aaa", "abb", bigramProbability); + addBigramWords(binaryDictionary, "aaa", "bcc", bigramProbability); + addBigramWords(binaryDictionary, "abb", "aaa", bigramProbability); + addBigramWords(binaryDictionary, "abb", "bcc", bigramProbability); assertEquals(true, binaryDictionary.isValidBigram("aaa", "abb")); assertEquals(true, binaryDictionary.isValidBigram("aaa", "bcc")); @@ -304,7 +393,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { binaryDictionary.removeBigramWords("aaa", "abb"); assertEquals(false, binaryDictionary.isValidBigram("aaa", "abb")); - binaryDictionary.addBigramWords("aaa", "abb", bigramProbability); + addBigramWords(binaryDictionary, "aaa", "abb", bigramProbability); assertEquals(true, binaryDictionary.isValidBigram("aaa", "abb")); @@ -324,9 +413,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testFlushDictionary() { + testFlushDictionary(FormatSpec.VERSION4); + } + + private void testFlushDictionary(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -335,8 +428,8 @@ public class BinaryDictionaryTests extends AndroidTestCase { Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); final int probability = 100; - binaryDictionary.addUnigramWord("aaa", probability); - binaryDictionary.addUnigramWord("abcd", probability); + addUnigramWord(binaryDictionary, "aaa", probability); + addUnigramWord(binaryDictionary, "abcd", probability); // Close without flushing. binaryDictionary.close(); @@ -347,8 +440,8 @@ public class BinaryDictionaryTests extends AndroidTestCase { assertEquals(Dictionary.NOT_A_PROBABILITY, binaryDictionary.getFrequency("aaa")); assertEquals(Dictionary.NOT_A_PROBABILITY, binaryDictionary.getFrequency("abcd")); - binaryDictionary.addUnigramWord("aaa", probability); - binaryDictionary.addUnigramWord("abcd", probability); + addUnigramWord(binaryDictionary, "aaa", probability); + addUnigramWord(binaryDictionary, "abcd", probability); binaryDictionary.flush(); binaryDictionary.close(); @@ -358,7 +451,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { assertEquals(probability, binaryDictionary.getFrequency("aaa")); assertEquals(probability, binaryDictionary.getFrequency("abcd")); - binaryDictionary.addUnigramWord("bcde", probability); + addUnigramWord(binaryDictionary, "bcde", probability); binaryDictionary.flush(); binaryDictionary.close(); @@ -372,9 +465,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testFlushWithGCDictionary() { + testFlushWithGCDictionary(FormatSpec.VERSION4); + } + + private void testFlushWithGCDictionary(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -384,13 +481,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { final int unigramProbability = 100; final int bigramProbability = 10; - binaryDictionary.addUnigramWord("aaa", unigramProbability); - binaryDictionary.addUnigramWord("abb", unigramProbability); - binaryDictionary.addUnigramWord("bcc", unigramProbability); - binaryDictionary.addBigramWords("aaa", "abb", bigramProbability); - binaryDictionary.addBigramWords("aaa", "bcc", bigramProbability); - binaryDictionary.addBigramWords("abb", "aaa", bigramProbability); - binaryDictionary.addBigramWords("abb", "bcc", bigramProbability); + addUnigramWord(binaryDictionary, "aaa", unigramProbability); + addUnigramWord(binaryDictionary, "abb", unigramProbability); + addUnigramWord(binaryDictionary, "bcc", unigramProbability); + addBigramWords(binaryDictionary, "aaa", "abb", bigramProbability); + addBigramWords(binaryDictionary, "aaa", "bcc", bigramProbability); + addBigramWords(binaryDictionary, "abb", "aaa", bigramProbability); + addBigramWords(binaryDictionary, "abb", "bcc", bigramProbability); binaryDictionary.flushWithGC(); binaryDictionary.close(); @@ -415,8 +512,12 @@ public class BinaryDictionaryTests extends AndroidTestCase { dictFile.delete(); } - // TODO: Evaluate performance of GC public void testAddBigramWordsAndFlashWithGC() { + testAddBigramWordsAndFlashWithGC(FormatSpec.VERSION4); + } + + // TODO: Evaluate performance of GC + private void testAddBigramWordsAndFlashWithGC(final int formatVersion) { final int wordCount = 100; final int bigramCount = 1000; final int codePointSetSize = 30; @@ -425,7 +526,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -446,7 +547,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { words.add(word); final int unigramProbability = random.nextInt(0xFF); unigramProbabilities.put(word, unigramProbability); - binaryDictionary.addUnigramWord(word, unigramProbability); + addUnigramWord(binaryDictionary, word, unigramProbability); } for (int i = 0; i < bigramCount; i++) { @@ -459,7 +560,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { bigramWords.add(bigram); final int bigramProbability = random.nextInt(0xF); bigramProbabilities.put(bigram, bigramProbability); - binaryDictionary.addBigramWords(word0, word1, bigramProbability); + addBigramWords(binaryDictionary, word0, word1, bigramProbability); } binaryDictionary.flushWithGC(); @@ -480,7 +581,11 @@ public class BinaryDictionaryTests extends AndroidTestCase { dictFile.delete(); } - public void testRandomOperetionsAndFlashWithGC() { + public void testRandomOperationsAndFlashWithGC() { + testRandomOperationsAndFlashWithGC(FormatSpec.VERSION4); + } + + private void testRandomOperationsAndFlashWithGC(final int formatVersion) { final int flashWithGCIterationCount = 50; final int operationCountInEachIteration = 200; final int initialUnigramCount = 100; @@ -494,7 +599,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -513,7 +618,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { words.add(word); final int unigramProbability = random.nextInt(0xFF); unigramProbabilities.put(word, unigramProbability); - binaryDictionary.addUnigramWord(word, unigramProbability); + addUnigramWord(binaryDictionary, word, unigramProbability); } binaryDictionary.flushWithGC(); binaryDictionary.close(); @@ -529,7 +634,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { words.add(word); final int unigramProbability = random.nextInt(0xFF); unigramProbabilities.put(word, unigramProbability); - binaryDictionary.addUnigramWord(word, unigramProbability); + addUnigramWord(binaryDictionary, word, unigramProbability); } // Add bigram. if (random.nextFloat() < addBigramProb && words.size() > 2) { @@ -547,7 +652,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { final Pair<String, String> bigram = new Pair<String, String>(word0, word1); bigramWords.add(bigram); bigramProbabilities.put(bigram, bigramProbability); - binaryDictionary.addBigramWords(word0, word1, bigramProbability); + addBigramWords(binaryDictionary, word0, word1, bigramProbability); } // Remove bigram. if (random.nextFloat() < removeBigramProb && !bigramWords.isEmpty()) { @@ -588,6 +693,10 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testAddManyUnigramsAndFlushWithGC() { + testAddManyUnigramsAndFlushWithGC(FormatSpec.VERSION4); + } + + private void testAddManyUnigramsAndFlushWithGC(final int formatVersion) { final int flashWithGCIterationCount = 3; final int codePointSetSize = 50; @@ -596,7 +705,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -615,7 +724,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { words.add(word); final int unigramProbability = random.nextInt(0xFF); unigramProbabilities.put(word, unigramProbability); - binaryDictionary.addUnigramWord(word, unigramProbability); + addUnigramWord(binaryDictionary, word, unigramProbability); } for (int j = 0; j < words.size(); j++) { @@ -632,6 +741,10 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testUnigramAndBigramCount() { + testUnigramAndBigramCount(FormatSpec.VERSION4); + } + + private void testUnigramAndBigramCount(final int formatVersion) { final int flashWithGCIterationCount = 10; final int codePointSetSize = 50; final int unigramCountPerIteration = 1000; @@ -641,7 +754,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -659,7 +772,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { final String word = CodePointUtils.generateWord(random, codePointSet); words.add(word); final int unigramProbability = random.nextInt(0xFF); - binaryDictionary.addUnigramWord(word, unigramProbability); + addUnigramWord(binaryDictionary, word, unigramProbability); } for (int j = 0; j < bigramCountPerIteration; j++) { final String word0 = words.get(random.nextInt(words.size())); @@ -669,20 +782,408 @@ public class BinaryDictionaryTests extends AndroidTestCase { } bigrams.add(new Pair<String, String>(word0, word1)); final int bigramProbability = random.nextInt(0xF); - binaryDictionary.addBigramWords(word0, word1, bigramProbability); + addBigramWords(binaryDictionary, word0, word1, bigramProbability); } assertEquals(new HashSet<String>(words).size(), Integer.parseInt( - binaryDictionary.getPropertyForTests(BinaryDictionary.UNIGRAM_COUNT_QUERY))); + binaryDictionary.getPropertyForTest(BinaryDictionary.UNIGRAM_COUNT_QUERY))); assertEquals(new HashSet<Pair<String, String>>(bigrams).size(), Integer.parseInt( - binaryDictionary.getPropertyForTests(BinaryDictionary.BIGRAM_COUNT_QUERY))); + binaryDictionary.getPropertyForTest(BinaryDictionary.BIGRAM_COUNT_QUERY))); binaryDictionary.flushWithGC(); assertEquals(new HashSet<String>(words).size(), Integer.parseInt( - binaryDictionary.getPropertyForTests(BinaryDictionary.UNIGRAM_COUNT_QUERY))); + binaryDictionary.getPropertyForTest(BinaryDictionary.UNIGRAM_COUNT_QUERY))); assertEquals(new HashSet<Pair<String, String>>(bigrams).size(), Integer.parseInt( - binaryDictionary.getPropertyForTests(BinaryDictionary.BIGRAM_COUNT_QUERY))); + binaryDictionary.getPropertyForTest(BinaryDictionary.BIGRAM_COUNT_QUERY))); binaryDictionary.close(); } dictFile.delete(); } + + public void testAddMultipleDictionaryEntries() { + testAddMultipleDictionaryEntries(FormatSpec.VERSION4); + } + + private void testAddMultipleDictionaryEntries(final int formatVersion) { + final int codePointSetSize = 20; + final int lmParamCount = 1000; + final double bigramContinueRate = 0.9; + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + + final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); + final HashMap<String, Integer> unigramProbabilities = new HashMap<String, Integer>(); + final HashMap<Pair<String, String>, Integer> bigramProbabilities = + new HashMap<Pair<String, String>, Integer>(); + + final LanguageModelParam[] languageModelParams = new LanguageModelParam[lmParamCount]; + String prevWord = null; + for (int i = 0; i < languageModelParams.length; i++) { + final String word = CodePointUtils.generateWord(random, codePointSet); + final int probability = random.nextInt(0xFF); + final int bigramProbability = random.nextInt(0xF); + unigramProbabilities.put(word, probability); + if (prevWord == null) { + languageModelParams[i] = new LanguageModelParam(word, probability, + BinaryDictionary.NOT_A_VALID_TIMESTAMP); + } else { + languageModelParams[i] = new LanguageModelParam(prevWord, word, probability, + bigramProbability, BinaryDictionary.NOT_A_VALID_TIMESTAMP); + bigramProbabilities.put(new Pair<String, String>(prevWord, word), + bigramProbability); + } + prevWord = (random.nextDouble() < bigramContinueRate) ? word : null; + } + + final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + binaryDictionary.addMultipleDictionaryEntries(languageModelParams); + + for (Map.Entry<String, Integer> entry : unigramProbabilities.entrySet()) { + assertEquals((int)entry.getValue(), binaryDictionary.getFrequency(entry.getKey())); + } + + for (Map.Entry<Pair<String, String>, Integer> entry : bigramProbabilities.entrySet()) { + final String word0 = entry.getKey().first; + final String word1 = entry.getKey().second; + final int unigramProbability = unigramProbabilities.get(word1); + final int bigramProbability = entry.getValue(); + final int probability = binaryDictionary.calculateProbability( + unigramProbability, bigramProbability); + assertEquals(probability, binaryDictionary.getBigramProbability(word0, word1)); + } + } + + public void testGetWordProperties() { + testGetWordProperties(FormatSpec.VERSION4); + } + + private void testGetWordProperties(final int formatVersion) { + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + final int UNIGRAM_COUNT = 1000; + final int BIGRAM_COUNT = 1000; + final int codePointSetSize = 20; + final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); + + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + + final WordProperty invalidWordProperty = binaryDictionary.getWordProperty("dummyWord"); + assertFalse(invalidWordProperty.isValid()); + + final ArrayList<String> words = new ArrayList<String>(); + final HashMap<String, Integer> wordProbabilities = new HashMap<String, Integer>(); + final HashMap<String, HashSet<String>> bigrams = new HashMap<String, HashSet<String>>(); + final HashMap<Pair<String, String>, Integer> bigramProbabilities = + new HashMap<Pair<String, String>, Integer>(); + + for (int i = 0; i < UNIGRAM_COUNT; i++) { + final String word = CodePointUtils.generateWord(random, codePointSet); + final int unigramProbability = random.nextInt(0xFF); + final boolean isNotAWord = random.nextBoolean(); + final boolean isBlacklisted = random.nextBoolean(); + // TODO: Add tests for historical info. + binaryDictionary.addUnigramWord(word, unigramProbability, + null /* shortcutTarget */, BinaryDictionary.NOT_A_PROBABILITY, + isNotAWord, isBlacklisted, BinaryDictionary.NOT_A_VALID_TIMESTAMP); + if (binaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) { + binaryDictionary.flushWithGC(); + } + words.add(word); + wordProbabilities.put(word, unigramProbability); + final WordProperty wordProperty = binaryDictionary.getWordProperty(word); + assertEquals(word, wordProperty.mWord); + assertTrue(wordProperty.isValid()); + assertEquals(isNotAWord, wordProperty.mIsNotAWord); + assertEquals(isBlacklisted, wordProperty.mIsBlacklistEntry); + assertEquals(false, wordProperty.mHasBigrams); + assertEquals(false, wordProperty.mHasShortcuts); + assertEquals(unigramProbability, wordProperty.mProbabilityInfo.mProbability); + assertTrue(wordProperty.mShortcutTargets.isEmpty()); + } + + for (int i = 0; i < BIGRAM_COUNT; i++) { + final int word0Index = random.nextInt(wordProbabilities.size()); + final int word1Index = random.nextInt(wordProbabilities.size()); + if (word0Index == word1Index) { + continue; + } + final String word0 = words.get(word0Index); + final String word1 = words.get(word1Index); + final int bigramProbability = random.nextInt(0xF); + binaryDictionary.addBigramWords(word0, word1, bigramProbability, + BinaryDictionary.NOT_A_VALID_TIMESTAMP); + if (binaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) { + binaryDictionary.flushWithGC(); + } + if (!bigrams.containsKey(word0)) { + final HashSet<String> bigramWord1s = new HashSet<String>(); + bigrams.put(word0, bigramWord1s); + } + bigrams.get(word0).add(word1); + bigramProbabilities.put(new Pair<String, String>(word0, word1), bigramProbability); + } + + for (int i = 0; i < words.size(); i++) { + final String word0 = words.get(i); + if (!bigrams.containsKey(word0)) { + continue; + } + final HashSet<String> bigramWord1s = bigrams.get(word0); + final WordProperty wordProperty = binaryDictionary.getWordProperty(word0); + assertEquals(bigramWord1s.size(), wordProperty.mBigrams.size()); + for (int j = 0; j < wordProperty.mBigrams.size(); j++) { + final String word1 = wordProperty.mBigrams.get(j).mWord; + assertTrue(bigramWord1s.contains(word1)); + final int probability = wordProperty.mBigrams.get(j).getProbability(); + assertEquals((int)bigramProbabilities.get(new Pair<String, String>(word0, word1)), + probability); + assertEquals(wordProperty.mBigrams.get(j).getProbability(), probability); + } + } + } + + public void testIterateAllWords() { + testIterateAllWords(FormatSpec.VERSION4); + } + + private void testIterateAllWords(final int formatVersion) { + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + final int UNIGRAM_COUNT = 1000; + final int BIGRAM_COUNT = 1000; + final int codePointSetSize = 20; + final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); + + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + + final WordProperty invalidWordProperty = binaryDictionary.getWordProperty("dummyWord"); + assertFalse(invalidWordProperty.isValid()); + + final ArrayList<String> words = new ArrayList<String>(); + final HashMap<String, Integer> wordProbabilitiesToCheckLater = + new HashMap<String, Integer>(); + final HashMap<String, HashSet<String>> bigrams = new HashMap<String, HashSet<String>>(); + final HashMap<Pair<String, String>, Integer> bigramProbabilitiesToCheckLater = + new HashMap<Pair<String, String>, Integer>(); + + for (int i = 0; i < UNIGRAM_COUNT; i++) { + final String word = CodePointUtils.generateWord(random, codePointSet); + final int unigramProbability = random.nextInt(0xFF); + addUnigramWord(binaryDictionary, word, unigramProbability); + if (binaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) { + binaryDictionary.flushWithGC(); + } + words.add(word); + wordProbabilitiesToCheckLater.put(word, unigramProbability); + } + + for (int i = 0; i < BIGRAM_COUNT; i++) { + final int word0Index = random.nextInt(wordProbabilitiesToCheckLater.size()); + final int word1Index = random.nextInt(wordProbabilitiesToCheckLater.size()); + if (word0Index == word1Index) { + continue; + } + final String word0 = words.get(word0Index); + final String word1 = words.get(word1Index); + final int bigramProbability = random.nextInt(0xF); + binaryDictionary.addBigramWords(word0, word1, bigramProbability, + BinaryDictionary.NOT_A_VALID_TIMESTAMP); + if (binaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) { + binaryDictionary.flushWithGC(); + } + if (!bigrams.containsKey(word0)) { + final HashSet<String> bigramWord1s = new HashSet<String>(); + bigrams.put(word0, bigramWord1s); + } + bigrams.get(word0).add(word1); + bigramProbabilitiesToCheckLater.put( + new Pair<String, String>(word0, word1), bigramProbability); + } + + final HashSet<String> wordSet = new HashSet<String>(words); + final HashSet<Pair<String, String>> bigramSet = + new HashSet<Pair<String,String>>(bigramProbabilitiesToCheckLater.keySet()); + int token = 0; + do { + final BinaryDictionary.GetNextWordPropertyResult result = + binaryDictionary.getNextWordProperty(token); + final WordProperty wordProperty = result.mWordProperty; + final String word0 = wordProperty.mWord; + assertEquals((int)wordProbabilitiesToCheckLater.get(word0), + wordProperty.mProbabilityInfo.mProbability); + wordSet.remove(word0); + final HashSet<String> bigramWord1s = bigrams.get(word0); + for (int j = 0; j < wordProperty.mBigrams.size(); j++) { + final String word1 = wordProperty.mBigrams.get(j).mWord; + assertTrue(bigramWord1s.contains(word1)); + final int probability = wordProperty.mBigrams.get(j).getProbability(); + final Pair<String, String> bigram = new Pair<String, String>(word0, word1); + assertEquals((int)bigramProbabilitiesToCheckLater.get(bigram), probability); + bigramSet.remove(bigram); + } + token = result.mNextToken; + } while (token != 0); + assertTrue(wordSet.isEmpty()); + assertTrue(bigramSet.isEmpty()); + } + + public void testAddShortcuts() { + testAddShortcuts(FormatSpec.VERSION4); + } + + private void testAddShortcuts(final int formatVersion) { + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + + final int unigramProbability = 100; + final int shortcutProbability = 10; + binaryDictionary.addUnigramWord("aaa", unigramProbability, "zzz", + shortcutProbability, false /* isNotAWord */, false /* isBlacklisted */, + 0 /* timestamp */); + WordProperty wordProperty = binaryDictionary.getWordProperty("aaa"); + assertEquals(1, wordProperty.mShortcutTargets.size()); + assertEquals("zzz", wordProperty.mShortcutTargets.get(0).mWord); + assertEquals(shortcutProbability, wordProperty.mShortcutTargets.get(0).getProbability()); + final int updatedShortcutProbability = 2; + binaryDictionary.addUnigramWord("aaa", unigramProbability, "zzz", + updatedShortcutProbability, false /* isNotAWord */, false /* isBlacklisted */, + 0 /* timestamp */); + wordProperty = binaryDictionary.getWordProperty("aaa"); + assertEquals(1, wordProperty.mShortcutTargets.size()); + assertEquals("zzz", wordProperty.mShortcutTargets.get(0).mWord); + assertEquals(updatedShortcutProbability, + wordProperty.mShortcutTargets.get(0).getProbability()); + binaryDictionary.addUnigramWord("aaa", unigramProbability, "yyy", + shortcutProbability, false /* isNotAWord */, false /* isBlacklisted */, + 0 /* timestamp */); + final HashMap<String, Integer> shortcutTargets = new HashMap<String, Integer>(); + shortcutTargets.put("zzz", updatedShortcutProbability); + shortcutTargets.put("yyy", shortcutProbability); + wordProperty = binaryDictionary.getWordProperty("aaa"); + assertEquals(2, wordProperty.mShortcutTargets.size()); + for (WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + assertTrue(shortcutTargets.containsKey(shortcutTarget.mWord)); + assertEquals((int)shortcutTargets.get(shortcutTarget.mWord), + shortcutTarget.getProbability()); + shortcutTargets.remove(shortcutTarget.mWord); + } + shortcutTargets.put("zzz", updatedShortcutProbability); + shortcutTargets.put("yyy", shortcutProbability); + binaryDictionary.flushWithGC(); + wordProperty = binaryDictionary.getWordProperty("aaa"); + assertEquals(2, wordProperty.mShortcutTargets.size()); + for (WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + assertTrue(shortcutTargets.containsKey(shortcutTarget.mWord)); + assertEquals((int)shortcutTargets.get(shortcutTarget.mWord), + shortcutTarget.getProbability()); + shortcutTargets.remove(shortcutTarget.mWord); + } + } + + public void testAddManyShortcuts() { + testAddManyShortcuts(FormatSpec.VERSION4); + } + + private void testAddManyShortcuts(final int formatVersion) { + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + final int UNIGRAM_COUNT = 1000; + final int SHORTCUT_COUNT = 10000; + final int codePointSetSize = 20; + final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); + + final ArrayList<String> words = new ArrayList<String>(); + final HashMap<String, Integer> unigramProbabilities = new HashMap<String, Integer>(); + final HashMap<String, HashMap<String, Integer>> shortcutTargets = + new HashMap<String, HashMap<String, Integer>>(); + + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + + for (int i = 0; i < UNIGRAM_COUNT; i++) { + final String word = CodePointUtils.generateWord(random, codePointSet); + final int unigramProbability = random.nextInt(0xFF); + addUnigramWord(binaryDictionary, word, unigramProbability); + words.add(word); + unigramProbabilities.put(word, unigramProbability); + if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { + binaryDictionary.flushWithGC(); + } + } + for (int i = 0; i < SHORTCUT_COUNT; i++) { + final String shortcutTarget = CodePointUtils.generateWord(random, codePointSet); + final int shortcutProbability = random.nextInt(0xF); + final String word = words.get(random.nextInt(words.size())); + final int unigramProbability = unigramProbabilities.get(word); + binaryDictionary.addUnigramWord(word, unigramProbability, shortcutTarget, + shortcutProbability, false /* isNotAWord */, false /* isBlacklisted */, + 0 /* timestamp */); + if (shortcutTargets.containsKey(word)) { + final HashMap<String, Integer> shortcutTargetsOfWord = shortcutTargets.get(word); + shortcutTargetsOfWord.put(shortcutTarget, shortcutProbability); + } else { + final HashMap<String, Integer> shortcutTargetsOfWord = + new HashMap<String, Integer>(); + shortcutTargetsOfWord.put(shortcutTarget, shortcutProbability); + shortcutTargets.put(word, shortcutTargetsOfWord); + } + if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { + binaryDictionary.flushWithGC(); + } + } + + for (final String word : words) { + final WordProperty wordProperty = binaryDictionary.getWordProperty(word); + assertEquals((int)unigramProbabilities.get(word), + wordProperty.mProbabilityInfo.mProbability); + if (!shortcutTargets.containsKey(word)) { + // The word does not have shortcut targets. + continue; + } + assertEquals(shortcutTargets.get(word).size(), wordProperty.mShortcutTargets.size()); + for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + final String targetCodePonts = shortcutTarget.mWord; + assertEquals((int)shortcutTargets.get(word).get(targetCodePonts), + shortcutTarget.getProbability()); + } + } + } } diff --git a/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java b/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java index c4fd5a0c4..6e894decf 100644 --- a/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java +++ b/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java @@ -50,8 +50,7 @@ public class BlueUnderlineTests extends InputTestsBase { final SpanGetter spanBefore = new SpanGetter(mEditText.getText(), SuggestionSpan.class); assertEquals("extend blue underline, span start", EXPECTED_SPAN_START, spanBefore.mStart); assertEquals("extend blue underline, span end", EXPECTED_SPAN_END, spanBefore.mEnd); - assertEquals("extend blue underline, span color", true, - spanBefore.isAutoCorrectionIndicator()); + assertTrue("extend blue underline, span color", spanBefore.isAutoCorrectionIndicator()); sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); // Now we have been able to re-evaluate the word, there shouldn't be an auto-correction span @@ -61,6 +60,7 @@ public class BlueUnderlineTests extends InputTestsBase { public void testBlueUnderlineOnBackspace() { final String STRING_TO_TYPE = "tgis"; + final int typedLength = STRING_TO_TYPE.length(); final int EXPECTED_SUGGESTION_SPAN_START = -1; final int EXPECTED_UNDERLINE_SPAN_START = 0; final int EXPECTED_UNDERLINE_SPAN_END = 4; @@ -68,6 +68,8 @@ public class BlueUnderlineTests extends InputTestsBase { sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); type(Constants.CODE_SPACE); + // typedLength + 1 because we also typed a space + mLatinIME.onUpdateSelection(0, 0, typedLength + 1, typedLength + 1, -1, -1); sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); type(Constants.CODE_DELETE); @@ -77,8 +79,8 @@ public class BlueUnderlineTests extends InputTestsBase { sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); final SpanGetter suggestionSpan = new SpanGetter(mEditText.getText(), SuggestionSpan.class); - assertEquals("show no blue underline after backspace, span start should be -1", - EXPECTED_SUGGESTION_SPAN_START, suggestionSpan.mStart); + assertFalse("show no blue underline after backspace, span should not be the auto-" + + "correction indicator", suggestionSpan.isAutoCorrectionIndicator()); final SpanGetter underlineSpan = new SpanGetter(mEditText.getText(), UnderlineSpan.class); assertEquals("should be composing, so should have an underline span", EXPECTED_UNDERLINE_SPAN_START, underlineSpan.mStart); @@ -104,7 +106,8 @@ public class BlueUnderlineTests extends InputTestsBase { sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); final SpanGetter span = new SpanGetter(mEditText.getText(), SuggestionSpan.class); - assertNull("blue underline removed when cursor is moved", span.mSpan); + assertFalse("blue underline removed when cursor is moved", + span.isAutoCorrectionIndicator()); } public void testComposingStopsOnSpace() { diff --git a/tests/src/com/android/inputmethod/latin/EditDistanceTests.java b/tests/src/com/android/inputmethod/latin/EditDistanceTests.java index 0b7fcbbe8..ffec20ab2 100644 --- a/tests/src/com/android/inputmethod/latin/EditDistanceTests.java +++ b/tests/src/com/android/inputmethod/latin/EditDistanceTests.java @@ -21,16 +21,6 @@ import android.test.suitebuilder.annotation.SmallTest; @SmallTest public class EditDistanceTests extends AndroidTestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - /* * dist(kitten, sitting) == 3 * diff --git a/tests/src/com/android/inputmethod/latin/ExpandableDictionaryTests.java b/tests/src/com/android/inputmethod/latin/ExpandableDictionaryTests.java deleted file mode 100644 index 6aae1044e..000000000 --- a/tests/src/com/android/inputmethod/latin/ExpandableDictionaryTests.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.inputmethod.latin; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -/** - * Unit test for ExpandableDictionary - */ -@SmallTest -public class ExpandableDictionaryTests extends AndroidTestCase { - - private final static int UNIGRAM_FREQ = 50; - // See UserBinaryDictionary for more information about this variable. - // For tests, its actual value does not matter. - private final static int SHORTCUT_FREQ = 14; - - public void testAddWordAndGetWordFrequency() { - final ExpandableDictionary dict = new ExpandableDictionary(Dictionary.TYPE_USER); - - // Add words - dict.addWord("abcde", "abcde", UNIGRAM_FREQ, SHORTCUT_FREQ); - dict.addWord("abcef", null, UNIGRAM_FREQ + 1, 0); - - // Check words - assertFalse(dict.isValidWord("abcde")); - assertEquals(UNIGRAM_FREQ, dict.getWordFrequency("abcde")); - assertTrue(dict.isValidWord("abcef")); - assertEquals(UNIGRAM_FREQ+1, dict.getWordFrequency("abcef")); - - dict.addWord("abc", null, UNIGRAM_FREQ + 2, 0); - assertTrue(dict.isValidWord("abc")); - assertEquals(UNIGRAM_FREQ + 2, dict.getWordFrequency("abc")); - - // Add existing word with lower frequency - dict.addWord("abc", null, UNIGRAM_FREQ, 0); - assertEquals(UNIGRAM_FREQ + 2, dict.getWordFrequency("abc")); - - // Add existing word with higher frequency - dict.addWord("abc", null, UNIGRAM_FREQ + 3, 0); - assertEquals(UNIGRAM_FREQ + 3, dict.getWordFrequency("abc")); - } -} diff --git a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java b/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java index cadd0f8f3..cf528d010 100644 --- a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java @@ -20,6 +20,7 @@ import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import com.android.inputmethod.latin.makedict.FusionDictionary; +import com.android.inputmethod.latin.makedict.ProbabilityInfo; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; import java.util.HashMap; @@ -31,18 +32,18 @@ import java.util.HashMap; public class FusionDictionaryTests extends AndroidTestCase { public void testFindWordInTree() { FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions(new HashMap<String,String>(), false, false)); + new FusionDictionary.DictionaryOptions(new HashMap<String,String>())); - dict.add("abc", 10, null, false /* isNotAWord */); + dict.add("abc", new ProbabilityInfo(10), null, false /* isNotAWord */); assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa")); assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "abc")); - dict.add("aa", 10, null, false /* isNotAWord */); + dict.add("aa", new ProbabilityInfo(10), null, false /* isNotAWord */); assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa")); assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aa")); - dict.add("babcd", 10, null, false /* isNotAWord */); - dict.add("bacde", 10, null, false /* isNotAWord */); + dict.add("babcd", new ProbabilityInfo(10), null, false /* isNotAWord */); + dict.add("bacde", new ProbabilityInfo(10), null, false /* isNotAWord */); assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "ba")); assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "babcd")); assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "bacde")); diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java index 8ad8689d8..ab9751380 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -307,12 +307,14 @@ public class InputLogicTests extends InputTestsBase { } public void testResumeSuggestionOnBackspace() { - final String WORD_TO_TYPE = "and this "; - type(WORD_TO_TYPE); + final String STRING_TO_TYPE = "and this "; + final int typedLength = STRING_TO_TYPE.length(); + type(STRING_TO_TYPE); assertEquals("resume suggestion on backspace", -1, BaseInputConnection.getComposingSpanStart(mEditText.getText())); assertEquals("resume suggestion on backspace", -1, BaseInputConnection.getComposingSpanEnd(mEditText.getText())); + mLatinIME.onUpdateSelection(0, 0, typedLength, typedLength, -1, -1); type(Constants.CODE_DELETE); assertEquals("resume suggestion on backspace", 4, BaseInputConnection.getComposingSpanStart(mEditText.getText())); @@ -348,4 +350,108 @@ public class InputLogicTests extends InputTestsBase { helperTestComposing("a'", true); } // TODO: Add some tests for non-BMP characters + + public void testAutoCorrectByUserHistory() { + final String WORD_TO_BE_CORRECTED = "qpmx"; + final String NOT_CORRECTED_RESULT = "qpmx "; + final String DESIRED_WORD = "qpmz"; + final String CORRECTED_RESULT = "qpmz "; + final int typeCountNotToAutocorrect = 3; + final int typeCountToAutoCorrect = 16; + int startIndex = 0; + int endIndex = 0; + + for (int i = 0; i < typeCountNotToAutocorrect; i++) { + type(DESIRED_WORD); + type(Constants.CODE_SPACE); + } + startIndex = mEditText.getText().length(); + type(WORD_TO_BE_CORRECTED); + type(Constants.CODE_SPACE); + endIndex = mEditText.getText().length(); + assertEquals("not auto-corrected by user history", NOT_CORRECTED_RESULT, + mEditText.getText().subSequence(startIndex, endIndex).toString()); + for (int i = typeCountNotToAutocorrect; i < typeCountToAutoCorrect; i++) { + type(DESIRED_WORD); + type(Constants.CODE_SPACE); + } + startIndex = mEditText.getText().length(); + type(WORD_TO_BE_CORRECTED); + type(Constants.CODE_SPACE); + endIndex = mEditText.getText().length(); + assertEquals("auto-corrected by user history", + CORRECTED_RESULT, mEditText.getText().subSequence(startIndex, endIndex).toString()); + } + + public void testPredictionsAfterSpace() { + final String WORD_TO_TYPE = "Barack "; + type(WORD_TO_TYPE); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + // Test the first prediction is displayed + final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest(); + assertEquals("predictions after space", "Obama", + suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null); + } + + public void testPredictionsAfterManualPick() { + final String WORD_TO_TYPE = "Barack"; + type(WORD_TO_TYPE); + // Choose the auto-correction, which is always in position 0. For "Barack", the + // auto-correction should be "Barack". + pickSuggestionManually(0, WORD_TO_TYPE); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + // Test the first prediction is displayed + final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest(); + assertEquals("predictions after manual pick", "Obama", + suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null); + } + + public void testNoPredictionsAfterPeriod() { + final String WORD_TO_TYPE = "Barack. "; + type(WORD_TO_TYPE); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + // Test the first prediction is not displayed + final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest(); + assertEquals("no prediction after period", 0, suggestedWords.size()); + } + + public void testPredictionsAfterRecorrection() { + final String PREFIX = "A "; + final String WORD_TO_TYPE = "Barack"; + final String FIRST_NON_TYPED_SUGGESTION = "Barrack"; + final int endOfPrefix = PREFIX.length(); + final int endOfWord = endOfPrefix + WORD_TO_TYPE.length(); + final int endOfSuggestion = endOfPrefix + FIRST_NON_TYPED_SUGGESTION.length(); + final int indexForManualCursor = endOfPrefix + 3; // +3 because it's after "Bar" in "Barack" + type(PREFIX); + mLatinIME.onUpdateSelection(0, 0, endOfPrefix, endOfPrefix, -1, -1); + type(WORD_TO_TYPE); + pickSuggestionManually(1, FIRST_NON_TYPED_SUGGESTION); + mLatinIME.onUpdateSelection(endOfPrefix, endOfPrefix, endOfSuggestion, endOfSuggestion, + -1, -1); + runMessages(); + type(" "); + mLatinIME.onUpdateSelection(endOfSuggestion, endOfSuggestion, + endOfSuggestion + 1, endOfSuggestion + 1, -1, -1); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + // Simulate a manual cursor move + mInputConnection.setSelection(indexForManualCursor, indexForManualCursor); + mLatinIME.onUpdateSelection(endOfSuggestion + 1, endOfSuggestion + 1, + indexForManualCursor, indexForManualCursor, -1, -1); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + pickSuggestionManually(0, WORD_TO_TYPE); + mLatinIME.onUpdateSelection(indexForManualCursor, indexForManualCursor, + endOfWord, endOfWord, -1, -1); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + // Test the first prediction is displayed + final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest(); + assertEquals("predictions after recorrection", "Obama", + suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null); + } } diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java b/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java index 0f0ebafb9..e38ba721e 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java @@ -99,7 +99,8 @@ public class InputLogicTestsLanguageWithoutSpaces extends InputTestsBase { assertEquals("predictions in lang without spaces", "Barack", mEditText.getText().toString()); // Test the first prediction is displayed + final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest(); assertEquals("predictions in lang without spaces", "Obama", - mLatinIME.getFirstSuggestedWord()); + suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null); } } diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java b/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java index 2d736e338..1257ae297 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java @@ -60,7 +60,7 @@ public class InputLogicTestsNonEnglish extends InputTestsBase { sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); assertTrue("type word then type space should display punctuation strip", - mLatinIME.isShowingPunctuationList()); + mLatinIME.getSuggestedWordsForTest().isPunctuationSuggestions()); pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); assertEquals("type word then type space then punctuation from strip twice for French", @@ -84,8 +84,9 @@ public class InputLogicTestsNonEnglish extends InputTestsBase { type(WORD_TO_TYPE); sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); + final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest(); assertEquals("type word then type space yields predictions for French", - EXPECTED_RESULT, mLatinIME.getFirstSuggestedWord()); + EXPECTED_RESULT, suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null); } finally { setBooleanPreference(NEXT_WORD_PREDICTION_OPTION, previousNextWordPredictionOption, defaultNextWordPredictionOption); diff --git a/tests/src/com/android/inputmethod/latin/InputPointersTests.java b/tests/src/com/android/inputmethod/latin/InputPointersTests.java index 5095f9606..1a47cddf4 100644 --- a/tests/src/com/android/inputmethod/latin/InputPointersTests.java +++ b/tests/src/com/android/inputmethod/latin/InputPointersTests.java @@ -55,14 +55,22 @@ public class InputPointersTests extends AndroidTestCase { final InputPointers src = new InputPointers(DEFAULT_CAPACITY); final int limit = src.getXCoordinates().length * 2 + 10; for (int i = 0; i < limit; i++) { - src.addPointer(i, i * 2, i * 3, i * 4); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + src.addPointer(x, y, pointerId, time); assertEquals("size after add " + i, i + 1, src.getPointerSize()); } for (int i = 0; i < limit; i++) { - assertEquals("xCoordinates at " + i, i, src.getXCoordinates()[i]); - assertEquals("yCoordinates at " + i, i * 2, src.getYCoordinates()[i]); - assertEquals("pointerIds at " + i, i * 3, src.getPointerIds()[i]); - assertEquals("times at " + i, i * 4, src.getTimes()[i]); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + assertEquals("xCoordinates at " + i, x, src.getXCoordinates()[i]); + assertEquals("yCoordinates at " + i, y, src.getYCoordinates()[i]); + assertEquals("pointerIds at " + i, pointerId, src.getPointerIds()[i]); + assertEquals("times at " + i, time, src.getTimes()[i]); } } @@ -70,14 +78,22 @@ public class InputPointersTests extends AndroidTestCase { final InputPointers src = new InputPointers(DEFAULT_CAPACITY); final int limit = 1000, step = 100; for (int i = 0; i < limit; i += step) { - src.addPointer(i, i, i * 2, i * 3, i * 4); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + src.addPointerAt(i, x, y, pointerId, time); assertEquals("size after add at " + i, i + 1, src.getPointerSize()); } for (int i = 0; i < limit; i += step) { - assertEquals("xCoordinates at " + i, i, src.getXCoordinates()[i]); - assertEquals("yCoordinates at " + i, i * 2, src.getYCoordinates()[i]); - assertEquals("pointerIds at " + i, i * 3, src.getPointerIds()[i]); - assertEquals("times at " + i, i * 4, src.getTimes()[i]); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + assertEquals("xCoordinates at " + i, x, src.getXCoordinates()[i]); + assertEquals("yCoordinates at " + i, y, src.getYCoordinates()[i]); + assertEquals("pointerIds at " + i, pointerId, src.getPointerIds()[i]); + assertEquals("times at " + i, time, src.getTimes()[i]); } } @@ -85,7 +101,11 @@ public class InputPointersTests extends AndroidTestCase { final InputPointers src = new InputPointers(DEFAULT_CAPACITY); final int limit = src.getXCoordinates().length * 2 + 10; for (int i = 0; i < limit; i++) { - src.addPointer(i, i * 2, i * 3, i * 4); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + src.addPointer(x, y, pointerId, time); } final InputPointers dst = new InputPointers(DEFAULT_CAPACITY); dst.set(src); @@ -100,7 +120,11 @@ public class InputPointersTests extends AndroidTestCase { final InputPointers src = new InputPointers(DEFAULT_CAPACITY); final int limit = 100; for (int i = 0; i < limit; i++) { - src.addPointer(i, i * 2, i * 3, i * 4); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + src.addPointer(x, y, pointerId, time); } final InputPointers dst = new InputPointers(DEFAULT_CAPACITY); dst.copy(src); @@ -121,106 +145,135 @@ public class InputPointersTests extends AndroidTestCase { } public void testAppend() { - final InputPointers src = new InputPointers(DEFAULT_CAPACITY); - final int srcLen = 100; - for (int i = 0; i < srcLen; i++) { - src.addPointer(i, i * 2, i * 3, i * 4); - } - final int dstLen = 50; + final int dstLength = 50; final InputPointers dst = new InputPointers(DEFAULT_CAPACITY); - for (int i = 0; i < dstLen; i++) { - final int value = -i - 1; - dst.addPointer(value * 4, value * 3, value * 2, value); + for (int i = 0; i < dstLength; i++) { + final int x = i * 4; + final int y = i * 3; + final int pointerId = i * 2; + final int time = i; + dst.addPointer(x, y, pointerId, time); } final InputPointers dstCopy = new InputPointers(DEFAULT_CAPACITY); dstCopy.copy(dst); - dst.append(src, 0, 0); - assertEquals("size after append zero", dstLen, dst.getPointerSize()); + final ResizableIntArray srcXCoords = new ResizableIntArray(DEFAULT_CAPACITY); + final ResizableIntArray srcYCoords = new ResizableIntArray(DEFAULT_CAPACITY); + final ResizableIntArray srcPointerIds = new ResizableIntArray(DEFAULT_CAPACITY); + final ResizableIntArray srcTimes = new ResizableIntArray(DEFAULT_CAPACITY); + final int srcLength = 100; + final int srcPointerId = 10; + for (int i = 0; i < srcLength; i++) { + final int x = i; + final int y = i * 2; + // The time value must be larger than <code>dst</code>. + final int time = i * 4 + dstLength; + srcXCoords.add(x); + srcYCoords.add(y); + srcPointerIds.add(srcPointerId); + srcTimes.add(time); + } + + final int startPos = 0; + dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords, + startPos, 0 /* length */); + assertEquals("size after append zero", dstLength, dst.getPointerSize()); assertIntArrayEquals("xCoordinates after append zero", - dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLen); + dstCopy.getXCoordinates(), startPos, dst.getXCoordinates(), startPos, dstLength); assertIntArrayEquals("yCoordinates after append zero", - dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLen); + dstCopy.getYCoordinates(), startPos, dst.getYCoordinates(), startPos, dstLength); assertIntArrayEquals("pointerIds after append zero", - dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLen); + dstCopy.getPointerIds(), startPos, dst.getPointerIds(), startPos, dstLength); assertIntArrayEquals("times after append zero", - dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLen); + dstCopy.getTimes(), startPos, dst.getTimes(), startPos, dstLength); - dst.append(src, 0, srcLen); - assertEquals("size after append", dstLen + srcLen, dst.getPointerSize()); + dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords, + startPos, srcLength); + assertEquals("size after append", dstLength + srcLength, dst.getPointerSize()); assertTrue("primitive length after append", - dst.getPointerIds().length >= dstLen + srcLen); + dst.getPointerIds().length >= dstLength + srcLength); assertIntArrayEquals("original xCoordinates values after append", - dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLen); + dstCopy.getXCoordinates(), startPos, dst.getXCoordinates(), startPos, dstLength); assertIntArrayEquals("original yCoordinates values after append", - dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLen); + dstCopy.getYCoordinates(), startPos, dst.getYCoordinates(), startPos, dstLength); assertIntArrayEquals("original pointerIds values after append", - dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLen); + dstCopy.getPointerIds(), startPos, dst.getPointerIds(), startPos, dstLength); assertIntArrayEquals("original times values after append", - dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLen); + dstCopy.getTimes(), startPos, dst.getTimes(), startPos, dstLength); assertIntArrayEquals("appended xCoordinates values after append", - src.getXCoordinates(), 0, dst.getXCoordinates(), dstLen, srcLen); + srcXCoords.getPrimitiveArray(), startPos, dst.getXCoordinates(), + dstLength, srcLength); assertIntArrayEquals("appended yCoordinates values after append", - src.getYCoordinates(), 0, dst.getYCoordinates(), dstLen, srcLen); + srcYCoords.getPrimitiveArray(), startPos, dst.getYCoordinates(), + dstLength, srcLength); assertIntArrayEquals("appended pointerIds values after append", - src.getPointerIds(), 0, dst.getPointerIds(), dstLen, srcLen); + srcPointerIds.getPrimitiveArray(), startPos, dst.getPointerIds(), + dstLength, srcLength); assertIntArrayEquals("appended times values after append", - src.getTimes(), 0, dst.getTimes(), dstLen, srcLen); + srcTimes.getPrimitiveArray(), startPos, dst.getTimes(), dstLength, srcLength); } public void testAppendResizableIntArray() { - final int srcLen = 100; + final int dstLength = 50; + final InputPointers dst = new InputPointers(DEFAULT_CAPACITY); + for (int i = 0; i < dstLength; i++) { + final int x = i * 4; + final int y = i * 3; + final int pointerId = i * 2; + final int time = i; + dst.addPointer(x, y, pointerId, time); + } + final InputPointers dstCopy = new InputPointers(DEFAULT_CAPACITY); + dstCopy.copy(dst); + + final int srcLength = 100; final int srcPointerId = 1; - final int[] srcPointerIds = new int[srcLen]; + final int[] srcPointerIds = new int[srcLength]; Arrays.fill(srcPointerIds, srcPointerId); final ResizableIntArray srcTimes = new ResizableIntArray(DEFAULT_CAPACITY); final ResizableIntArray srcXCoords = new ResizableIntArray(DEFAULT_CAPACITY); final ResizableIntArray srcYCoords= new ResizableIntArray(DEFAULT_CAPACITY); - for (int i = 0; i < srcLen; i++) { - srcTimes.add(i * 2); - srcXCoords.add(i * 3); - srcYCoords.add(i * 4); + for (int i = 0; i < srcLength; i++) { + // The time value must be larger than <code>dst</code>. + final int time = i * 2 + dstLength; + final int x = i * 3; + final int y = i * 4; + srcTimes.add(time); + srcXCoords.add(x); + srcYCoords.add(y); } - final int dstLen = 50; - final InputPointers dst = new InputPointers(DEFAULT_CAPACITY); - for (int i = 0; i < dstLen; i++) { - final int value = -i - 1; - dst.addPointer(value * 4, value * 3, value * 2, value); - } - final InputPointers dstCopy = new InputPointers(DEFAULT_CAPACITY); - dstCopy.copy(dst); dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords, 0, 0); - assertEquals("size after append zero", dstLen, dst.getPointerSize()); + assertEquals("size after append zero", dstLength, dst.getPointerSize()); assertIntArrayEquals("xCoordinates after append zero", - dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLen); + dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLength); assertIntArrayEquals("yCoordinates after append zero", - dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLen); + dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLength); assertIntArrayEquals("pointerIds after append zero", - dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLen); + dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLength); assertIntArrayEquals("times after append zero", - dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLen); + dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLength); - dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords, 0, srcLen); - assertEquals("size after append", dstLen + srcLen, dst.getPointerSize()); + dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords, 0, srcLength); + assertEquals("size after append", dstLength + srcLength, dst.getPointerSize()); assertTrue("primitive length after append", - dst.getPointerIds().length >= dstLen + srcLen); + dst.getPointerIds().length >= dstLength + srcLength); assertIntArrayEquals("original xCoordinates values after append", - dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLen); + dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLength); assertIntArrayEquals("original yCoordinates values after append", - dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLen); + dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLength); assertIntArrayEquals("original pointerIds values after append", - dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLen); + dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLength); assertIntArrayEquals("original times values after append", - dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLen); + dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLength); assertIntArrayEquals("appended xCoordinates values after append", - srcXCoords.getPrimitiveArray(), 0, dst.getXCoordinates(), dstLen, srcLen); + srcXCoords.getPrimitiveArray(), 0, dst.getXCoordinates(), dstLength, srcLength); assertIntArrayEquals("appended yCoordinates values after append", - srcYCoords.getPrimitiveArray(), 0, dst.getYCoordinates(), dstLen, srcLen); + srcYCoords.getPrimitiveArray(), 0, dst.getYCoordinates(), dstLength, srcLength); assertIntArrayEquals("appended pointerIds values after append", - srcPointerIds, 0, dst.getPointerIds(), dstLen, srcLen); + srcPointerIds, 0, dst.getPointerIds(), dstLength, srcLength); assertIntArrayEquals("appended times values after append", - srcTimes.getPrimitiveArray(), 0, dst.getTimes(), dstLen, srcLen); + srcTimes.getPrimitiveArray(), 0, dst.getTimes(), dstLength, srcLength); } // TODO: Consolidate this method with @@ -250,14 +303,24 @@ public class InputPointersTests extends AndroidTestCase { final int limit = 100; final int shiftAmount = 20; for (int i = 0; i < limit; i++) { - src.addPointer(i, i * 2, i * 3, i * 4); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + src.addPointer(x, y, pointerId, time); } src.shift(shiftAmount); + assertEquals("length after shift", src.getPointerSize(), limit - shiftAmount); for (int i = 0; i < limit - shiftAmount; ++i) { - assertEquals("xCoordinates at " + i, i + shiftAmount, src.getXCoordinates()[i]); - assertEquals("yCoordinates at " + i, (i + shiftAmount) * 2, src.getYCoordinates()[i]); - assertEquals("pointerIds at " + i, (i + shiftAmount) * 3, src.getPointerIds()[i]); - assertEquals("times at " + i, (i + shiftAmount) * 4, src.getTimes()[i]); + final int oldIndex = i + shiftAmount; + final int x = oldIndex; + final int y = oldIndex * 2; + final int pointerId = oldIndex * 3; + final int time = oldIndex * 4; + assertEquals("xCoordinates at " + i, x, src.getXCoordinates()[i]); + assertEquals("yCoordinates at " + i, y, src.getYCoordinates()[i]); + assertEquals("pointerIds at " + i, pointerId, src.getPointerIds()[i]); + assertEquals("times at " + i, time, src.getTimes()[i]); } } } diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java index b9b52a6f3..690c559e8 100644 --- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java +++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java @@ -25,35 +25,49 @@ import android.text.InputType; import android.text.SpannableStringBuilder; import android.text.style.CharacterStyle; import android.text.style.SuggestionSpan; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InputMethodSubtype; import android.widget.EditText; import android.widget.FrameLayout; +import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.settings.DebugSettings; +import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.utils.LocaleUtils; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import java.util.Locale; +import java.util.concurrent.TimeUnit; public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { + private static final String TAG = InputTestsBase.class.getSimpleName(); - private static final String PREF_DEBUG_MODE = "debug_mode"; + // Default value for auto-correction threshold. This is the string representation of the + // index in the resources array of auto-correction threshold settings. + private static final String DEFAULT_AUTO_CORRECTION_THRESHOLD = "1"; - // The message that sets the underline is posted with a 200 ms delay - protected static final int DELAY_TO_WAIT_FOR_UNDERLINE = 200; + // The message that sets the underline is posted with a 500 ms delay + protected static final int DELAY_TO_WAIT_FOR_UNDERLINE = 500; // The message that sets predictions is posted with a 200 ms delay protected static final int DELAY_TO_WAIT_FOR_PREDICTIONS = 200; + private final int TIMEOUT_TO_WAIT_FOR_LOADING_MAIN_DICTIONARY_IN_SECONDS = 60; protected LatinIME mLatinIME; protected Keyboard mKeyboard; protected MyEditText mEditText; protected View mInputView; protected InputConnection mInputConnection; + private boolean mPreviousDebugSetting; + private boolean mPreviousBigramPredictionSettings; + private String mPreviousAutoCorrectSetting; // A helper class to ease span tests public static class SpanGetter { @@ -135,13 +149,30 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { final boolean previousSetting = prefs.getBoolean(key, defaultValue); final SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean(key, value); - editor.commit(); + editor.apply(); + return previousSetting; + } + + protected String setStringPreference(final String key, final String value, + final String defaultValue) { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mLatinIME); + final String previousSetting = prefs.getString(key, defaultValue); + final SharedPreferences.Editor editor = prefs.edit(); + editor.putString(key, value); + editor.apply(); return previousSetting; } // returns the previous setting value protected boolean setDebugMode(final boolean value) { - return setBooleanPreference(PREF_DEBUG_MODE, value, false); + return setBooleanPreference(DebugSettings.PREF_DEBUG_MODE, value, false); + } + + protected EditorInfo enrichEditorInfo(final EditorInfo ei) { + // Some tests that inherit from us need to add some data in the EditorInfo (see + // AppWorkaroundsTests#enrichEditorInfo() for a concrete example of this). Since we + // control the EditorInfo, we supply a hook here for children to override. + return ei; } @Override @@ -154,15 +185,19 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { mEditText.setEnabled(true); setupService(); mLatinIME = getService(); - final boolean previousDebugSetting = setDebugMode(true); + mPreviousDebugSetting = setDebugMode(true); + mPreviousBigramPredictionSettings = setBooleanPreference(Settings.PREF_BIGRAM_PREDICTIONS, + true, true /* defaultValue */); + mPreviousAutoCorrectSetting = setStringPreference(Settings.PREF_AUTO_CORRECTION_THRESHOLD, + DEFAULT_AUTO_CORRECTION_THRESHOLD, DEFAULT_AUTO_CORRECTION_THRESHOLD); mLatinIME.onCreate(); - setDebugMode(previousDebugSetting); - final EditorInfo ei = new EditorInfo(); + EditorInfo ei = new EditorInfo(); final InputConnection ic = mEditText.onCreateInputConnection(ei); final LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); final ViewGroup vg = new FrameLayout(getContext()); mInputView = inflater.inflate(R.layout.input_view, vg); + ei = enrichEditorInfo(ei); mLatinIME.onCreateInputMethodInterface().startInput(ic, ei); mLatinIME.setInputView(mInputView); mLatinIME.onBindInput(); @@ -170,6 +205,22 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { mLatinIME.onStartInputView(ei, false); mInputConnection = ic; changeLanguage("en_US"); + // Run messages to avoid the messages enqueued by startInputView() and its friends + // to run on a later call and ruin things. We need to wait first because some of them + // can be posted with a delay (notably, MSG_RESUME_SUGGESTIONS) + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + } + + @Override + protected void tearDown() throws Exception { + mLatinIME.mHandler.removeAllMessages(); + setBooleanPreference(Settings.PREF_BIGRAM_PREDICTIONS, mPreviousBigramPredictionSettings, + true /* defaultValue */); + setStringPreference(Settings.PREF_AUTO_CORRECTION_THRESHOLD, mPreviousAutoCorrectSetting, + DEFAULT_AUTO_CORRECTION_THRESHOLD); + setDebugMode(mPreviousDebugSetting); + super.tearDown(); } // We need to run the messages added to the handler from LatinIME. The only way to do @@ -224,40 +275,55 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { } } - protected void waitForDictionaryToBeLoaded() { - int remainingAttempts = 300; - while (remainingAttempts > 0 && mLatinIME.isCurrentlyWaitingForMainDictionary()) { - try { - Thread.sleep(200); - } catch (InterruptedException e) { - // Don't do much - } finally { - --remainingAttempts; - } + protected void waitForDictionariesToBeLoaded() { + try { + mLatinIME.waitForLoadingDictionaries( + TIMEOUT_TO_WAIT_FOR_LOADING_MAIN_DICTIONARY_IN_SECONDS, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Log.e(TAG, "Interrupted during waiting for loading main dictionary.", e); } } protected void changeLanguage(final String locale) { changeLanguageWithoutWait(locale); - waitForDictionaryToBeLoaded(); + waitForDictionariesToBeLoaded(); } protected void changeLanguageWithoutWait(final String locale) { mEditText.mCurrentLocale = LocaleUtils.constructLocaleFromString(locale); - SubtypeSwitcher.getInstance().forceLocale(mEditText.mCurrentLocale); + // TODO: this is forcing a QWERTY keyboard for all locales, which is wrong. + // It's still better than using whatever keyboard is the current one, but we + // should actually use the default keyboard for this locale. + // TODO: Use {@link InputMethodSubtype.InputMethodSubtypeBuilder} directly or indirectly so + // that {@link InputMethodSubtype#isAsciiCapable} can return the correct value. + final String EXTRA_VALUE_FOR_TEST = + "KeyboardLayoutSet=" + SubtypeLocaleUtils.QWERTY + + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE + + "," + Constants.Subtype.ExtraValue.ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE + + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE; + final InputMethodSubtype subtype = InputMethodSubtypeCompatUtils.newInputMethodSubtype( + R.string.subtype_no_language_qwerty, + R.drawable.ic_ime_switcher_dark, + locale, + Constants.Subtype.KEYBOARD_MODE, + EXTRA_VALUE_FOR_TEST, + false /* isAuxiliary */, + false /* overridesImplicitlyEnabledSubtype */, + 0 /* id */); + SubtypeSwitcher.getInstance().forceSubtype(subtype); mLatinIME.loadKeyboard(); runMessages(); mKeyboard = mLatinIME.mKeyboardSwitcher.getKeyboard(); + mLatinIME.clearPersonalizedDictionariesForTest(); } protected void changeKeyboardLocaleAndDictLocale(final String keyboardLocale, final String dictLocale) { changeLanguage(keyboardLocale); if (!keyboardLocale.equals(dictLocale)) { - mLatinIME.replaceMainDictionaryForTest( - LocaleUtils.constructLocaleFromString(dictLocale)); + mLatinIME.replaceDictionariesForTest(LocaleUtils.constructLocaleFromString(dictLocale)); } - waitForDictionaryToBeLoaded(); + waitForDictionariesToBeLoaded(); } protected void pickSuggestionManually(final int index, final String suggestion) { diff --git a/tests/src/com/android/inputmethod/latin/LatinImeStressTests.java b/tests/src/com/android/inputmethod/latin/LatinImeStressTests.java index 5e98cdf8d..db14b8329 100644 --- a/tests/src/com/android/inputmethod/latin/LatinImeStressTests.java +++ b/tests/src/com/android/inputmethod/latin/LatinImeStressTests.java @@ -41,7 +41,7 @@ public class LatinImeStressTests extends InputTestsBase { } } } - public void testSwitchLanguagesAndInputRandamCodePoints() { + public void testSwitchLanguagesAndInputRandomCodePoints() { final String[] locales = {"en_US", "de", "el", "es", "fi", "it", "nl", "pt", "ru"}; final int switchCount = 50; final int maxWordCountToTypeInEachIteration = 20; diff --git a/tests/src/com/android/inputmethod/latin/PunctuationTests.java b/tests/src/com/android/inputmethod/latin/PunctuationTests.java index 84ff6b307..c253e6488 100644 --- a/tests/src/com/android/inputmethod/latin/PunctuationTests.java +++ b/tests/src/com/android/inputmethod/latin/PunctuationTests.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin; +import android.provider.Settings.Secure; import android.test.suitebuilder.annotation.LargeTest; import com.android.inputmethod.latin.R; @@ -40,7 +41,7 @@ public class PunctuationTests extends InputTestsBase { sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); assertTrue("type word then type space should display punctuation strip", - mLatinIME.isShowingPunctuationList()); + mLatinIME.getSuggestedWordsForTest().isPunctuationSuggestions()); pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); assertEquals("type word then type space then punctuation from strip twice", @@ -153,7 +154,9 @@ public class PunctuationTests extends InputTestsBase { final String WORD_TO_TYPE = "you'f "; final String EXPECTED_RESULT = "you'd "; type(WORD_TO_TYPE); - assertEquals("auto-correction with single quote inside", + assertEquals("auto-correction with single quote inside. ID = " + + Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID) + + " ; Suggestions = " + mLatinIME.getSuggestedWordsForTest(), EXPECTED_RESULT, mEditText.getText().toString()); } @@ -161,7 +164,37 @@ public class PunctuationTests extends InputTestsBase { final String WORD_TO_TYPE = "'tgis' "; final String EXPECTED_RESULT = "'this' "; type(WORD_TO_TYPE); - assertEquals("auto-correction with single quotes around", + assertEquals("auto-correction with single quotes around. ID = " + + Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID) + + " ; Suggestions = " + mLatinIME.getSuggestedWordsForTest(), + EXPECTED_RESULT, mEditText.getText().toString()); + } + + public void testAutoSpaceWithDoubleQuotes() { + final String STRING_TO_TYPE = "He said\"hello\"to me. I replied,\"hi\"." + + "Then, 5\"passed. He said\"bye\"and left."; + final String EXPECTED_RESULT = "He said \"hello\" to me. I replied, \"hi\". " + + "Then, 5\" passed. He said \"bye\" and left. \""; + // Split by double quote, so that we can type the double quotes individually. + for (final String partToType : STRING_TO_TYPE.split("\"")) { + // Split at word boundaries. This regexp means "anywhere that is preceded + // by a word character but not followed by a word character, OR that is not + // preceded by a word character but followed by a word character". + // We need to input word by word because auto-spaces are only active when + // manually picking or gesturing (which we can't simulate yet), but only words + // can be picked. + final String[] wordsToType = partToType.split("(?<=\\w)(?!\\w)|(?<!\\w)(?=\\w)"); + for (final String wordToType : wordsToType) { + type(wordToType); + if (wordToType.matches("^\\w+$")) { + // Only pick selection if that was a word, because if that was not a word, + // then we don't have a composition. + pickSuggestionManually(0, wordToType); + } + } + type("\""); + } + assertEquals("auto-space with double quotes", EXPECTED_RESULT, mEditText.getText().toString()); } } diff --git a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java index c0dd9933c..7f0743543 100644 --- a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java +++ b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java @@ -16,15 +16,13 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.latin.utils.TextRange; - +import android.content.res.Resources; import android.inputmethodservice.InputMethodService; import android.os.Parcel; import android.test.AndroidTestCase; import android.test.MoreAsserts; import android.test.suitebuilder.annotation.SmallTest; import android.text.SpannableString; -import android.text.Spanned; import android.text.TextUtils; import android.text.style.SuggestionSpan; import android.view.inputmethod.ExtractedText; @@ -32,6 +30,11 @@ import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnectionWrapper; +import com.android.inputmethod.latin.settings.SpacingAndPunctuations; +import com.android.inputmethod.latin.utils.RunInLocale; +import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.utils.TextRange; + import java.util.Locale; @SmallTest @@ -39,11 +42,19 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { // The following is meant to be a reasonable default for // the "word_separators" resource. - private static final String sSeparators = ".,:;!?-"; + private SpacingAndPunctuations mSpacingAndPunctuations; @Override protected void setUp() throws Exception { super.setUp(); + final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() { + @Override + protected SpacingAndPunctuations job(final Resources res) { + return new SpacingAndPunctuations(res); + } + }; + final Resources res = getContext().getResources(); + mSpacingAndPunctuations = job.runInLocale(res, Locale.ENGLISH); } private class MockConnection extends InputConnectionWrapper { @@ -137,9 +148,12 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { */ public void testGetPreviousWord() { // If one of the following cases breaks, the bigram suggestions won't work. - assertEquals(RichInputConnection.getNthPreviousWord("abc def", sSeparators, 2), "abc"); - assertNull(RichInputConnection.getNthPreviousWord("abc", sSeparators, 2)); - assertNull(RichInputConnection.getNthPreviousWord("abc. def", sSeparators, 2)); + assertEquals(RichInputConnection.getNthPreviousWord( + "abc def", mSpacingAndPunctuations, 2), "abc"); + assertNull(RichInputConnection.getNthPreviousWord( + "abc", mSpacingAndPunctuations, 2)); + assertNull(RichInputConnection.getNthPreviousWord( + "abc. def", mSpacingAndPunctuations, 2)); // The following tests reflect the current behavior of the function // RichInputConnection#getNthPreviousWord. @@ -148,20 +162,34 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { // this function if needed - especially since it does not seem very // logical. These tests are just there to catch any unintentional // changes in the behavior of the RichInputConnection#getPreviousWord method. - assertEquals(RichInputConnection.getNthPreviousWord("abc def ", sSeparators, 2), "abc"); - assertEquals(RichInputConnection.getNthPreviousWord("abc def.", sSeparators, 2), "abc"); - assertEquals(RichInputConnection.getNthPreviousWord("abc def .", sSeparators, 2), "def"); - assertNull(RichInputConnection.getNthPreviousWord("abc ", sSeparators, 2)); - - assertEquals(RichInputConnection.getNthPreviousWord("abc def", sSeparators, 1), "def"); - assertEquals(RichInputConnection.getNthPreviousWord("abc def ", sSeparators, 1), "def"); - assertNull(RichInputConnection.getNthPreviousWord("abc def.", sSeparators, 1)); - assertNull(RichInputConnection.getNthPreviousWord("abc def .", sSeparators, 1)); + assertEquals(RichInputConnection.getNthPreviousWord( + "abc def ", mSpacingAndPunctuations, 2), "abc"); + assertEquals(RichInputConnection.getNthPreviousWord( + "abc def.", mSpacingAndPunctuations, 2), "abc"); + assertEquals(RichInputConnection.getNthPreviousWord( + "abc def .", mSpacingAndPunctuations, 2), "def"); + assertNull(RichInputConnection.getNthPreviousWord( + "abc ", mSpacingAndPunctuations, 2)); + + assertEquals(RichInputConnection.getNthPreviousWord( + "abc def", mSpacingAndPunctuations, 1), "def"); + assertEquals(RichInputConnection.getNthPreviousWord( + "abc def ", mSpacingAndPunctuations, 1), "def"); + assertNull(RichInputConnection.getNthPreviousWord( + "abc def.", mSpacingAndPunctuations, 1)); + assertNull(RichInputConnection.getNthPreviousWord( + "abc def .", mSpacingAndPunctuations, 1)); } /** * Test logic in getting the word range at the cursor. */ + private static final int[] SPACE = { Constants.CODE_SPACE }; + static final int[] TAB = { Constants.CODE_TAB }; + private static final int[] SPACE_TAB = StringUtils.toSortedCodePointArray(" \t"); + // A character that needs surrogate pair to represent its code point (U+2008A). + private static final String SUPPLEMENTARY_CHAR = "\uD840\uDC8A"; + public void testGetWordRangeAtCursor() { ExtractedText et = new ExtractedText(); final MockInputMethodService mockInputMethodService = new MockInputMethodService(); @@ -173,48 +201,47 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { ic.beginBatchEdit(); // basic case - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); assertTrue(TextUtils.equals("word", r.mWord)); // more than one word - r = ic.getWordRangeAtCursor(" ", 1); + r = ic.getWordRangeAtCursor(SPACE, 1); assertTrue(TextUtils.equals("word word", r.mWord)); ic.endBatchEdit(); // tab character instead of space mockInputMethodService.setInputConnection(new MockConnection("one\tword\two", "rd", et)); ic.beginBatchEdit(); - r = ic.getWordRangeAtCursor("\t", 1); + r = ic.getWordRangeAtCursor(TAB, 1); ic.endBatchEdit(); assertTrue(TextUtils.equals("word\tword", r.mWord)); // only one word doesn't go too far mockInputMethodService.setInputConnection(new MockConnection("one\tword\two", "rd", et)); ic.beginBatchEdit(); - r = ic.getWordRangeAtCursor("\t", 1); + r = ic.getWordRangeAtCursor(TAB, 1); ic.endBatchEdit(); assertTrue(TextUtils.equals("word\tword", r.mWord)); // tab or space mockInputMethodService.setInputConnection(new MockConnection("one word\two", "rd", et)); ic.beginBatchEdit(); - r = ic.getWordRangeAtCursor(" \t", 1); + r = ic.getWordRangeAtCursor(SPACE_TAB, 1); ic.endBatchEdit(); assertTrue(TextUtils.equals("word\tword", r.mWord)); // tab or space multiword mockInputMethodService.setInputConnection(new MockConnection("one word\two", "rd", et)); ic.beginBatchEdit(); - r = ic.getWordRangeAtCursor(" \t", 2); + r = ic.getWordRangeAtCursor(SPACE_TAB, 2); ic.endBatchEdit(); assertTrue(TextUtils.equals("one word\tword", r.mWord)); // splitting on supplementary character - final String supplementaryChar = "\uD840\uDC8A"; mockInputMethodService.setInputConnection( - new MockConnection("one word" + supplementaryChar + "wo", "rd", et)); + new MockConnection("one word" + SUPPLEMENTARY_CHAR + "wo", "rd", et)); ic.beginBatchEdit(); - r = ic.getWordRangeAtCursor(supplementaryChar, 0); + r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR), 0); ic.endBatchEdit(); assertTrue(TextUtils.equals("word", r.mWord)); } @@ -244,7 +271,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { TextRange r; SuggestionSpan[] suggestions; - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); suggestions = r.getSuggestionSpansAtWord(); assertEquals(suggestions.length, 1); MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); @@ -256,7 +283,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 10 /* start */, 16 /* end */, 0 /* flags */); mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); suggestions = r.getSuggestionSpansAtWord(); assertEquals(suggestions.length, 2); MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); @@ -269,7 +296,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 5 /* start */, 16 /* end */, 0 /* flags */); mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); suggestions = r.getSuggestionSpansAtWord(); assertEquals(suggestions.length, 1); MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); @@ -281,7 +308,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 10 /* start */, 20 /* end */, 0 /* flags */); mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); suggestions = r.getSuggestionSpansAtWord(); assertEquals(suggestions.length, 1); MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); @@ -293,7 +320,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 5 /* start */, 20 /* end */, 0 /* flags */); mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); suggestions = r.getSuggestionSpansAtWord(); assertEquals(suggestions.length, 1); MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); @@ -305,7 +332,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 5 /* start */, 20 /* end */, 0 /* flags */); mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); suggestions = r.getSuggestionSpansAtWord(); assertEquals(suggestions.length, 0); } diff --git a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java index 375352067..8fe473523 100644 --- a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java +++ b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java @@ -46,10 +46,9 @@ public class SuggestedWordsTests extends AndroidTestCase { } final SuggestedWords words = new SuggestedWords( - list, + list, null /* rawSuggestions */, false /* typedWordValid */, false /* willAutoCorrect */, - false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, false /* isPrediction*/); assertEquals(NUMBER_OF_ADDED_SUGGESTIONS + 1, words.size()); diff --git a/tests/src/com/android/inputmethod/latin/WordComposerTests.java b/tests/src/com/android/inputmethod/latin/WordComposerTests.java index 1434c6b63..d68bb5c54 100644 --- a/tests/src/com/android/inputmethod/latin/WordComposerTests.java +++ b/tests/src/com/android/inputmethod/latin/WordComposerTests.java @@ -19,6 +19,9 @@ package com.android.inputmethod.latin; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; +import com.android.inputmethod.latin.utils.CoordinateUtils; +import com.android.inputmethod.latin.utils.StringUtils; + /** * Unit tests for WordComposer. */ @@ -26,10 +29,20 @@ import android.test.suitebuilder.annotation.SmallTest; public class WordComposerTests extends AndroidTestCase { public void testMoveCursor() { final WordComposer wc = new WordComposer(); + // BMP is the Basic Multilingual Plane, as defined by Unicode. This includes + // most characters for most scripts, including all Roman alphabet languages, + // CJK, Arabic, Hebrew. Notable exceptions include some emoji and some + // very rare Chinese ideograms. BMP characters can be encoded on 2 bytes + // in UTF-16, whereas those outside the BMP need 4 bytes. + // http://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane final String STR_WITHIN_BMP = "abcdef"; - wc.setComposingWord(STR_WITHIN_BMP, null); - assertEquals(wc.size(), - STR_WITHIN_BMP.codePointCount(0, STR_WITHIN_BMP.length())); + final int[] CODEPOINTS_WITHIN_BMP = StringUtils.toCodePointArray(STR_WITHIN_BMP); + final int[] COORDINATES_WITHIN_BMP = + CoordinateUtils.newCoordinateArray(CODEPOINTS_WITHIN_BMP.length, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + final String PREVWORD = "prevword"; + wc.setComposingWord(CODEPOINTS_WITHIN_BMP, COORDINATES_WITHIN_BMP, PREVWORD); + assertEquals(wc.size(), STR_WITHIN_BMP.codePointCount(0, STR_WITHIN_BMP.length())); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); wc.setCursorPositionWithinWord(2); assertTrue(wc.isCursorFrontOrMiddleOfComposingWord()); @@ -43,15 +56,26 @@ public class WordComposerTests extends AndroidTestCase { // Move the cursor to after the 'f' assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1)); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); + // Check the previous word is still there + assertEquals(PREVWORD, wc.getPreviousWordForSuggestion()); // Move the cursor past the end of the word assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(1)); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(15)); + // Do what LatinIME does when the cursor is moved outside of the word, + // and check the behavior is correct. + wc.reset(); + assertNull(wc.getPreviousWordForSuggestion()); // \uD861\uDED7 is 𨛗, a character outside the BMP final String STR_WITH_SUPPLEMENTARY_CHAR = "abcde\uD861\uDED7fgh"; - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); - assertEquals(wc.size(), STR_WITH_SUPPLEMENTARY_CHAR.codePointCount(0, - STR_WITH_SUPPLEMENTARY_CHAR.length())); + final int[] CODEPOINTS_WITH_SUPPLEMENTARY_CHAR = + StringUtils.toCodePointArray(STR_WITH_SUPPLEMENTARY_CHAR); + final int[] COORDINATES_WITH_SUPPLEMENTARY_CHAR = + CoordinateUtils.newCoordinateArray(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */); + assertEquals(wc.size(), CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); wc.setCursorPositionWithinWord(3); assertTrue(wc.isCursorFrontOrMiddleOfComposingWord()); @@ -59,34 +83,48 @@ public class WordComposerTests extends AndroidTestCase { assertTrue(wc.isCursorFrontOrMiddleOfComposingWord()); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1)); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); + assertNull(wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + STR_WITHIN_BMP); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7)); + assertEquals(STR_WITHIN_BMP, wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + STR_WITH_SUPPLEMENTARY_CHAR); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7)); + assertEquals(STR_WITH_SUPPLEMENTARY_CHAR, wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + STR_WITHIN_BMP); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-3)); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-1)); + assertEquals(STR_WITHIN_BMP, wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */); wc.setCursorPositionWithinWord(3); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-9)); + assertNull(wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + STR_WITH_SUPPLEMENTARY_CHAR); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-10)); + assertEquals(STR_WITH_SUPPLEMENTARY_CHAR, wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-11)); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0)); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */); wc.setCursorPositionWithinWord(2); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0)); } diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java index 32c07e106..e21e340c2 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java @@ -17,30 +17,30 @@ package com.android.inputmethod.latin.makedict; import android.test.AndroidTestCase; -import android.test.MoreAsserts; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; +import android.util.Pair; import android.util.SparseArray; +import com.android.inputmethod.latin.BinaryDictionary; import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding; import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; +import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.utils.ByteArrayDictBuffer; import com.android.inputmethod.latin.utils.CollectionUtils; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map.Entry; import java.util.Random; import java.util.Set; @@ -52,18 +52,18 @@ import java.util.TreeMap; @LargeTest public class BinaryDictDecoderEncoderTests extends AndroidTestCase { private static final String TAG = BinaryDictDecoderEncoderTests.class.getSimpleName(); - private static final int DEFAULT_MAX_UNIGRAMS = 100; + private static final int DEFAULT_MAX_UNIGRAMS = 300; private static final int DEFAULT_CODE_POINT_SET_SIZE = 50; + private static final int LARGE_CODE_POINT_SET_SIZE = 300; private static final int UNIGRAM_FREQ = 10; private static final int BIGRAM_FREQ = 50; private static final int TOLERANCE_OF_BIGRAM_FREQ = 5; private static final int NUM_OF_NODES_HAVING_SHORTCUTS = 50; private static final int NUM_OF_SHORTCUTS = 5; - private static final int USE_BYTE_ARRAY = 1; - private static final int USE_BYTE_BUFFER = 2; - private static final ArrayList<String> sWords = CollectionUtils.newArrayList(); + private static final ArrayList<String> sWordsWithVariousCodePoints = + CollectionUtils.newArrayList(); private static final SparseArray<List<Integer>> sEmptyBigrams = CollectionUtils.newSparseArray(); private static final SparseArray<List<Integer>> sStarBigrams = CollectionUtils.newSparseArray(); @@ -71,33 +71,18 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { CollectionUtils.newSparseArray(); private static final HashMap<String, List<String>> sShortcuts = CollectionUtils.newHashMap(); - private static final FormatSpec.FormatOptions VERSION2 = new FormatSpec.FormatOptions(2); - private static final FormatSpec.FormatOptions VERSION3_WITHOUT_DYNAMIC_UPDATE = - new FormatSpec.FormatOptions(3, false /* supportsDynamicUpdate */); - private static final FormatSpec.FormatOptions VERSION3_WITH_DYNAMIC_UPDATE = - new FormatSpec.FormatOptions(3, true /* supportsDynamicUpdate */); - private static final FormatSpec.FormatOptions VERSION4_WITHOUT_DYNAMIC_UPDATE = - new FormatSpec.FormatOptions(4, false /* supportsDynamicUpdate */); - private static final FormatSpec.FormatOptions VERSION4_WITH_DYNAMIC_UPDATE = - new FormatSpec.FormatOptions(4, true /* supportsDynamicUpdate */); - private static final FormatSpec.FormatOptions VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP = - new FormatSpec.FormatOptions(4, true /* supportsDynamicUpdate */, - true /* hasTimestamp */); - - private static final String TEST_DICT_FILE_EXTENSION = ".testDict"; - public BinaryDictDecoderEncoderTests() { this(System.currentTimeMillis(), DEFAULT_MAX_UNIGRAMS); } public BinaryDictDecoderEncoderTests(final long seed, final int maxUnigrams) { super(); + BinaryDictionary.setCurrentTimeForTest(0); Log.e(TAG, "Testing dictionary: seed is " + seed); final Random random = new Random(seed); sWords.clear(); - final int[] codePointSet = CodePointUtils.generateCodePointSet(DEFAULT_CODE_POINT_SET_SIZE, - random); - generateWords(maxUnigrams, random, codePointSet); + sWordsWithVariousCodePoints.clear(); + generateWords(maxUnigrams, random); for (int i = 0; i < sWords.size(); ++i) { sChainBigrams.put(i, new ArrayList<Integer>()); @@ -124,23 +109,35 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { } } - private DictEncoder getDictEncoder(final File file, final FormatOptions formatOptions) { - if (formatOptions.mVersion == FormatSpec.VERSION4) { - return new Ver4DictEncoder(getContext().getCacheDir()); - } else if (formatOptions.mVersion == 3 || formatOptions.mVersion == 2) { - return new Ver3DictEncoder(file); - } else { - throw new RuntimeException("The format option has a wrong version : " - + formatOptions.mVersion); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + BinaryDictionary.setCurrentTimeForTest(0); + } + + @Override + protected void tearDown() throws Exception { + // Quit test mode. + BinaryDictionary.setCurrentTimeForTest(-1); + super.tearDown(); } - private void generateWords(final int number, final Random random, final int[] codePointSet) { + private void generateWords(final int number, final Random random) { + final int[] codePointSet = CodePointUtils.generateCodePointSet(DEFAULT_CODE_POINT_SET_SIZE, + random); final Set<String> wordSet = CollectionUtils.newHashSet(); while (wordSet.size() < number) { wordSet.add(CodePointUtils.generateWord(random, codePointSet)); } sWords.addAll(wordSet); + + final int[] largeCodePointSet = CodePointUtils.generateCodePointSet( + LARGE_CODE_POINT_SET_SIZE, random); + wordSet.clear(); + while (wordSet.size() < number) { + wordSet.add(CodePointUtils.generateWord(random, largeCodePointSet)); + } + sWordsWithVariousCodePoints.addAll(wordSet); } /** @@ -156,8 +153,8 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { shortcuts.add(new WeightedString(shortcut, UNIGRAM_FREQ)); } } - dict.add(word, UNIGRAM_FREQ, (shortcutMap == null) ? null : shortcuts, - false /* isNotAWord */); + dict.add(word, new ProbabilityInfo(UNIGRAM_FREQ), + (shortcutMap == null) ? null : shortcuts, false /* isNotAWord */); } } @@ -167,7 +164,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { for (int i = 0; i < bigrams.size(); ++i) { final int w1 = bigrams.keyAt(i); for (int w2 : bigrams.valueAt(i)) { - dict.setBigram(words.get(w1), words.get(w2), BIGRAM_FREQ); + dict.setBigram(words.get(w1), words.get(w2), new ProbabilityInfo(BIGRAM_FREQ)); } } } @@ -186,7 +183,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { long now = -1, diff = -1; try { - final DictEncoder dictEncoder = getDictEncoder(file, formatOptions); + final DictEncoder dictEncoder = BinaryDictUtils.getDictEncoder(file, formatOptions); now = System.currentTimeMillis(); // If you need to dump the dict to a textual file, uncomment the line below and the @@ -241,56 +238,22 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { private String outputOptions(final int bufferType, final FormatSpec.FormatOptions formatOptions) { String result = " : buffer type = " - + ((bufferType == USE_BYTE_BUFFER) ? "byte buffer" : "byte array"); - result += " : version = " + formatOptions.mVersion; - return result + ", supportsDynamicUpdate = " + formatOptions.mSupportsDynamicUpdate; - } - - private DictionaryOptions getDictionaryOptions(final String id, final String version) { - final DictionaryOptions options = new DictionaryOptions(new HashMap<String, String>(), - false, false); - options.mAttributes.put("version", version); - options.mAttributes.put("dictionary", id); - return options; + + ((bufferType == BinaryDictUtils.USE_BYTE_BUFFER) ? "byte buffer" : "byte array"); + return result + " : version = " + formatOptions.mVersion; } - private File setUpDictionaryFile(final String name, final String version) { - File file = null; - try { - file = new File(getContext().getCacheDir(), name + "." + version - + TEST_DICT_FILE_EXTENSION); - file.createNewFile(); - } catch (IOException e) { - // do nothing - } - assertTrue("Failed to create the dictionary file.", file.exists()); - return file; - } - - private DictDecoder getDictDecoder(final File file, final int bufferType, - final FormatOptions formatOptions, final DictionaryOptions dictOptions) { - if (formatOptions.mVersion == FormatSpec.VERSION4) { - final FileHeader header = new FileHeader(0, dictOptions, formatOptions); - return FormatSpec.getDictDecoder(new File(getContext().getCacheDir(), - header.getId() + "." + header.getVersion()), bufferType); - } else { - return FormatSpec.getDictDecoder(file, bufferType); - } - } // Tests for readDictionaryBinary and writeDictionaryBinary private long timeReadingAndCheckDict(final File file, final List<String> words, final SparseArray<List<Integer>> bigrams, - final HashMap<String, List<String>> shortcutMap, final int bufferType, - final FormatOptions formatOptions, final DictionaryOptions dictOptions) { + final HashMap<String, List<String>> shortcutMap, final int bufferType) { long now, diff = -1; FusionDictionary dict = null; try { - final DictDecoder dictDecoder = getDictDecoder(file, bufferType, formatOptions, - dictOptions); + final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file, bufferType); now = System.currentTimeMillis(); - dict = dictDecoder.readDictionaryBinary(null, false /* deleteDictIfBroken */); + dict = dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */); diff = System.currentTimeMillis() - now; } catch (IOException e) { Log.e(TAG, "IOException while reading dictionary", e); @@ -310,17 +273,17 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final String dictName = "runReadAndWrite"; final String dictVersion = Long.toString(System.currentTimeMillis()); - final File file = setUpDictionaryFile(dictName, dictVersion); + final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions, + getContext().getCacheDir()); final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - getDictionaryOptions(dictName, dictVersion)); + BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions)); addUnigrams(words.size(), dict, words, shortcuts); addBigrams(dict, words, bigrams); checkDictionary(dict, words, bigrams, shortcuts); final long write = timeWritingDictToFile(file, dict, formatOptions); - final long read = timeReadingAndCheckDict(file, words, bigrams, shortcuts, bufferType, - formatOptions, dict.mOptions); + final long read = timeReadingAndCheckDict(file, words, bigrams, shortcuts, bufferType); return "PROF: read=" + read + "ms, write=" + write + "ms :" + message + " : " + outputOptions(bufferType, formatOptions); @@ -340,6 +303,9 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { "chain with shortcuts")); results.add(runReadAndWrite(sWords, sStarBigrams, sShortcuts, bufferType, formatOptions, "star with shortcuts")); + results.add(runReadAndWrite(sWordsWithVariousCodePoints, sEmptyBigrams, + null /* shortcuts */, bufferType, formatOptions, + "unigram with various code points")); } // Unit test for CharEncoding.readString and CharEncoding.writeString. @@ -349,8 +315,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final byte[] buffer = new byte[50 * 3]; final DictBuffer dictBuffer = new ByteArrayDictBuffer(buffer); for (final String word : sWords) { - Log.d("testReadAndWriteString", "write : " + word); - Arrays.fill(buffer, (byte)0); + Arrays.fill(buffer, (byte) 0); CharEncoding.writeString(buffer, 0, word); dictBuffer.position(0); final String str = CharEncoding.readString(dictBuffer); @@ -361,13 +326,12 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { public void testReadAndWriteWithByteBuffer() { final List<String> results = CollectionUtils.newArrayList(); - runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION2); - runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION3_WITHOUT_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION3_WITH_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION4_WITHOUT_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); - + runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_BUFFER, + BinaryDictUtils.VERSION2_OPTIONS); + runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_BUFFER, + BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); + runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_BUFFER, + BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); for (final String result : results) { Log.d(TAG, result); } @@ -376,12 +340,12 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { public void testReadAndWriteWithByteArray() { final List<String> results = CollectionUtils.newArrayList(); - runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION2); - runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION3_WITHOUT_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION3_WITH_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION4_WITHOUT_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_ARRAY, + BinaryDictUtils.VERSION2_OPTIONS); + runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_ARRAY, + BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); + runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_ARRAY, + BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); for (final String result : results) { Log.d(TAG, result); @@ -394,53 +358,54 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final SparseArray<List<Integer>> expectedBigrams, final TreeMap<Integer, String> resultWords, final TreeMap<Integer, Integer> resultFrequencies, - final TreeMap<Integer, ArrayList<PendingAttribute>> resultBigrams) { + final TreeMap<Integer, ArrayList<PendingAttribute>> resultBigrams, + final boolean checkProbability) { // check unigrams final Set<String> actualWordsSet = new HashSet<String>(resultWords.values()); final Set<String> expectedWordsSet = new HashSet<String>(expectedWords); assertEquals(actualWordsSet, expectedWordsSet); - - for (int freq : resultFrequencies.values()) { - assertEquals(freq, UNIGRAM_FREQ); + if (checkProbability) { + for (int freq : resultFrequencies.values()) { + assertEquals(freq, UNIGRAM_FREQ); + } } // check bigrams - final HashMap<String, List<String>> expBigrams = new HashMap<String, List<String>>(); + final HashMap<String, Set<String>> expBigrams = new HashMap<String, Set<String>>(); for (int i = 0; i < expectedBigrams.size(); ++i) { final String word1 = expectedWords.get(expectedBigrams.keyAt(i)); for (int w2 : expectedBigrams.valueAt(i)) { if (expBigrams.get(word1) == null) { - expBigrams.put(word1, new ArrayList<String>()); + expBigrams.put(word1, new HashSet<String>()); } expBigrams.get(word1).add(expectedWords.get(w2)); } } - final HashMap<String, List<String>> actBigrams = new HashMap<String, List<String>>(); + final HashMap<String, Set<String>> actBigrams = new HashMap<String, Set<String>>(); for (Entry<Integer, ArrayList<PendingAttribute>> entry : resultBigrams.entrySet()) { final String word1 = resultWords.get(entry.getKey()); final int unigramFreq = resultFrequencies.get(entry.getKey()); for (PendingAttribute attr : entry.getValue()) { final String word2 = resultWords.get(attr.mAddress); if (actBigrams.get(word1) == null) { - actBigrams.put(word1, new ArrayList<String>()); + actBigrams.put(word1, new HashSet<String>()); } actBigrams.get(word1).add(word2); - final int bigramFreq = BinaryDictIOUtils.reconstructBigramFrequency( - unigramFreq, attr.mFrequency); - assertTrue(Math.abs(bigramFreq - BIGRAM_FREQ) < TOLERANCE_OF_BIGRAM_FREQ); + if (checkProbability) { + final int bigramFreq = BinaryDictIOUtils.reconstructBigramFrequency( + unigramFreq, attr.mFrequency); + assertTrue(Math.abs(bigramFreq - BIGRAM_FREQ) < TOLERANCE_OF_BIGRAM_FREQ); + } } } - assertEquals(actBigrams, expBigrams); } private long timeAndCheckReadUnigramsAndBigramsBinary(final File file, final List<String> words, final SparseArray<List<Integer>> bigrams, final int bufferType, - final FormatOptions formatOptions, final DictionaryOptions dictOptions) { - FileInputStream inStream = null; - + final boolean checkProbability) { final TreeMap<Integer, String> resultWords = CollectionUtils.newTreeMap(); final TreeMap<Integer, ArrayList<PendingAttribute>> resultBigrams = CollectionUtils.newTreeMap(); @@ -448,8 +413,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { long now = -1, diff = -1; try { - final DictDecoder dictDecoder = getDictDecoder(file, bufferType, formatOptions, - dictOptions); + final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file, bufferType); now = System.currentTimeMillis(); dictDecoder.readUnigramsAndBigramsBinary(resultWords, resultFreqs, resultBigrams); diff = System.currentTimeMillis() - now; @@ -457,17 +421,9 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { Log.e(TAG, "IOException", e); } catch (UnsupportedFormatException e) { Log.e(TAG, "UnsupportedFormatException", e); - } finally { - if (inStream != null) { - try { - inStream.close(); - } catch (IOException e) { - // do nothing - } - } } - checkWordMap(words, bigrams, resultWords, resultFreqs, resultBigrams); + checkWordMap(words, bigrams, resultWords, resultFreqs, resultBigrams, checkProbability); return diff; } @@ -476,20 +432,24 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final FormatSpec.FormatOptions formatOptions, final String message) { final String dictName = "runReadUnigrams"; final String dictVersion = Long.toString(System.currentTimeMillis()); - final File file = setUpDictionaryFile(dictName, dictVersion); + final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions, + getContext().getCacheDir()); // making the dictionary from lists of words. final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - getDictionaryOptions(dictName, dictVersion)); + BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions)); addUnigrams(words.size(), dict, words, null /* shortcutMap */); addBigrams(dict, words, bigrams); timeWritingDictToFile(file, dict, formatOptions); + // Caveat: Currently, the Java code to read a v4 dictionary doesn't calculate the + // probability when there's a timestamp for the entry. + // TODO: Abandon the Java code, and implement the v4 dictionary reading code in native. long wordMap = timeAndCheckReadUnigramsAndBigramsBinary(file, words, bigrams, bufferType, - formatOptions, dict.mOptions); + !formatOptions.mHasTimestamp /* checkProbability */); long fullReading = timeReadingAndCheckDict(file, words, bigrams, null /* shortcutMap */, - bufferType, formatOptions, dict.mOptions); + bufferType); return "readDictionaryBinary=" + fullReading + ", readUnigramsAndBigramsBinary=" + wordMap + " : " + message + " : " + outputOptions(bufferType, formatOptions); @@ -508,13 +468,8 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { public void testReadUnigramsAndBigramsBinaryWithByteBuffer() { final ArrayList<String> results = CollectionUtils.newArrayList(); - runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION2); - runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION3_WITHOUT_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION3_WITH_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION4_WITHOUT_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, - VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_BUFFER, + BinaryDictUtils.VERSION2_OPTIONS); for (final String result : results) { Log.d(TAG, result); @@ -524,13 +479,8 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { public void testReadUnigramsAndBigramsBinaryWithByteArray() { final ArrayList<String> results = CollectionUtils.newArrayList(); - runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION2); - runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION3_WITHOUT_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION3_WITH_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION4_WITHOUT_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, - VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_ARRAY, + BinaryDictUtils.VERSION2_OPTIONS); for (final String result : results) { Log.d(TAG, result); @@ -541,7 +491,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { private String getWordFromBinary(final DictDecoder dictDecoder, final int address) { if (dictDecoder.getPosition() != 0) dictDecoder.setPosition(0); - FileHeader fileHeader = null; + DictionaryHeader fileHeader = null; try { fileHeader = dictDecoder.readHeader(); } catch (IOException e) { @@ -550,8 +500,8 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { return null; } if (fileHeader == null) return null; - return BinaryDictDecoderUtils.getWordAtPosition(dictDecoder, fileHeader.mHeaderSize, - address, fileHeader.mFormatOptions).mWord; + return BinaryDictDecoderUtils.getWordAtPosition(dictDecoder, fileHeader.mBodyOffset, + address).mWord; } private long checkGetTerminalPosition(final DictDecoder dictDecoder, final String word, @@ -578,20 +528,21 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final FormatOptions formatOptions, final String message) { final String dictName = "testGetTerminalPosition"; final String dictVersion = Long.toString(System.currentTimeMillis()); - final File file = setUpDictionaryFile(dictName, dictVersion); + final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions, + getContext().getCacheDir()); final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - getDictionaryOptions(dictName, dictVersion)); + BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions)); addUnigrams(sWords.size(), dict, sWords, null /* shortcutMap */); addBigrams(dict, words, bigrams); timeWritingDictToFile(file, dict, formatOptions); - final DictDecoder dictDecoder = getDictDecoder(file, DictDecoder.USE_BYTEARRAY, - formatOptions, dict.mOptions); + final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file, DictDecoder.USE_BYTEARRAY); try { dictDecoder.openDictBuffer(); } catch (IOException e) { - // ignore + Log.e(TAG, "IOException while opening the buffer", e); + } catch (UnsupportedFormatException e) { Log.e(TAG, "IOException while opening the buffer", e); } assertTrue("Can't get the buffer", dictDecoder.isDictBufferOpen()); @@ -638,65 +589,110 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { public void testGetTerminalPosition() { final ArrayList<String> results = CollectionUtils.newArrayList(); - runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION2); - runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION3_WITHOUT_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION3_WITH_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION4_WITHOUT_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); - - runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION2); - runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION3_WITHOUT_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION3_WITH_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION4_WITHOUT_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_ARRAY, + BinaryDictUtils.VERSION2_OPTIONS); + runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_BUFFER, + BinaryDictUtils.VERSION2_OPTIONS); for (final String result : results) { Log.d(TAG, result); } } - private void runTestDeleteWord(final FormatOptions formatOptions) { - final String dictName = "testDeleteWord"; + public void testVer2DictGetWordProperty() { + final FormatOptions formatOptions = BinaryDictUtils.VERSION2_OPTIONS; + final ArrayList<String> words = sWords; + final HashMap<String, List<String>> shortcuts = sShortcuts; + final String dictName = "testGetWordProperty"; final String dictVersion = Long.toString(System.currentTimeMillis()); - final File file = setUpDictionaryFile(dictName, dictVersion); - final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions( - new HashMap<String, String>(), false, false)); - addUnigrams(sWords.size(), dict, sWords, null /* shortcutMap */); + BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions)); + addUnigrams(words.size(), dict, words, shortcuts); + addBigrams(dict, words, sEmptyBigrams); + final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions, + getContext().getCacheDir()); + file.delete(); timeWritingDictToFile(file, dict, formatOptions); - - final DictUpdater dictUpdater; - if (formatOptions.mVersion == 3) { - dictUpdater = new Ver3DictUpdater(file, DictDecoder.USE_WRITABLE_BYTEBUFFER); - } else if (formatOptions.mVersion == 4) { - dictUpdater = new Ver4DictUpdater(file, DictDecoder.USE_WRITABLE_BYTEBUFFER); - } else { - throw new RuntimeException("DictUpdater for version " + formatOptions.mVersion - + " doesn't exist."); - } - - try { - MoreAsserts.assertNotEqual(FormatSpec.NOT_VALID_WORD, - dictUpdater.getTerminalPosition(sWords.get(0))); - dictUpdater.deleteWord(sWords.get(0)); - assertEquals(FormatSpec.NOT_VALID_WORD, - dictUpdater.getTerminalPosition(sWords.get(0))); - - MoreAsserts.assertNotEqual(FormatSpec.NOT_VALID_WORD, - dictUpdater.getTerminalPosition(sWords.get(5))); - dictUpdater.deleteWord(sWords.get(5)); - assertEquals(FormatSpec.NOT_VALID_WORD, - dictUpdater.getTerminalPosition(sWords.get(5))); - } catch (IOException e) { - } catch (UnsupportedFormatException e) { + final BinaryDictionary binaryDictionary = new BinaryDictionary(file.getAbsolutePath(), + 0 /* offset */, file.length(), true /* useFullEditDistance */, + Locale.ENGLISH, dictName, false /* isUpdatable */); + for (final String word : words) { + final WordProperty wordProperty = binaryDictionary.getWordProperty(word); + assertEquals(word, wordProperty.mWord); + assertEquals(UNIGRAM_FREQ, wordProperty.getProbability()); + if (shortcuts.containsKey(word)) { + assertEquals(shortcuts.get(word).size(), wordProperty.mShortcutTargets.size()); + final List<String> shortcutList = shortcuts.get(word); + assertTrue(wordProperty.mHasShortcuts); + for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + assertTrue(shortcutList.contains(shortcutTarget.mWord)); + assertEquals(UNIGRAM_FREQ, shortcutTarget.getProbability()); + shortcutList.remove(shortcutTarget.mWord); + } + assertTrue(shortcutList.isEmpty()); + } } } - public void testDeleteWord() { - runTestDeleteWord(VERSION3_WITH_DYNAMIC_UPDATE); - runTestDeleteWord(VERSION4_WITH_DYNAMIC_UPDATE); + public void testVer2DictIteration() { + final FormatOptions formatOptions = BinaryDictUtils.VERSION2_OPTIONS; + final ArrayList<String> words = sWords; + final HashMap<String, List<String>> shortcuts = sShortcuts; + final SparseArray<List<Integer>> bigrams = sEmptyBigrams; + final String dictName = "testGetWordProperty"; + final String dictVersion = Long.toString(System.currentTimeMillis()); + final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), + BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions)); + addUnigrams(words.size(), dict, words, shortcuts); + addBigrams(dict, words, bigrams); + final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions, + getContext().getCacheDir()); + timeWritingDictToFile(file, dict, formatOptions); + Log.d(TAG, file.getAbsolutePath()); + final BinaryDictionary binaryDictionary = new BinaryDictionary(file.getAbsolutePath(), + 0 /* offset */, file.length(), true /* useFullEditDistance */, + Locale.ENGLISH, dictName, false /* isUpdatable */); + + final HashSet<String> wordSet = new HashSet<String>(words); + final HashSet<Pair<String, String>> bigramSet = new HashSet<Pair<String,String>>(); + + for (int i = 0; i < words.size(); i++) { + final List<Integer> bigramList = bigrams.get(i); + if (bigramList != null) { + for (final Integer word1Index : bigramList) { + final String word1 = words.get(word1Index); + bigramSet.add(new Pair<String, String>(words.get(i), word1)); + } + } + } + int token = 0; + do { + final BinaryDictionary.GetNextWordPropertyResult result = + binaryDictionary.getNextWordProperty(token); + final WordProperty wordProperty = result.mWordProperty; + final String word0 = wordProperty.mWord; + assertEquals(UNIGRAM_FREQ, wordProperty.mProbabilityInfo.mProbability); + wordSet.remove(word0); + if (shortcuts.containsKey(word0)) { + assertEquals(shortcuts.get(word0).size(), wordProperty.mShortcutTargets.size()); + final List<String> shortcutList = shortcuts.get(word0); + assertNotNull(wordProperty.mShortcutTargets); + for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + assertTrue(shortcutList.contains(shortcutTarget.mWord)); + assertEquals(UNIGRAM_FREQ, shortcutTarget.getProbability()); + shortcutList.remove(shortcutTarget.mWord); + } + assertTrue(shortcutList.isEmpty()); + } + for (int j = 0; j < wordProperty.mBigrams.size(); j++) { + final String word1 = wordProperty.mBigrams.get(j).mWord; + final Pair<String, String> bigram = new Pair<String, String>(word0, word1); + assertTrue(bigramSet.contains(bigram)); + bigramSet.remove(bigram); + } + token = result.mNextToken; + } while (token != 0); + assertTrue(wordSet.isEmpty()); + assertTrue(bigramSet.isEmpty()); } } diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java deleted file mode 100644 index afe5adb73..000000000 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.inputmethod.latin.makedict; - -import android.test.AndroidTestCase; -import android.test.MoreAsserts; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; - -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; -import com.android.inputmethod.latin.utils.CollectionUtils; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Random; - -@LargeTest -public class BinaryDictIOUtilsTests extends AndroidTestCase { - private static final String TAG = BinaryDictIOUtilsTests.class.getSimpleName(); - private static final FormatSpec.FormatOptions FORMAT_OPTIONS = - new FormatSpec.FormatOptions(3, true); - - private static final ArrayList<String> sWords = CollectionUtils.newArrayList(); - public static final int DEFAULT_MAX_UNIGRAMS = 1500; - private final int mMaxUnigrams; - - private static final String TEST_DICT_FILE_EXTENSION = ".testDict"; - - private static final int VERSION3 = 3; - private static final int VERSION4 = 4; - - private static final String[] CHARACTERS = { - "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", - "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", - "\u00FC" /* ü */, "\u00E2" /* â */, "\u00F1" /* ñ */, // accented characters - "\u4E9C" /* 亜 */, "\u4F0A" /* 伊 */, "\u5B87" /* 宇 */, // kanji - "\uD841\uDE28" /* 𠘨 */, "\uD840\uDC0B" /* 𠀋 */, "\uD861\uDED7" /* 𨛗 */ // surrogate pair - }; - - public BinaryDictIOUtilsTests() { - // 1500 is the default max unigrams - this(System.currentTimeMillis(), DEFAULT_MAX_UNIGRAMS); - } - - public BinaryDictIOUtilsTests(final long seed, final int maxUnigrams) { - super(); - Log.d(TAG, "Seed for test is " + seed + ", maxUnigrams is " + maxUnigrams); - mMaxUnigrams = maxUnigrams; - final Random random = new Random(seed); - sWords.clear(); - for (int i = 0; i < maxUnigrams; ++i) { - sWords.add(generateWord(random.nextInt())); - } - } - - // Utilities for test - private String generateWord(final int value) { - final int lengthOfChars = CHARACTERS.length; - StringBuilder builder = new StringBuilder(""); - long lvalue = Math.abs((long)value); - while (lvalue > 0) { - builder.append(CHARACTERS[(int)(lvalue % lengthOfChars)]); - lvalue /= lengthOfChars; - } - if (builder.toString().equals("")) return "a"; - return builder.toString(); - } - - private static void printPtNode(final PtNodeInfo info) { - Log.d(TAG, " PtNode at " + info.mOriginalAddress); - Log.d(TAG, " flags = " + info.mFlags); - Log.d(TAG, " parentAddress = " + info.mParentAddress); - Log.d(TAG, " characters = " + new String(info.mCharacters, 0, - info.mCharacters.length)); - if (info.mFrequency != -1) Log.d(TAG, " frequency = " + info.mFrequency); - if (info.mChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS) { - Log.d(TAG, " children address = no children address"); - } else { - Log.d(TAG, " children address = " + info.mChildrenAddress); - } - if (info.mShortcutTargets != null) { - for (final WeightedString ws : info.mShortcutTargets) { - Log.d(TAG, " shortcuts = " + ws.mWord); - } - } - if (info.mBigrams != null) { - for (final PendingAttribute attr : info.mBigrams) { - Log.d(TAG, " bigram = " + attr.mAddress); - } - } - Log.d(TAG, " end address = " + info.mEndAddress); - } - - private static void printNode(final Ver3DictDecoder dictDecoder, - final FormatSpec.FormatOptions formatOptions) { - final DictBuffer dictBuffer = dictDecoder.getDictBuffer(); - Log.d(TAG, "Node at " + dictBuffer.position()); - final int count = BinaryDictDecoderUtils.readPtNodeCount(dictBuffer); - Log.d(TAG, " ptNodeCount = " + count); - for (int i = 0; i < count; ++i) { - final PtNodeInfo currentInfo = dictDecoder.readPtNode(dictBuffer.position(), - formatOptions); - printPtNode(currentInfo); - } - if (formatOptions.mSupportsDynamicUpdate) { - final int forwardLinkAddress = dictBuffer.readUnsignedInt24(); - Log.d(TAG, " forwardLinkAddress = " + forwardLinkAddress); - } - } - - @SuppressWarnings("unused") - private static void printBinaryFile(final Ver3DictDecoder dictDecoder) - throws IOException, UnsupportedFormatException { - final FileHeader fileHeader = dictDecoder.readHeader(); - final DictBuffer dictBuffer = dictDecoder.getDictBuffer(); - while (dictBuffer.position() < dictBuffer.limit()) { - printNode(dictDecoder, fileHeader.mFormatOptions); - } - } - - private int getWordPosition(final File file, final String word) { - int position = FormatSpec.NOT_VALID_WORD; - - try { - final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(file, - DictDecoder.USE_READONLY_BYTEBUFFER); - position = dictDecoder.getTerminalPosition(word); - } catch (IOException e) { - } catch (UnsupportedFormatException e) { - } - return position; - } - - /** - * Find a word using the DictDecoder. - * - * @param dictDecoder the dict decoder - * @param word the word searched - * @return the found ptNodeInfo - * @throws IOException - * @throws UnsupportedFormatException - */ - private static PtNodeInfo findWordByBinaryDictReader(final DictDecoder dictDecoder, - final String word) throws IOException, UnsupportedFormatException { - int position = dictDecoder.getTerminalPosition(word); - if (position != FormatSpec.NOT_VALID_WORD) { - dictDecoder.setPosition(0); - final FileHeader header = dictDecoder.readHeader(); - dictDecoder.setPosition(position); - return dictDecoder.readPtNode(position, header.mFormatOptions); - } - return null; - } - - private PtNodeInfo findWordFromFile(final File file, final String word) { - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file); - PtNodeInfo info = null; - try { - dictDecoder.openDictBuffer(); - info = findWordByBinaryDictReader(dictDecoder, word); - } catch (IOException e) { - } catch (UnsupportedFormatException e) { - } - return info; - } - - // return amount of time to insert a word - private long insertAndCheckWord(final File file, final String word, final int frequency, - final boolean exist, final ArrayList<WeightedString> bigrams, - final ArrayList<WeightedString> shortcuts, final int formatVersion) { - long amountOfTime = -1; - try { - final DictUpdater dictUpdater; - if (formatVersion == VERSION3) { - dictUpdater = new Ver3DictUpdater(file, DictDecoder.USE_WRITABLE_BYTEBUFFER); - } else { - throw new RuntimeException("DictUpdater for version " + formatVersion + " doesn't" - + " exist."); - } - - if (!exist) { - assertEquals(FormatSpec.NOT_VALID_WORD, getWordPosition(file, word)); - } - final long now = System.nanoTime(); - dictUpdater.insertWord(word, frequency, bigrams, shortcuts, false, false); - amountOfTime = System.nanoTime() - now; - MoreAsserts.assertNotEqual(FormatSpec.NOT_VALID_WORD, getWordPosition(file, word)); - } catch (IOException e) { - Log.e(TAG, "Raised an IOException while inserting a word", e); - } catch (UnsupportedFormatException e) { - Log.e(TAG, "Raised an UnsupportedFormatException error while inserting a word", e); - } - return amountOfTime; - } - - private void deleteWord(final File file, final String word, final int formatVersion) { - try { - final DictUpdater dictUpdater; - if (formatVersion == VERSION3) { - dictUpdater = new Ver3DictUpdater(file, DictDecoder.USE_WRITABLE_BYTEBUFFER); - } else { - throw new RuntimeException("DictUpdater for version " + formatVersion + " doesn't" - + " exist."); - } - dictUpdater.deleteWord(word); - } catch (IOException e) { - } catch (UnsupportedFormatException e) { - } - } - - private void checkReverseLookup(final File file, final String word, final int position) { - - try { - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file); - final FileHeader fileHeader = dictDecoder.readHeader(); - assertEquals(word, - BinaryDictDecoderUtils.getWordAtPosition(dictDecoder, fileHeader.mHeaderSize, - position, fileHeader.mFormatOptions).mWord); - } catch (IOException e) { - Log.e(TAG, "Raised an IOException while looking up a word", e); - } catch (UnsupportedFormatException e) { - Log.e(TAG, "Raised an UnsupportedFormatException error while looking up a word", e); - } - } - - private void runTestInsertWord(final int formatVersion) { - File file = null; - try { - file = File.createTempFile("testInsertWord", TEST_DICT_FILE_EXTENSION, - getContext().getCacheDir()); - } catch (IOException e) { - fail("IOException while creating temporary file: " + e); - } - - // set an initial dictionary. - final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions(new HashMap<String,String>(), false, false)); - dict.add("abcd", 10, null, false); - - try { - final DictEncoder dictEncoder = new Ver3DictEncoder(file); - dictEncoder.writeDictionary(dict, FORMAT_OPTIONS); - } catch (IOException e) { - fail("IOException while writing an initial dictionary : " + e); - } catch (UnsupportedFormatException e) { - fail("UnsupportedFormatException while writing an initial dictionary : " + e); - } - - MoreAsserts.assertNotEqual(FormatSpec.NOT_VALID_WORD, getWordPosition(file, "abcd")); - insertAndCheckWord(file, "abcde", 10, false, null, null, formatVersion); - - insertAndCheckWord(file, "abcdefghijklmn", 10, false, null, null, formatVersion); - checkReverseLookup(file, "abcdefghijklmn", getWordPosition(file, "abcdefghijklmn")); - - insertAndCheckWord(file, "abcdabcd", 10, false, null, null, formatVersion); - checkReverseLookup(file, "abcdabcd", getWordPosition(file, "abcdabcd")); - - // update the existing word. - insertAndCheckWord(file, "abcdabcd", 15, true, null, null, formatVersion); - - // split 1 - insertAndCheckWord(file, "ab", 20, false, null, null, formatVersion); - - // split 2 - insertAndCheckWord(file, "ami", 30, false, null, null, formatVersion); - - deleteWord(file, "ami", formatVersion); - assertEquals(FormatSpec.NOT_VALID_WORD, getWordPosition(file, "ami")); - - insertAndCheckWord(file, "abcdabfg", 30, false, null, null, formatVersion); - - deleteWord(file, "abcd", formatVersion); - assertEquals(FormatSpec.NOT_VALID_WORD, getWordPosition(file, "abcd")); - } - - public void testInsertWord() { - runTestInsertWord(VERSION3); - } - - private void runTestInsertWordWithBigrams(final int formatVersion) { - File file = null; - try { - file = File.createTempFile("testInsertWordWithBigrams", TEST_DICT_FILE_EXTENSION, - getContext().getCacheDir()); - } catch (IOException e) { - fail("IOException while creating temporary file: " + e); - } - - // set an initial dictionary. - final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions(new HashMap<String,String>(), false, false)); - dict.add("abcd", 10, null, false); - dict.add("efgh", 15, null, false); - - try { - final DictEncoder dictEncoder = new Ver3DictEncoder(file); - dictEncoder.writeDictionary(dict, FORMAT_OPTIONS); - } catch (IOException e) { - fail("IOException while writing an initial dictionary : " + e); - } catch (UnsupportedFormatException e) { - fail("UnsupportedFormatException while writing an initial dictionary : " + e); - } - - final ArrayList<WeightedString> banana = new ArrayList<WeightedString>(); - banana.add(new WeightedString("banana", 10)); - - insertAndCheckWord(file, "banana", 0, false, null, null, formatVersion); - insertAndCheckWord(file, "recursive", 60, true, banana, null, formatVersion); - - final PtNodeInfo info = findWordFromFile(file, "recursive"); - int bananaPos = getWordPosition(file, "banana"); - assertNotNull(info.mBigrams); - assertEquals(info.mBigrams.size(), 1); - assertEquals(info.mBigrams.get(0).mAddress, bananaPos); - } - - public void testInsertWordWithBigrams() { - runTestInsertWordWithBigrams(VERSION3); - } - - private void runTestRandomWords(final int formatVersion) { - File file = null; - try { - file = File.createTempFile("testRandomWord", TEST_DICT_FILE_EXTENSION, - getContext().getCacheDir()); - } catch (IOException e) { - } - assertNotNull(file); - - // set an initial dictionary. - final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions(new HashMap<String, String>(), false, - false)); - dict.add("initial", 10, null, false); - - try { - final DictEncoder dictEncoder = new Ver3DictEncoder(file); - dictEncoder.writeDictionary(dict, FORMAT_OPTIONS); - } catch (IOException e) { - assertTrue(false); - } catch (UnsupportedFormatException e) { - assertTrue(false); - } - - long maxTimeToInsert = 0, sum = 0; - long minTimeToInsert = 100000000; // 1000000000 is an upper bound for minTimeToInsert. - int cnt = 0; - for (final String word : sWords) { - final long diff = insertAndCheckWord(file, word, - cnt % FormatSpec.MAX_TERMINAL_FREQUENCY, false, null, null, formatVersion); - maxTimeToInsert = Math.max(maxTimeToInsert, diff); - minTimeToInsert = Math.min(minTimeToInsert, diff); - sum += diff; - cnt++; - } - cnt = 0; - for (final String word : sWords) { - MoreAsserts.assertNotEqual(FormatSpec.NOT_VALID_WORD, getWordPosition(file, word)); - } - - Log.d(TAG, "Test version " + formatVersion); - Log.d(TAG, "max = " + ((double)maxTimeToInsert/1000000) + " ms."); - Log.d(TAG, "min = " + ((double)minTimeToInsert/1000000) + " ms."); - Log.d(TAG, "avg = " + ((double)sum/mMaxUnigrams/1000000) + " ms."); - } - - public void testRandomWords() { - runTestRandomWords(VERSION3); - } -} diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictUtils.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictUtils.java new file mode 100644 index 000000000..79f3e0dc9 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictUtils.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin.makedict; + +import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; +import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; + +import java.io.File; +import java.util.HashMap; + +public class BinaryDictUtils { + public static final int USE_BYTE_ARRAY = 1; + public static final int USE_BYTE_BUFFER = 2; + + public static final String TEST_DICT_FILE_EXTENSION = ".testDict"; + + public static final FormatSpec.FormatOptions VERSION2_OPTIONS = + new FormatSpec.FormatOptions(FormatSpec.VERSION2); + public static final FormatSpec.FormatOptions VERSION4_OPTIONS_WITHOUT_TIMESTAMP = + new FormatSpec.FormatOptions(FormatSpec.VERSION4, false /* hasTimestamp */); + public static final FormatSpec.FormatOptions VERSION4_OPTIONS_WITH_TIMESTAMP = + new FormatSpec.FormatOptions(FormatSpec.VERSION4, true /* hasTimestamp */); + + public static DictionaryOptions makeDictionaryOptions(final String id, final String version, + final FormatSpec.FormatOptions formatOptions) { + final DictionaryOptions options = new DictionaryOptions(new HashMap<String, String>()); + options.mAttributes.put(DictionaryHeader.DICTIONARY_LOCALE_KEY, "en_US"); + options.mAttributes.put(DictionaryHeader.DICTIONARY_ID_KEY, id); + options.mAttributes.put(DictionaryHeader.DICTIONARY_VERSION_KEY, version); + if (formatOptions.mHasTimestamp) { + options.mAttributes.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); + options.mAttributes.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); + } + return options; + } + + public static File getDictFile(final String name, final String version, + final FormatOptions formatOptions, final File directory) { + if (formatOptions.mVersion == FormatSpec.VERSION2) { + return new File(directory, name + "." + version + TEST_DICT_FILE_EXTENSION); + } else if (formatOptions.mVersion == FormatSpec.VERSION4) { + return new File(directory, name + "." + version); + } else { + throw new RuntimeException("the format option has a wrong version : " + + formatOptions.mVersion); + } + } + + public static DictEncoder getDictEncoder(final File file, final FormatOptions formatOptions) { + if (formatOptions.mVersion == FormatSpec.VERSION4) { + if (!file.isDirectory()) { + file.mkdir(); + } + return new Ver4DictEncoder(file); + } else if (formatOptions.mVersion == FormatSpec.VERSION2) { + return new Ver2DictEncoder(file); + } else { + throw new RuntimeException("The format option has a wrong version : " + + formatOptions.mVersion); + } + } +} diff --git a/tests/src/com/android/inputmethod/latin/makedict/SparseTableTests.java b/tests/src/com/android/inputmethod/latin/makedict/SparseTableTests.java deleted file mode 100644 index aeb8552bd..000000000 --- a/tests/src/com/android/inputmethod/latin/makedict/SparseTableTests.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.inputmethod.latin.makedict; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Random; - -/** - * Unit tests for SparseTable. - */ -@LargeTest -public class SparseTableTests extends AndroidTestCase { - private static final String TAG = SparseTableTests.class.getSimpleName(); - - private final Random mRandom; - private final ArrayList<Integer> mRandomIndex; - - private static final int DEFAULT_SIZE = 10000; - private static final int BLOCK_SIZE = 8; - - public SparseTableTests() { - this(System.currentTimeMillis(), DEFAULT_SIZE); - } - - public SparseTableTests(final long seed, final int tableSize) { - super(); - Log.d(TAG, "Seed for test is " + seed + ", size is " + tableSize); - mRandom = new Random(seed); - mRandomIndex = new ArrayList<Integer>(tableSize); - for (int i = 0; i < tableSize; ++i) { - mRandomIndex.add(SparseTable.NOT_EXIST); - } - } - - public void testSet() { - final SparseTable table = new SparseTable(16, BLOCK_SIZE, 1); - table.set(0, 3, 6); - table.set(0, 8, 16); - for (int i = 0; i < 16; ++i) { - if (i == 3 || i == 8) { - assertEquals(i * 2, table.get(0, i)); - } else { - assertEquals(SparseTable.NOT_EXIST, table.get(0, i)); - } - } - } - - private void generateRandomIndex(final int size, final int prop) { - for (int i = 0; i < size; ++i) { - if (mRandom.nextInt(100) < prop) { - mRandomIndex.set(i, mRandom.nextInt()); - } else { - mRandomIndex.set(i, SparseTable.NOT_EXIST); - } - } - } - - private void runTestRandomSet() { - final SparseTable table = new SparseTable(DEFAULT_SIZE, BLOCK_SIZE, 1); - int elementCount = 0; - for (int i = 0; i < DEFAULT_SIZE; ++i) { - if (mRandomIndex.get(i) != SparseTable.NOT_EXIST) { - table.set(0, i, mRandomIndex.get(i)); - elementCount++; - } - } - - Log.d(TAG, "table size = " + table.getLookupTableSize() + " + " - + table.getContentTableSize()); - Log.d(TAG, "the table has " + elementCount + " elements"); - for (int i = 0; i < DEFAULT_SIZE; ++i) { - assertEquals(table.get(0, i), (int)mRandomIndex.get(i)); - } - - // flush and reload - OutputStream lookupOutStream = null; - OutputStream contentOutStream = null; - try { - final File lookupIndexFile = File.createTempFile("testRandomSet", ".small"); - final File contentFile = File.createTempFile("testRandomSet", ".big"); - lookupOutStream = new FileOutputStream(lookupIndexFile); - contentOutStream = new FileOutputStream(contentFile); - table.write(lookupOutStream, new OutputStream[] { contentOutStream }); - lookupOutStream.flush(); - contentOutStream.flush(); - final SparseTable newTable = SparseTable.readFromFiles(lookupIndexFile, - new File[] { contentFile }, BLOCK_SIZE); - for (int i = 0; i < DEFAULT_SIZE; ++i) { - assertEquals(table.get(0, i), newTable.get(0, i)); - } - } catch (IOException e) { - Log.d(TAG, "IOException while flushing and realoding", e); - } finally { - if (lookupOutStream != null) { - try { - lookupOutStream.close(); - } catch (IOException e) { - Log.d(TAG, "IOException while closing the stream", e); - } - } - if (contentOutStream != null) { - try { - contentOutStream.close(); - } catch (IOException e) { - Log.d(TAG, "IOException while closing contentStream.", e); - } - } - } - } - - public void testRandomSet() { - for (int i = 0; i <= 100; i += 10) { - generateRandomIndex(DEFAULT_SIZE, i); - runTestRandomSet(); - } - } - - public void testMultipleContents() { - final int numOfContents = 5; - generateRandomIndex(DEFAULT_SIZE, 20); - final SparseTable table = new SparseTable(DEFAULT_SIZE, BLOCK_SIZE, numOfContents); - for (int i = 0; i < mRandomIndex.size(); ++i) { - if (mRandomIndex.get(i) != SparseTable.NOT_EXIST) { - for (int j = 0; j < numOfContents; ++j) { - table.set(j, i, mRandomIndex.get(i)); - } - } - } - - OutputStream lookupOutStream = null; - OutputStream[] contentsOutStream = new OutputStream[numOfContents]; - try { - final File lookupIndexFile = File.createTempFile("testMultipleContents", "small"); - lookupOutStream = new FileOutputStream(lookupIndexFile); - final File[] contentFiles = new File[numOfContents]; - for (int i = 0; i < numOfContents; ++i) { - contentFiles[i] = File.createTempFile("testMultipleContents", "big" + i); - contentsOutStream[i] = new FileOutputStream(contentFiles[i]); - } - table.write(lookupOutStream, contentsOutStream); - lookupOutStream.flush(); - for (int i = 0; i < numOfContents; ++i) { - contentsOutStream[i].flush(); - } - final SparseTable newTable = SparseTable.readFromFiles(lookupIndexFile, contentFiles, - BLOCK_SIZE); - for (int i = 0; i < numOfContents; ++i) { - for (int j = 0; j < DEFAULT_SIZE; ++j) { - assertEquals(table.get(i, j), newTable.get(i, j)); - } - } - } catch (IOException e) { - Log.d(TAG, "IOException while flushing and reloading", e); - } finally { - if (lookupOutStream != null) { - try { - lookupOutStream.close(); - } catch (IOException e) { - Log.d(TAG, "IOException while closing the stream", e); - } - } - for (int i = 0; i < numOfContents; ++i) { - if (contentsOutStream[i] != null) { - try { - contentsOutStream[i].close(); - } catch (IOException e) { - Log.d(TAG, "IOException while closing the stream.", e); - } - } - } - } - } -} diff --git a/tests/src/com/android/inputmethod/latin/makedict/Ver3DictDecoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/Ver2DictDecoderTests.java index 9611599b9..a85753e6b 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/Ver3DictDecoderTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/Ver2DictDecoderTests.java @@ -32,10 +32,10 @@ import java.io.FileOutputStream; import java.io.IOException; /** - * Unit tests for Ver3DictDecoder + * Unit tests for Ver2DictDecoder */ -public class Ver3DictDecoderTests extends AndroidTestCase { - private static final String TAG = Ver3DictDecoderTests.class.getSimpleName(); +public class Ver2DictDecoderTests extends AndroidTestCase { + private static final String TAG = Ver2DictDecoderTests.class.getSimpleName(); private final byte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; @@ -68,7 +68,7 @@ public class Ver3DictDecoderTests extends AndroidTestCase { } assertNotNull(testFile); - final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(testFile, factory); + final Ver2DictDecoder dictDecoder = new Ver2DictDecoder(testFile, factory); try { dictDecoder.openDictBuffer(); } catch (Exception e) { @@ -110,7 +110,7 @@ public class Ver3DictDecoderTests extends AndroidTestCase { Log.e(TAG, "IOException while the creating temporary file", e); } - final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(testFile, factory); + final Ver2DictDecoder dictDecoder = new Ver2DictDecoder(testFile, factory); // the default return value of getBuffer() must be null. assertNull("the default return value of getBuffer() is not null", diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java index 7c1decb71..b1239f0af 100644 --- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java @@ -16,18 +16,19 @@ package com.android.inputmethod.latin.personalization; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; +import com.android.inputmethod.latin.BinaryDictionary; import com.android.inputmethod.latin.ExpandableBinaryDictionary; import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.FileUtils; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Random; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -38,25 +39,57 @@ import java.util.concurrent.TimeUnit; @LargeTest public class UserHistoryDictionaryTests extends AndroidTestCase { private static final String TAG = UserHistoryDictionaryTests.class.getSimpleName(); - private SharedPreferences mPrefs; private static final String[] CHARACTERS = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" }; - private static final int MIN_USER_HISTORY_DICTIONARY_FILE_SIZE = 1000; - private static final int WAIT_TERMINATING_IN_MILLISECONDS = 100; + private int mCurrentTime = 0; @Override - public void setUp() { - mPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + protected void setUp() throws Exception { + super.setUp(); + resetCurrentTimeForTestMode(); + } + + @Override + protected void tearDown() throws Exception { + stopTestModeInNativeCode(); + super.tearDown(); + } + + private void resetCurrentTimeForTestMode() { + mCurrentTime = 0; + setCurrentTimeForTestMode(mCurrentTime); + } + + private void forcePassingShortTime() { + // 3 days. + final int timeToElapse = (int)TimeUnit.DAYS.toSeconds(3); + mCurrentTime += timeToElapse; + setCurrentTimeForTestMode(mCurrentTime); + } + + private void forcePassingLongTime() { + // 60 days. + final int timeToElapse = (int)TimeUnit.DAYS.toSeconds(60); + mCurrentTime += timeToElapse; + setCurrentTimeForTestMode(mCurrentTime); + } + + private static int setCurrentTimeForTestMode(final int currentTime) { + return BinaryDictionary.setCurrentTimeForTest(currentTime); + } + + private static int stopTestModeInNativeCode() { + return BinaryDictionary.setCurrentTimeForTest(-1); } /** * Generates a random word. */ - private String generateWord(final int value) { + private static String generateWord(final int value) { final int lengthOfChars = CHARACTERS.length; StringBuilder builder = new StringBuilder(); long lvalue = Math.abs((long)value); @@ -67,7 +100,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { return builder.toString(); } - private List<String> generateWords(final int number, final Random random) { + private static List<String> generateWords(final int number, final Random random) { final Set<String> wordSet = CollectionUtils.newHashSet(); while (wordSet.size() < number) { wordSet.add(generateWord(random.nextInt())); @@ -75,10 +108,11 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { return new ArrayList<String>(wordSet); } - private void addToDict(final UserHistoryDictionary dict, final List<String> words) { + private static void addToDict(final UserHistoryDictionary dict, final List<String> words) { String prevWord = null; for (String word : words) { - dict.addToDictionary(prevWord, word, true); + dict.addToDictionary(prevWord, word, true, + (int)TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); prevWord = word; } } @@ -87,22 +121,18 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { * @param checkContents if true, checks whether written words are actually in the dictionary * or not. */ - private void addAndWriteRandomWords(final String testFilenameSuffix, final int numberOfWords, + private void addAndWriteRandomWords(final Locale locale, final int numberOfWords, final Random random, final boolean checkContents) { final List<String> words = generateWords(numberOfWords, random); - final UserHistoryDictionary dict = - PersonalizationHelper.getUserHistoryDictionary(getContext(), - testFilenameSuffix /* locale */, mPrefs); + final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary( + mContext, locale); // Add random words to the user history dictionary. addToDict(dict, words); if (checkContents) { - try { - Thread.sleep(TimeUnit.MILLISECONDS.convert(5L, TimeUnit.SECONDS)); - } catch (InterruptedException e) { - } + dict.waitAllTasksForTests(); for (int i = 0; i < numberOfWords; ++i) { final String word = words.get(i); - assertTrue(dict.isInDictionaryForTests(word)); + assertTrue(dict.isInUnderlyingBinaryDictionaryForTests(word)); } } // write to file. @@ -111,57 +141,48 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { /** * Clear all entries in the user history dictionary. - * @param testFilenameSuffix file name suffix used for testing. + * @param locale dummy locale for testing. */ - private void clearHistory(final String testFilenameSuffix) { - final UserHistoryDictionary dict = - PersonalizationHelper.getUserHistoryDictionary(getContext(), - testFilenameSuffix /* locale */, mPrefs); + private void clearHistory(final Locale locale) { + final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary( + mContext, locale); + dict.waitAllTasksForTests(); dict.clearAndFlushDictionary(); dict.close(); + dict.waitAllTasksForTests(); } /** * Shut down executer and wait until all operations of user history are done. - * @param testFilenameSuffix file name suffix used for testing. + * @param locale dummy locale for testing. */ - private void waitForWriting(final String testFilenameSuffix) { - try { - final UserHistoryDictionary dict = - PersonalizationHelper.getUserHistoryDictionary(getContext(), - testFilenameSuffix, mPrefs); - dict.shutdownExecutorForTests(); - while (!dict.isTerminatedForTests()) { - Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS); - } - } catch (InterruptedException e) { - Log.d(TAG, "InterruptedException: ", e); - } + private void waitForWriting(final Locale locale) { + final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary( + mContext, locale); + dict.waitAllTasksForTests(); } public void testRandomWords() { Log.d(TAG, "This test can be used for profiling."); Log.d(TAG, "Usage: please set UserHistoryDictionary.PROFILE_SAVE_RESTORE to true."); - final String testFilenameSuffix = "testRandomWords" + System.currentTimeMillis(); - final String fileName = UserHistoryDictionary.NAME + "." + testFilenameSuffix - + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; + final Locale dummyLocale = new Locale("test_random_words" + System.currentTimeMillis()); + final String dictName = ExpandableBinaryDictionary.getDictName( + UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */); + final File dictFile = ExpandableBinaryDictionary.getDictFile( + mContext, dictName, null /* dictFile */); final int numberOfWords = 1000; final Random random = new Random(123456); try { - clearHistory(testFilenameSuffix); - addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random, + clearHistory(dummyLocale); + addAndWriteRandomWords(dummyLocale, numberOfWords, random, true /* checksContents */); } finally { Log.d(TAG, "waiting for writing ..."); - waitForWriting(testFilenameSuffix); - final File dictFile = new File(getContext().getFilesDir(), fileName); - if (dictFile != null) { - assertTrue(dictFile.exists()); - assertTrue(dictFile.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE); - dictFile.delete(); - } + waitForWriting(dummyLocale); + assertTrue("check exisiting of " + dictFile, dictFile.exists()); + FileUtils.deleteRecursively(dictFile); } } @@ -171,17 +192,18 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { final int numberOfWordsInsertedForEachLanguageSwitch = 100; final File dictFiles[] = new File[numberOfLanguages]; - final String testFilenameSuffixes[] = new String[numberOfLanguages]; + final Locale dummyLocales[] = new Locale[numberOfLanguages]; try { final Random random = new Random(123456); // Create filename suffixes for this test. for (int i = 0; i < numberOfLanguages; i++) { - testFilenameSuffixes[i] = "testSwitchingLanguages" + i; - final String fileName = UserHistoryDictionary.NAME + "." + - testFilenameSuffixes[i] + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; - dictFiles[i] = new File(getContext().getFilesDir(), fileName); - clearHistory(testFilenameSuffixes[i]); + dummyLocales[i] = new Locale("test_switching_languages" + i); + final String dictName = ExpandableBinaryDictionary.getDictName( + UserHistoryDictionary.NAME, dummyLocales[i], null /* dictFile */); + dictFiles[i] = ExpandableBinaryDictionary.getDictFile( + mContext, dictName, null /* dictFile */); + clearHistory(dummyLocales[i]); } final long start = System.currentTimeMillis(); @@ -189,7 +211,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { for (int i = 0; i < numberOfLanguageSwitching; i++) { final int index = i % numberOfLanguages; // Switch languages to testFilenameSuffixes[index]. - addAndWriteRandomWords(testFilenameSuffixes[index], + addAndWriteRandomWords(dummyLocales[index], numberOfWordsInsertedForEachLanguageSwitch, random, false /* checksContents */); } @@ -200,40 +222,61 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { } finally { Log.d(TAG, "waiting for writing ..."); for (int i = 0; i < numberOfLanguages; i++) { - waitForWriting(testFilenameSuffixes[i]); + waitForWriting(dummyLocales[i]); } - for (final File file : dictFiles) { - if (file != null) { - assertTrue(file.exists()); - assertTrue(file.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE); - file.delete(); - } + for (final File dictFile : dictFiles) { + assertTrue("check exisiting of " + dictFile, dictFile.exists()); + FileUtils.deleteRecursively(dictFile); } } } public void testAddManyWords() { - final String testFilenameSuffix = "testRandomWords" + System.currentTimeMillis(); - final int numberOfWords = - ExpandableBinaryDictionary.ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE ? - 10000 : 1000; + final Locale dummyLocale = new Locale("test_random_words" + System.currentTimeMillis()); + final String dictName = ExpandableBinaryDictionary.getDictName( + UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */); + final File dictFile = ExpandableBinaryDictionary.getDictFile( + mContext, dictName, null /* dictFile */); + final int numberOfWords = 10000; final Random random = new Random(123456); - clearHistory(testFilenameSuffix); + clearHistory(dummyLocale); try { - addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random, - true /* checksContents */); + addAndWriteRandomWords(dummyLocale, numberOfWords, random, true /* checksContents */); } finally { Log.d(TAG, "waiting for writing ..."); - waitForWriting(testFilenameSuffix); - final String fileName = UserHistoryDictionary.NAME + "." + testFilenameSuffix - + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; - final File dictFile = new File(getContext().getFilesDir(), fileName); - if (dictFile != null) { - assertTrue(dictFile.exists()); - assertTrue(dictFile.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE); - dictFile.delete(); - } + waitForWriting(dummyLocale); + assertTrue("check exisiting of " + dictFile, dictFile.exists()); + FileUtils.deleteRecursively(dictFile); } } + public void testDecaying() { + final Locale dummyLocale = new Locale("test_decaying" + System.currentTimeMillis()); + final int numberOfWords = 5000; + final Random random = new Random(123456); + resetCurrentTimeForTestMode(); + clearHistory(dummyLocale); + final List<String> words = generateWords(numberOfWords, random); + final UserHistoryDictionary dict = + PersonalizationHelper.getUserHistoryDictionary(getContext(), dummyLocale); + dict.waitAllTasksForTests(); + String prevWord = null; + for (final String word : words) { + dict.addToDictionary(prevWord, word, true, mCurrentTime); + prevWord = word; + assertTrue(dict.isInUnderlyingBinaryDictionaryForTests(word)); + } + forcePassingShortTime(); + dict.decayIfNeeded(); + dict.waitAllTasksForTests(); + for (final String word : words) { + assertTrue(dict.isInUnderlyingBinaryDictionaryForTests(word)); + } + forcePassingLongTime(); + dict.decayIfNeeded(); + dict.waitAllTasksForTests(); + for (final String word : words) { + assertFalse(dict.isInUnderlyingBinaryDictionaryForTests(word)); + } + } } diff --git a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java new file mode 100644 index 000000000..2cc22fae4 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java @@ -0,0 +1,477 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin.settings; + +import android.content.res.Resources; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.utils.RunInLocale; + +import junit.framework.AssertionFailedError; + +import java.util.Locale; + +@SmallTest +public class SpacingAndPunctuationsTests extends AndroidTestCase { + private static final int ARMENIAN_FULL_STOP = '\u0589'; + private static final int ARMENIAN_COMMA = '\u055D'; + + private int mScreenMetrics; + + private boolean isPhone() { + return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_PHONE + || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_PHONE; + } + + private boolean isTablet() { + return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_TABLET + || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_TABLET; + } + + private SpacingAndPunctuations ENGLISH; + private SpacingAndPunctuations FRENCH; + private SpacingAndPunctuations GERMAN; + private SpacingAndPunctuations ARMENIAN; + private SpacingAndPunctuations THAI; + private SpacingAndPunctuations KHMER; + private SpacingAndPunctuations LAO; + private SpacingAndPunctuations ARABIC; + private SpacingAndPunctuations PERSIAN; + private SpacingAndPunctuations HEBREW; + + private SpacingAndPunctuations UNITED_STATES; + private SpacingAndPunctuations UNITED_KINGDOM; + private SpacingAndPunctuations CANADA_FRENCH; + private SpacingAndPunctuations SWISS_GERMAN; + private SpacingAndPunctuations INDIA_ENGLISH; + private SpacingAndPunctuations ARMENIA_ARMENIAN; + private SpacingAndPunctuations CAMBODIA_KHMER; + private SpacingAndPunctuations LAOS_LAO; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mScreenMetrics = mContext.getResources().getInteger(R.integer.config_screen_metrics); + + // Language only + ENGLISH = getSpacingAndPunctuations(Locale.ENGLISH); + FRENCH = getSpacingAndPunctuations(Locale.FRENCH); + GERMAN = getSpacingAndPunctuations(Locale.GERMAN); + THAI = getSpacingAndPunctuations(new Locale("th")); + ARMENIAN = getSpacingAndPunctuations(new Locale("hy")); + KHMER = getSpacingAndPunctuations(new Locale("km")); + LAO = getSpacingAndPunctuations(new Locale("lo")); + ARABIC = getSpacingAndPunctuations(new Locale("ar")); + PERSIAN = getSpacingAndPunctuations(new Locale("fa")); + HEBREW = getSpacingAndPunctuations(new Locale("iw")); + + // Language and Country + UNITED_STATES = getSpacingAndPunctuations(Locale.US); + UNITED_KINGDOM = getSpacingAndPunctuations(Locale.UK); + CANADA_FRENCH = getSpacingAndPunctuations(Locale.CANADA_FRENCH); + SWISS_GERMAN = getSpacingAndPunctuations(new Locale("de", "CH")); + INDIA_ENGLISH = getSpacingAndPunctuations(new Locale("en", "IN")); + ARMENIA_ARMENIAN = getSpacingAndPunctuations(new Locale("hy", "AM")); + CAMBODIA_KHMER = getSpacingAndPunctuations(new Locale("km", "KH")); + LAOS_LAO = getSpacingAndPunctuations(new Locale("lo", "LA")); + } + + private SpacingAndPunctuations getSpacingAndPunctuations(final Locale locale) { + final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() { + @Override + protected SpacingAndPunctuations job(Resources res) { + return new SpacingAndPunctuations(res); + } + }; + return job.runInLocale(getContext().getResources(), locale); + } + + private static void testingStandardWordSeparator(final SpacingAndPunctuations sp) { + assertTrue("Tab", sp.isWordSeparator('\t')); + assertTrue("Newline", sp.isWordSeparator('\n')); + assertTrue("Space", sp.isWordSeparator(' ')); + assertTrue("Exclamation", sp.isWordSeparator('!')); + assertTrue("Quotation", sp.isWordSeparator('"')); + assertFalse("Number", sp.isWordSeparator('#')); + assertFalse("Dollar", sp.isWordSeparator('$')); + assertFalse("Percent", sp.isWordSeparator('%')); + assertTrue("Ampersand", sp.isWordSeparator('&')); + assertFalse("Apostrophe", sp.isWordSeparator('\'')); + assertTrue("L Paren", sp.isWordSeparator('(')); + assertTrue("R Paren", sp.isWordSeparator(')')); + assertTrue("Asterisk", sp.isWordSeparator('*')); + assertTrue("Plus", sp.isWordSeparator('+')); + assertTrue("Comma", sp.isWordSeparator(',')); + assertFalse("Minus", sp.isWordSeparator('-')); + assertTrue("Period", sp.isWordSeparator('.')); + assertTrue("Slash", sp.isWordSeparator('/')); + assertTrue("Colon", sp.isWordSeparator(':')); + assertTrue("Semicolon", sp.isWordSeparator(';')); + assertTrue("L Angle", sp.isWordSeparator('<')); + assertTrue("Equal", sp.isWordSeparator('=')); + assertTrue("R Angle", sp.isWordSeparator('>')); + assertTrue("Question", sp.isWordSeparator('?')); + assertFalse("Atmark", sp.isWordSeparator('@')); + assertTrue("L S Bracket", sp.isWordSeparator('[')); + assertFalse("B Slash", sp.isWordSeparator('\\')); + assertTrue("R S Bracket", sp.isWordSeparator(']')); + assertFalse("Circumflex", sp.isWordSeparator('^')); + assertTrue("Underscore", sp.isWordSeparator('_')); + assertFalse("Grave", sp.isWordSeparator('`')); + assertTrue("L C Brace", sp.isWordSeparator('{')); + assertTrue("V Line", sp.isWordSeparator('|')); + assertTrue("R C Brace", sp.isWordSeparator('}')); + assertFalse("Tilde", sp.isWordSeparator('~')); + } + + public void testWordSeparator() { + testingStandardWordSeparator(ENGLISH); + testingStandardWordSeparator(FRENCH); + testingStandardWordSeparator(CANADA_FRENCH); + testingStandardWordSeparator(ARMENIA_ARMENIAN); + assertTrue(ARMENIA_ARMENIAN.isWordSeparator(ARMENIAN_FULL_STOP)); + assertTrue(ARMENIA_ARMENIAN.isWordSeparator(ARMENIAN_COMMA)); + // TODO: We should fix these. + testingStandardWordSeparator(ARMENIAN); + assertFalse(ARMENIAN.isWordSeparator(ARMENIAN_FULL_STOP)); + assertFalse(ARMENIAN.isWordSeparator(ARMENIAN_COMMA)); + } + + private static void testingStandardWordConnector(final SpacingAndPunctuations sp) { + assertFalse("Tab", sp.isWordConnector('\t')); + assertFalse("Newline", sp.isWordConnector('\n')); + assertFalse("Space", sp.isWordConnector(' ')); + assertFalse("Exclamation", sp.isWordConnector('!')); + assertFalse("Quotation", sp.isWordConnector('"')); + assertFalse("Number", sp.isWordConnector('#')); + assertFalse("Dollar", sp.isWordConnector('$')); + assertFalse("Percent", sp.isWordConnector('%')); + assertFalse("Ampersand", sp.isWordConnector('&')); + assertTrue("Apostrophe", sp.isWordConnector('\'')); + assertFalse("L Paren", sp.isWordConnector('(')); + assertFalse("R Paren", sp.isWordConnector(')')); + assertFalse("Asterisk", sp.isWordConnector('*')); + assertFalse("Plus", sp.isWordConnector('+')); + assertFalse("Comma", sp.isWordConnector(',')); + assertTrue("Minus", sp.isWordConnector('-')); + assertFalse("Period", sp.isWordConnector('.')); + assertFalse("Slash", sp.isWordConnector('/')); + assertFalse("Colon", sp.isWordConnector(':')); + assertFalse("Semicolon", sp.isWordConnector(';')); + assertFalse("L Angle", sp.isWordConnector('<')); + assertFalse("Equal", sp.isWordConnector('=')); + assertFalse("R Angle", sp.isWordConnector('>')); + assertFalse("Question", sp.isWordConnector('?')); + assertFalse("Atmark", sp.isWordConnector('@')); + assertFalse("L S Bracket", sp.isWordConnector('[')); + assertFalse("B Slash", sp.isWordConnector('\\')); + assertFalse("R S Bracket", sp.isWordConnector(']')); + assertFalse("Circumflex", sp.isWordConnector('^')); + assertFalse("Underscore", sp.isWordConnector('_')); + assertFalse("Grave", sp.isWordConnector('`')); + assertFalse("L C Brace", sp.isWordConnector('{')); + assertFalse("V Line", sp.isWordConnector('|')); + assertFalse("R C Brace", sp.isWordConnector('}')); + assertFalse("Tilde", sp.isWordConnector('~')); + + } + + public void testWordConnector() { + testingStandardWordConnector(ENGLISH); + testingStandardWordConnector(FRENCH); + testingStandardWordConnector(CANADA_FRENCH); + testingStandardWordConnector(ARMENIA_ARMENIAN); + } + + private static void testingCommonPrecededBySpace(final SpacingAndPunctuations sp) { + assertFalse("Tab", sp.isUsuallyPrecededBySpace('\t')); + assertFalse("Newline", sp.isUsuallyPrecededBySpace('\n')); + assertFalse("Space", sp.isUsuallyPrecededBySpace(' ')); + //assertFalse("Exclamation", sp.isUsuallyPrecededBySpace('!')); + assertFalse("Quotation", sp.isUsuallyPrecededBySpace('"')); + assertFalse("Number", sp.isUsuallyPrecededBySpace('#')); + assertFalse("Dollar", sp.isUsuallyPrecededBySpace('$')); + assertFalse("Percent", sp.isUsuallyPrecededBySpace('%')); + assertTrue("Ampersand", sp.isUsuallyPrecededBySpace('&')); + assertFalse("Apostrophe", sp.isUsuallyPrecededBySpace('\'')); + assertTrue("L Paren", sp.isUsuallyPrecededBySpace('(')); + assertFalse("R Paren", sp.isUsuallyPrecededBySpace(')')); + assertFalse("Asterisk", sp.isUsuallyPrecededBySpace('*')); + assertFalse("Plus", sp.isUsuallyPrecededBySpace('+')); + assertFalse("Comma", sp.isUsuallyPrecededBySpace(',')); + assertFalse("Minus", sp.isUsuallyPrecededBySpace('-')); + assertFalse("Period", sp.isUsuallyPrecededBySpace('.')); + assertFalse("Slash", sp.isUsuallyPrecededBySpace('/')); + //assertFalse("Colon", sp.isUsuallyPrecededBySpace(':')); + //assertFalse("Semicolon", sp.isUsuallyPrecededBySpace(';')); + assertFalse("L Angle", sp.isUsuallyPrecededBySpace('<')); + assertFalse("Equal", sp.isUsuallyPrecededBySpace('=')); + assertFalse("R Angle", sp.isUsuallyPrecededBySpace('>')); + //assertFalse("Question", sp.isUsuallyPrecededBySpace('?')); + assertFalse("Atmark", sp.isUsuallyPrecededBySpace('@')); + assertTrue("L S Bracket", sp.isUsuallyPrecededBySpace('[')); + assertFalse("B Slash", sp.isUsuallyPrecededBySpace('\\')); + assertFalse("R S Bracket", sp.isUsuallyPrecededBySpace(']')); + assertFalse("Circumflex", sp.isUsuallyPrecededBySpace('^')); + assertFalse("Underscore", sp.isUsuallyPrecededBySpace('_')); + assertFalse("Grave", sp.isUsuallyPrecededBySpace('`')); + assertTrue("L C Brace", sp.isUsuallyPrecededBySpace('{')); + assertFalse("V Line", sp.isUsuallyPrecededBySpace('|')); + assertFalse("R C Brace", sp.isUsuallyPrecededBySpace('}')); + assertFalse("Tilde", sp.isUsuallyPrecededBySpace('~')); + } + + private static void testingStandardPrecededBySpace(final SpacingAndPunctuations sp) { + testingCommonPrecededBySpace(sp); + assertFalse("Exclamation", sp.isUsuallyPrecededBySpace('!')); + assertFalse("Colon", sp.isUsuallyPrecededBySpace(':')); + assertFalse("Semicolon", sp.isUsuallyPrecededBySpace(';')); + assertFalse("Question", sp.isUsuallyPrecededBySpace('?')); + } + + public void testIsUsuallyPrecededBySpace() { + testingStandardPrecededBySpace(ENGLISH); + testingCommonPrecededBySpace(FRENCH); + assertTrue("Exclamation", FRENCH.isUsuallyPrecededBySpace('!')); + assertTrue("Colon", FRENCH.isUsuallyPrecededBySpace(':')); + assertTrue("Semicolon", FRENCH.isUsuallyPrecededBySpace(';')); + assertTrue("Question", FRENCH.isUsuallyPrecededBySpace('?')); + testingCommonPrecededBySpace(CANADA_FRENCH); + assertFalse("Exclamation", CANADA_FRENCH.isUsuallyPrecededBySpace('!')); + assertTrue("Colon", CANADA_FRENCH.isUsuallyPrecededBySpace(':')); + assertFalse("Semicolon", CANADA_FRENCH.isUsuallyPrecededBySpace(';')); + assertFalse("Question", CANADA_FRENCH.isUsuallyPrecededBySpace('?')); + testingStandardPrecededBySpace(ARMENIA_ARMENIAN); + } + + private static void testingStandardFollowedBySpace(final SpacingAndPunctuations sp) { + assertFalse("Tab", sp.isUsuallyFollowedBySpace('\t')); + assertFalse("Newline", sp.isUsuallyFollowedBySpace('\n')); + assertFalse("Space", sp.isUsuallyFollowedBySpace(' ')); + assertTrue("Exclamation", sp.isUsuallyFollowedBySpace('!')); + assertFalse("Quotation", sp.isUsuallyFollowedBySpace('"')); + assertFalse("Number", sp.isUsuallyFollowedBySpace('#')); + assertFalse("Dollar", sp.isUsuallyFollowedBySpace('$')); + assertFalse("Percent", sp.isUsuallyFollowedBySpace('%')); + assertTrue("Ampersand", sp.isUsuallyFollowedBySpace('&')); + assertFalse("Apostrophe", sp.isUsuallyFollowedBySpace('\'')); + assertFalse("L Paren", sp.isUsuallyFollowedBySpace('(')); + assertTrue("R Paren", sp.isUsuallyFollowedBySpace(')')); + assertFalse("Asterisk", sp.isUsuallyFollowedBySpace('*')); + assertFalse("Plus", sp.isUsuallyFollowedBySpace('+')); + assertTrue("Comma", sp.isUsuallyFollowedBySpace(',')); + assertFalse("Minus", sp.isUsuallyFollowedBySpace('-')); + assertTrue("Period", sp.isUsuallyFollowedBySpace('.')); + assertFalse("Slash", sp.isUsuallyFollowedBySpace('/')); + assertTrue("Colon", sp.isUsuallyFollowedBySpace(':')); + assertTrue("Semicolon", sp.isUsuallyFollowedBySpace(';')); + assertFalse("L Angle", sp.isUsuallyFollowedBySpace('<')); + assertFalse("Equal", sp.isUsuallyFollowedBySpace('=')); + assertFalse("R Angle", sp.isUsuallyFollowedBySpace('>')); + assertTrue("Question", sp.isUsuallyFollowedBySpace('?')); + assertFalse("Atmark", sp.isUsuallyFollowedBySpace('@')); + assertFalse("L S Bracket", sp.isUsuallyFollowedBySpace('[')); + assertFalse("B Slash", sp.isUsuallyFollowedBySpace('\\')); + assertTrue("R S Bracket", sp.isUsuallyFollowedBySpace(']')); + assertFalse("Circumflex", sp.isUsuallyFollowedBySpace('^')); + assertFalse("Underscore", sp.isUsuallyFollowedBySpace('_')); + assertFalse("Grave", sp.isUsuallyFollowedBySpace('`')); + assertFalse("L C Brace", sp.isUsuallyFollowedBySpace('{')); + assertFalse("V Line", sp.isUsuallyFollowedBySpace('|')); + assertTrue("R C Brace", sp.isUsuallyFollowedBySpace('}')); + assertFalse("Tilde", sp.isUsuallyFollowedBySpace('~')); + } + + public void testIsUsuallyFollowedBySpace() { + testingStandardFollowedBySpace(ENGLISH); + testingStandardFollowedBySpace(FRENCH); + testingStandardFollowedBySpace(CANADA_FRENCH); + testingStandardFollowedBySpace(ARMENIA_ARMENIAN); + assertTrue(ARMENIA_ARMENIAN.isUsuallyFollowedBySpace(ARMENIAN_FULL_STOP)); + assertTrue(ARMENIA_ARMENIAN.isUsuallyFollowedBySpace(ARMENIAN_COMMA)); + } + + private static void testingStandardSentenceSeparator(final SpacingAndPunctuations sp) { + assertFalse("Tab", sp.isUsuallyFollowedBySpace('\t')); + assertFalse("Newline", sp.isUsuallyFollowedBySpace('\n')); + assertFalse("Space", sp.isUsuallyFollowedBySpace(' ')); + assertFalse("Exclamation", sp.isUsuallyFollowedBySpace('!')); + assertFalse("Quotation", sp.isUsuallyFollowedBySpace('"')); + assertFalse("Number", sp.isUsuallyFollowedBySpace('#')); + assertFalse("Dollar", sp.isUsuallyFollowedBySpace('$')); + assertFalse("Percent", sp.isUsuallyFollowedBySpace('%')); + assertFalse("Ampersand", sp.isUsuallyFollowedBySpace('&')); + assertFalse("Apostrophe", sp.isUsuallyFollowedBySpace('\'')); + assertFalse("L Paren", sp.isUsuallyFollowedBySpace('(')); + assertFalse("R Paren", sp.isUsuallyFollowedBySpace(')')); + assertFalse("Asterisk", sp.isUsuallyFollowedBySpace('*')); + assertFalse("Plus", sp.isUsuallyFollowedBySpace('+')); + assertFalse("Comma", sp.isUsuallyFollowedBySpace(',')); + assertFalse("Minus", sp.isUsuallyFollowedBySpace('-')); + assertTrue("Period", sp.isUsuallyFollowedBySpace('.')); + assertFalse("Slash", sp.isUsuallyFollowedBySpace('/')); + assertFalse("Colon", sp.isUsuallyFollowedBySpace(':')); + assertFalse("Semicolon", sp.isUsuallyFollowedBySpace(';')); + assertFalse("L Angle", sp.isUsuallyFollowedBySpace('<')); + assertFalse("Equal", sp.isUsuallyFollowedBySpace('=')); + assertFalse("R Angle", sp.isUsuallyFollowedBySpace('>')); + assertFalse("Question", sp.isUsuallyFollowedBySpace('?')); + assertFalse("Atmark", sp.isUsuallyFollowedBySpace('@')); + assertFalse("L S Bracket", sp.isUsuallyFollowedBySpace('[')); + assertFalse("B Slash", sp.isUsuallyFollowedBySpace('\\')); + assertFalse("R S Bracket", sp.isUsuallyFollowedBySpace(']')); + assertFalse("Circumflex", sp.isUsuallyFollowedBySpace('^')); + assertFalse("Underscore", sp.isUsuallyFollowedBySpace('_')); + assertFalse("Grave", sp.isUsuallyFollowedBySpace('`')); + assertFalse("L C Brace", sp.isUsuallyFollowedBySpace('{')); + assertFalse("V Line", sp.isUsuallyFollowedBySpace('|')); + assertFalse("R C Brace", sp.isUsuallyFollowedBySpace('}')); + assertFalse("Tilde", sp.isUsuallyFollowedBySpace('~')); + } + + public void isSentenceSeparator() { + testingStandardSentenceSeparator(ENGLISH); + try { + testingStandardSentenceSeparator(ARMENIA_ARMENIAN); + fail("Armenian Sentence Separator"); + } catch (final AssertionFailedError e) { + assertEquals("Period", e.getMessage()); + } + assertTrue(ARMENIA_ARMENIAN.isSentenceSeparator(ARMENIAN_FULL_STOP)); + assertFalse(ARMENIA_ARMENIAN.isSentenceSeparator(ARMENIAN_COMMA)); + } + + public void testLanguageHasSpace() { + assertTrue(ENGLISH.mCurrentLanguageHasSpaces); + assertTrue(FRENCH.mCurrentLanguageHasSpaces); + assertTrue(GERMAN.mCurrentLanguageHasSpaces); + assertFalse(THAI.mCurrentLanguageHasSpaces); + assertFalse(CAMBODIA_KHMER.mCurrentLanguageHasSpaces); + assertFalse(LAOS_LAO.mCurrentLanguageHasSpaces); + // TODO: We should fix these. + assertTrue(KHMER.mCurrentLanguageHasSpaces); + assertTrue(LAO.mCurrentLanguageHasSpaces); + } + + public void testUsesAmericanTypography() { + assertTrue(ENGLISH.mUsesAmericanTypography); + assertTrue(UNITED_STATES.mUsesAmericanTypography); + assertTrue(UNITED_KINGDOM.mUsesAmericanTypography); + assertTrue(INDIA_ENGLISH.mUsesAmericanTypography); + assertFalse(FRENCH.mUsesAmericanTypography); + assertFalse(GERMAN.mUsesAmericanTypography); + assertFalse(SWISS_GERMAN.mUsesAmericanTypography); + } + + public void testUsesGermanRules() { + assertFalse(ENGLISH.mUsesGermanRules); + assertFalse(FRENCH.mUsesGermanRules); + assertTrue(GERMAN.mUsesGermanRules); + assertTrue(SWISS_GERMAN.mUsesGermanRules); + } + + // Punctuations for phone. + private static final String[] PUNCTUATION_LABELS_PHONE = { + "!", "?", ",", ":", ";", "\"", "(", ")", "'", "-", "/", "@", "_" + }; + private static final String[] PUNCTUATION_WORDS_PHONE_LTR = PUNCTUATION_LABELS_PHONE; + private static final String[] PUNCTUATION_WORDS_PHONE_HEBREW = { + "!", "?", ",", ":", ";", "\"", ")", "(", "'", "-", "/", "@", "_" + }; + // U+061F: "؟" ARABIC QUESTION MARK + // U+060C: "،" ARABIC COMMA + // U+061B: "؛" ARABIC SEMICOLON + private static final String[] PUNCTUATION_LABELS_PHONE_ARABIC_PERSIAN = { + "!", "\u061F", "\u060C", ":", "\u061B", "\"", "(", ")", "'", "-", "/", "@", "_" + }; + private static final String[] PUNCTUATION_WORDS_PHONE_ARABIC_PERSIAN = { + "!", "\u061F", "\u060C", ":", "\u061B", "\"", ")", "(", "'", "-", "/", "@", "_" + }; + + // Punctuations for tablet. + private static final String[] PUNCTUATION_LABELS_TABLET = { + ":", ";", "\"", "(", ")", "'", "-", "/", "@", "_" + }; + private static final String[] PUNCTUATION_WORDS_TABLET_LTR = PUNCTUATION_LABELS_TABLET; + private static final String[] PUNCTUATION_WORDS_TABLET_HEBREW = { + ":", ";", "\"", ")", "(", "'", "-", "/", "@", "_" + }; + private static final String[] PUNCTUATION_LABELS_TABLET_ARABIC_PERSIAN = { + "!", "\u061F", ":", "\u061B", "\"", "'", "(", ")", "-", "/", "@", "_" + }; + private static final String[] PUNCTUATION_WORDS_TABLET_ARABIC_PERSIAN = { + "!", "\u061F", ":", "\u061B", "\"", "'", ")", "(", "-", "/", "@", "_" + }; + + private static void testingStandardPunctuationSuggestions(final SpacingAndPunctuations sp, + final String[] punctuationLabels, final String[] punctuationWords) { + final SuggestedWords suggestedWords = sp.mSuggestPuncList; + assertFalse("typedWordValid", suggestedWords.mTypedWordValid); + assertFalse("willAutoCorrect", suggestedWords.mWillAutoCorrect); + assertTrue("isPunctuationSuggestions", suggestedWords.isPunctuationSuggestions()); + assertFalse("isObsoleteSuggestions", suggestedWords.mIsObsoleteSuggestions); + assertFalse("isPrediction", suggestedWords.mIsPrediction); + assertEquals("size", punctuationLabels.length, suggestedWords.size()); + for (int index = 0; index < suggestedWords.size(); index++) { + assertEquals("punctuation label at " + index, + punctuationLabels[index], suggestedWords.getLabel(index)); + assertEquals("punctuation word at " + index, + punctuationWords[index], suggestedWords.getWord(index)); + } + } + + public void testPhonePunctuationSuggestions() { + if (!isPhone()) { + return; + } + testingStandardPunctuationSuggestions(ENGLISH, + PUNCTUATION_LABELS_PHONE, PUNCTUATION_WORDS_PHONE_LTR); + testingStandardPunctuationSuggestions(FRENCH, + PUNCTUATION_LABELS_PHONE, PUNCTUATION_WORDS_PHONE_LTR); + testingStandardPunctuationSuggestions(GERMAN, + PUNCTUATION_LABELS_PHONE, PUNCTUATION_WORDS_PHONE_LTR); + testingStandardPunctuationSuggestions(ARABIC, + PUNCTUATION_LABELS_PHONE_ARABIC_PERSIAN, PUNCTUATION_WORDS_PHONE_ARABIC_PERSIAN); + testingStandardPunctuationSuggestions(PERSIAN, + PUNCTUATION_LABELS_PHONE_ARABIC_PERSIAN, PUNCTUATION_WORDS_PHONE_ARABIC_PERSIAN); + testingStandardPunctuationSuggestions(HEBREW, + PUNCTUATION_LABELS_PHONE, PUNCTUATION_WORDS_PHONE_HEBREW); + } + + public void testTabletPunctuationSuggestions() { + if (!isTablet()) { + return; + } + testingStandardPunctuationSuggestions(ENGLISH, + PUNCTUATION_LABELS_TABLET, PUNCTUATION_WORDS_TABLET_LTR); + testingStandardPunctuationSuggestions(FRENCH, + PUNCTUATION_LABELS_TABLET, PUNCTUATION_WORDS_TABLET_LTR); + testingStandardPunctuationSuggestions(GERMAN, + PUNCTUATION_LABELS_TABLET, PUNCTUATION_WORDS_TABLET_LTR); + testingStandardPunctuationSuggestions(ARABIC, + PUNCTUATION_LABELS_TABLET_ARABIC_PERSIAN, PUNCTUATION_WORDS_TABLET_ARABIC_PERSIAN); + testingStandardPunctuationSuggestions(PERSIAN, + PUNCTUATION_LABELS_TABLET_ARABIC_PERSIAN, PUNCTUATION_WORDS_TABLET_ARABIC_PERSIAN); + testingStandardPunctuationSuggestions(HEBREW, + PUNCTUATION_LABELS_TABLET, PUNCTUATION_WORDS_TABLET_HEBREW); + } +} diff --git a/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java index 1fd5c989a..020d63299 100644 --- a/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java @@ -16,75 +16,98 @@ package com.android.inputmethod.latin.utils; -import com.android.inputmethod.latin.settings.SettingsValues; - +import android.content.res.Resources; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import android.text.TextUtils; +import com.android.inputmethod.latin.settings.SpacingAndPunctuations; + import java.util.Locale; @SmallTest public class CapsModeUtilsTests extends AndroidTestCase { private static void onePathForCaps(final CharSequence cs, final int expectedResult, - final int mask, final SettingsValues sv, final boolean hasSpaceBefore) { - int oneTimeResult = expectedResult & mask; + final int mask, final SpacingAndPunctuations sp, final boolean hasSpaceBefore) { + final int oneTimeResult = expectedResult & mask; assertEquals("After >" + cs + "<", oneTimeResult, - CapsModeUtils.getCapsMode(cs, mask, sv, hasSpaceBefore)); + CapsModeUtils.getCapsMode(cs, mask, sp, hasSpaceBefore)); } private static void allPathsForCaps(final CharSequence cs, final int expectedResult, - final SettingsValues sv, final boolean hasSpaceBefore) { + final SpacingAndPunctuations sp, final boolean hasSpaceBefore) { final int c = TextUtils.CAP_MODE_CHARACTERS; final int w = TextUtils.CAP_MODE_WORDS; final int s = TextUtils.CAP_MODE_SENTENCES; - onePathForCaps(cs, expectedResult, c | w | s, sv, hasSpaceBefore); - onePathForCaps(cs, expectedResult, w | s, sv, hasSpaceBefore); - onePathForCaps(cs, expectedResult, c | s, sv, hasSpaceBefore); - onePathForCaps(cs, expectedResult, c | w, sv, hasSpaceBefore); - onePathForCaps(cs, expectedResult, c, sv, hasSpaceBefore); - onePathForCaps(cs, expectedResult, w, sv, hasSpaceBefore); - onePathForCaps(cs, expectedResult, s, sv, hasSpaceBefore); + onePathForCaps(cs, expectedResult, c | w | s, sp, hasSpaceBefore); + onePathForCaps(cs, expectedResult, w | s, sp, hasSpaceBefore); + onePathForCaps(cs, expectedResult, c | s, sp, hasSpaceBefore); + onePathForCaps(cs, expectedResult, c | w, sp, hasSpaceBefore); + onePathForCaps(cs, expectedResult, c, sp, hasSpaceBefore); + onePathForCaps(cs, expectedResult, w, sp, hasSpaceBefore); + onePathForCaps(cs, expectedResult, s, sp, hasSpaceBefore); } public void testGetCapsMode() { final int c = TextUtils.CAP_MODE_CHARACTERS; final int w = TextUtils.CAP_MODE_WORDS; final int s = TextUtils.CAP_MODE_SENTENCES; - SettingsValues sv = SettingsValues.makeDummySettingsValuesForTest(Locale.ENGLISH); - allPathsForCaps("", c | w | s, sv, false); - allPathsForCaps("Word", c, sv, false); - allPathsForCaps("Word.", c, sv, false); - allPathsForCaps("Word ", c | w, sv, false); - allPathsForCaps("Word. ", c | w | s, sv, false); - allPathsForCaps("Word..", c, sv, false); - allPathsForCaps("Word.. ", c | w | s, sv, false); - allPathsForCaps("Word... ", c | w | s, sv, false); - allPathsForCaps("Word ... ", c | w | s, sv, false); - allPathsForCaps("Word . ", c | w, sv, false); - allPathsForCaps("In the U.S ", c | w, sv, false); - allPathsForCaps("In the U.S. ", c | w, sv, false); - allPathsForCaps("Some stuff (e.g. ", c | w, sv, false); - allPathsForCaps("In the U.S.. ", c | w | s, sv, false); - allPathsForCaps("\"Word.\" ", c | w | s, sv, false); - allPathsForCaps("\"Word\". ", c | w | s, sv, false); - allPathsForCaps("\"Word\" ", c | w, sv, false); + final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() { + @Override + protected SpacingAndPunctuations job(final Resources res) { + return new SpacingAndPunctuations(res); + } + }; + final Resources res = getContext().getResources(); + SpacingAndPunctuations sp = job.runInLocale(res, Locale.ENGLISH); + allPathsForCaps("", c | w | s, sp, false); + allPathsForCaps("Word", c, sp, false); + allPathsForCaps("Word.", c, sp, false); + allPathsForCaps("Word ", c | w, sp, false); + allPathsForCaps("Word. ", c | w | s, sp, false); + allPathsForCaps("Word..", c, sp, false); + allPathsForCaps("Word.. ", c | w | s, sp, false); + allPathsForCaps("Word... ", c | w | s, sp, false); + allPathsForCaps("Word ... ", c | w | s, sp, false); + allPathsForCaps("Word . ", c | w, sp, false); + allPathsForCaps("In the U.S ", c | w, sp, false); + allPathsForCaps("In the U.S. ", c | w, sp, false); + allPathsForCaps("Some stuff (e.g. ", c | w, sp, false); + allPathsForCaps("In the U.S.. ", c | w | s, sp, false); + allPathsForCaps("\"Word.\" ", c | w | s, sp, false); + allPathsForCaps("\"Word\". ", c | w | s, sp, false); + allPathsForCaps("\"Word\" ", c | w, sp, false); // Test for phantom space - allPathsForCaps("Word", c | w, sv, true); - allPathsForCaps("Word.", c | w | s, sv, true); + allPathsForCaps("Word", c | w, sp, true); + allPathsForCaps("Word.", c | w | s, sp, true); // Tests after some whitespace - allPathsForCaps("Word\n", c | w | s, sv, false); - allPathsForCaps("Word\n", c | w | s, sv, true); - allPathsForCaps("Word\n ", c | w | s, sv, true); - allPathsForCaps("Word.\n", c | w | s, sv, false); - allPathsForCaps("Word.\n", c | w | s, sv, true); - allPathsForCaps("Word.\n ", c | w | s, sv, true); + allPathsForCaps("Word\n", c | w | s, sp, false); + allPathsForCaps("Word\n", c | w | s, sp, true); + allPathsForCaps("Word\n ", c | w | s, sp, true); + allPathsForCaps("Word.\n", c | w | s, sp, false); + allPathsForCaps("Word.\n", c | w | s, sp, true); + allPathsForCaps("Word.\n ", c | w | s, sp, true); + + sp = job.runInLocale(res, Locale.FRENCH); + allPathsForCaps("\"Word.\" ", c | w, sp, false); + allPathsForCaps("\"Word\". ", c | w | s, sp, false); + allPathsForCaps("\"Word\" ", c | w, sp, false); - sv = SettingsValues.makeDummySettingsValuesForTest(Locale.FRENCH); - allPathsForCaps("\"Word.\" ", c | w, sv, false); - allPathsForCaps("\"Word\". ", c | w | s, sv, false); - allPathsForCaps("\"Word\" ", c | w, sv, false); + // Test special case for German. German does not capitalize at the start of a + // line when the previous line starts with a comma. It does in other cases. + sp = job.runInLocale(res, Locale.GERMAN); + allPathsForCaps("Liebe Sara,\n", c | w, sp, false); + allPathsForCaps("Liebe Sara,\n", c | w, sp, true); + allPathsForCaps("Liebe Sara, \n ", c | w, sp, false); + allPathsForCaps("Liebe Sara \n ", c | w | s, sp, false); + allPathsForCaps("Liebe Sara.\n ", c | w | s, sp, false); + sp = job.runInLocale(res, Locale.ENGLISH); + allPathsForCaps("Liebe Sara,\n", c | w | s, sp, false); + allPathsForCaps("Liebe Sara,\n", c | w | s, sp, true); + allPathsForCaps("Liebe Sara, \n ", c | w | s, sp, false); + allPathsForCaps("Liebe Sara \n ", c | w | s, sp, false); + allPathsForCaps("Liebe Sara.\n ", c | w | s, sp, false); } } diff --git a/tests/src/com/android/inputmethod/latin/utils/DictionaryInfoUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/DictionaryInfoUtilsTests.java new file mode 100644 index 000000000..6e716074c --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/utils/DictionaryInfoUtilsTests.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin.utils; + +import android.content.res.Resources; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.latin.settings.SpacingAndPunctuations; + +import java.util.Locale; + +@SmallTest +public class DictionaryInfoUtilsTests extends AndroidTestCase { + public void testLooksValidForDictionaryInsertion() { + final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() { + @Override + protected SpacingAndPunctuations job(final Resources res) { + return new SpacingAndPunctuations(res); + } + }; + final Resources res = getContext().getResources(); + final SpacingAndPunctuations sp = job.runInLocale(res, Locale.ENGLISH); + assertTrue(DictionaryInfoUtils.looksValidForDictionaryInsertion("aochaueo", sp)); + assertFalse(DictionaryInfoUtils.looksValidForDictionaryInsertion("", sp)); + assertTrue(DictionaryInfoUtils.looksValidForDictionaryInsertion("ao-ch'aueo", sp)); + assertFalse(DictionaryInfoUtils.looksValidForDictionaryInsertion("2908743256", sp)); + assertTrue(DictionaryInfoUtils.looksValidForDictionaryInsertion("31aochaueo", sp)); + assertFalse(DictionaryInfoUtils.looksValidForDictionaryInsertion("akeo raeoch oerch .", + sp)); + assertFalse(DictionaryInfoUtils.looksValidForDictionaryInsertion("!!!", sp)); + } +} diff --git a/tests/src/com/android/inputmethod/latin/utils/ForgettingCurveTests.java b/tests/src/com/android/inputmethod/latin/utils/ForgettingCurveTests.java deleted file mode 100644 index 823bd5d7d..000000000 --- a/tests/src/com/android/inputmethod/latin/utils/ForgettingCurveTests.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.inputmethod.latin.utils; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -@SmallTest -public class ForgettingCurveTests extends AndroidTestCase { - public void testFcToFreq() { - for (int i = 0; i < Byte.MAX_VALUE; ++i) { - final byte fc = (byte)i; - final int e = UserHistoryForgettingCurveUtils.fcToElapsedTime(fc); - final int c = UserHistoryForgettingCurveUtils.fcToCount(fc); - final int l = UserHistoryForgettingCurveUtils.fcToLevel(fc); - final byte fc2 = UserHistoryForgettingCurveUtils.calcFc(e, c, l); - assertEquals(fc, fc2); - } - byte fc = 0; - int l; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < (UserHistoryForgettingCurveUtils.COUNT_MAX + 1); ++j) { - fc = UserHistoryForgettingCurveUtils.pushCount(fc, true); - } - l = UserHistoryForgettingCurveUtils.fcToLevel(fc); - assertEquals(l, Math.max(1, Math.min(i + 1, 3))); - } - fc = 0; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < (UserHistoryForgettingCurveUtils.COUNT_MAX + 1); ++j) { - fc = UserHistoryForgettingCurveUtils.pushCount(fc, false); - } - l = UserHistoryForgettingCurveUtils.fcToLevel(fc); - assertEquals(l, Math.min(i + 1, 3)); - } - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < (UserHistoryForgettingCurveUtils.ELAPSED_TIME_MAX + 1); ++j) { - fc = UserHistoryForgettingCurveUtils.pushElapsedTime(fc); - } - l = UserHistoryForgettingCurveUtils.fcToLevel(fc); - assertEquals(l, Math.max(0, 2 - i)); - } - } -} diff --git a/tests/src/com/android/inputmethod/latin/utils/RecapitalizeStatusTests.java b/tests/src/com/android/inputmethod/latin/utils/RecapitalizeStatusTests.java index a52041264..ada80c3fa 100644 --- a/tests/src/com/android/inputmethod/latin/utils/RecapitalizeStatusTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/RecapitalizeStatusTests.java @@ -19,31 +19,35 @@ package com.android.inputmethod.latin.utils; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; +import com.android.inputmethod.latin.Constants; + import java.util.Locale; @SmallTest public class RecapitalizeStatusTests extends AndroidTestCase { + private static final int[] SPACE = { Constants.CODE_SPACE }; + public void testTrim() { final RecapitalizeStatus status = new RecapitalizeStatus(); - status.initialize(30, 40, "abcdefghij", Locale.ENGLISH, " "); + status.initialize(30, 40, "abcdefghij", Locale.ENGLISH, SPACE); status.trim(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(40, status.getNewCursorEnd()); - status.initialize(30, 44, " abcdefghij", Locale.ENGLISH, " "); + status.initialize(30, 44, " abcdefghij", Locale.ENGLISH, SPACE); status.trim(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(34, status.getNewCursorStart()); assertEquals(44, status.getNewCursorEnd()); - status.initialize(30, 40, "abcdefgh ", Locale.ENGLISH, " "); + status.initialize(30, 40, "abcdefgh ", Locale.ENGLISH, SPACE); status.trim(); assertEquals("abcdefgh", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(38, status.getNewCursorEnd()); - status.initialize(30, 45, " abcdefghij ", Locale.ENGLISH, " "); + status.initialize(30, 45, " abcdefghij ", Locale.ENGLISH, SPACE); status.trim(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(33, status.getNewCursorStart()); @@ -52,7 +56,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase { public void testRotate() { final RecapitalizeStatus status = new RecapitalizeStatus(); - status.initialize(29, 40, "abcd efghij", Locale.ENGLISH, " "); + status.initialize(29, 40, "abcd efghij", Locale.ENGLISH, SPACE); status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); @@ -64,7 +68,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase { status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); - status.initialize(29, 40, "Abcd Efghij", Locale.ENGLISH, " "); + status.initialize(29, 40, "Abcd Efghij", Locale.ENGLISH, SPACE); status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); @@ -76,7 +80,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase { status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); - status.initialize(29, 40, "ABCD EFGHIJ", Locale.ENGLISH, " "); + status.initialize(29, 40, "ABCD EFGHIJ", Locale.ENGLISH, SPACE); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); @@ -88,7 +92,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase { status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); - status.initialize(29, 39, "AbCDefghij", Locale.ENGLISH, " "); + status.initialize(29, 39, "AbCDefghij", Locale.ENGLISH, SPACE); status.rotate(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); @@ -102,7 +106,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase { status.rotate(); assertEquals("abcdefghij", status.getRecapitalizedString()); - status.initialize(29, 40, "Abcd efghij", Locale.ENGLISH, " "); + status.initialize(29, 40, "Abcd efghij", Locale.ENGLISH, SPACE); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); @@ -116,7 +120,8 @@ public class RecapitalizeStatusTests extends AndroidTestCase { status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); - status.initialize(30, 34, "grüß", Locale.GERMAN, " "); status.rotate(); + status.initialize(30, 34, "grüß", Locale.GERMAN, SPACE); + status.rotate(); assertEquals("Grüß", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(34, status.getNewCursorEnd()); @@ -133,7 +138,8 @@ public class RecapitalizeStatusTests extends AndroidTestCase { assertEquals(30, status.getNewCursorStart()); assertEquals(34, status.getNewCursorEnd()); - status.initialize(30, 33, "œuf", Locale.FRENCH, " "); status.rotate(); + status.initialize(30, 33, "œuf", Locale.FRENCH, SPACE); + status.rotate(); assertEquals("Œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); @@ -150,7 +156,8 @@ public class RecapitalizeStatusTests extends AndroidTestCase { assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); - status.initialize(30, 33, "œUf", Locale.FRENCH, " "); status.rotate(); + status.initialize(30, 33, "œUf", Locale.FRENCH, SPACE); + status.rotate(); assertEquals("œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); @@ -171,7 +178,8 @@ public class RecapitalizeStatusTests extends AndroidTestCase { assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); - status.initialize(30, 35, "école", Locale.FRENCH, " "); status.rotate(); + status.initialize(30, 35, "école", Locale.FRENCH, SPACE); + status.rotate(); assertEquals("École", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(35, status.getNewCursorEnd()); diff --git a/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java b/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java index cad80d5ce..8f58e6873 100644 --- a/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java @@ -39,7 +39,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { int[] array2 = null, array3 = null; final int limit = DEFAULT_CAPACITY * 2 + 10; for (int i = 0; i < limit; i++) { - src.add(i); + final int value = i; + src.add(value); assertEquals("length after add " + i, i + 1, src.getLength()); if (i == DEFAULT_CAPACITY) { array2 = src.getPrimitiveArray(); @@ -56,7 +57,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { } } for (int i = 0; i < limit; i++) { - assertEquals("value at " + i, i, src.get(i)); + final int value = i; + assertEquals("value at " + i, value, src.get(i)); } } @@ -64,11 +66,13 @@ public class ResizableIntArrayTests extends AndroidTestCase { final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY); final int limit = DEFAULT_CAPACITY * 10, step = DEFAULT_CAPACITY * 2; for (int i = 0; i < limit; i += step) { - src.add(i, i); + final int value = i; + src.addAt(i, value); assertEquals("length after add at " + i, i + 1, src.getLength()); } for (int i = 0; i < limit; i += step) { - assertEquals("value at " + i, i, src.get(i)); + final int value = i; + assertEquals("value at " + i, value, src.get(i)); } } @@ -88,9 +92,10 @@ public class ResizableIntArrayTests extends AndroidTestCase { } final int index = DEFAULT_CAPACITY / 2; - src.add(index, 100); + final int valueAddAt = 100; + src.addAt(index, valueAddAt); assertEquals("legth after add at " + index, index + 1, src.getLength()); - assertEquals("value after add at " + index, 100, src.get(index)); + assertEquals("value after add at " + index, valueAddAt, src.get(index)); assertEquals("value after add at 0", 0, src.get(0)); try { final int value = src.get(src.getLength()); @@ -104,7 +109,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY); final int[] array = src.getPrimitiveArray(); for (int i = 0; i < DEFAULT_CAPACITY; i++) { - src.add(i); + final int value = i; + src.add(value); assertEquals("length after add " + i, i + 1, src.getLength()); } @@ -116,7 +122,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { int[] array3 = null; for (int i = 0; i < DEFAULT_CAPACITY; i++) { - src.add(i); + final int value = i; + src.add(value); assertEquals("length after add " + i, i + 1, src.getLength()); if (i == smallerLength) { array3 = src.getPrimitiveArray(); @@ -133,7 +140,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY); final int[] array = src.getPrimitiveArray(); for (int i = 0; i < DEFAULT_CAPACITY; i++) { - src.add(i); + final int value = i; + src.add(value); assertEquals("length after add " + i, i + 1, src.getLength()); } @@ -144,11 +152,11 @@ public class ResizableIntArrayTests extends AndroidTestCase { assertNotSame("array after larger setLength", array, array2); assertEquals("array length after larger setLength", largerLength, array2.length); for (int i = 0; i < largerLength; i++) { - final int v = src.get(i); + final int value = i; if (i < DEFAULT_CAPACITY) { - assertEquals("value at " + i, i, v); + assertEquals("value at " + i, value, src.get(i)); } else { - assertEquals("value at " + i, 0, v); + assertEquals("value at " + i, 0, src.get(i)); } } @@ -159,7 +167,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { assertSame("array after smaller setLength", array2, array3); assertEquals("array length after smaller setLength", largerLength, array3.length); for (int i = 0; i < smallerLength; i++) { - assertEquals("value at " + i, i, src.get(i)); + final int value = i; + assertEquals("value at " + i, value, src.get(i)); } } @@ -167,7 +176,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY); final int limit = DEFAULT_CAPACITY * 2 + 10; for (int i = 0; i < limit; i++) { - src.add(i); + final int value = i; + src.add(value); } final ResizableIntArray dst = new ResizableIntArray(DEFAULT_CAPACITY); @@ -179,7 +189,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { public void testCopy() { final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY); for (int i = 0; i < DEFAULT_CAPACITY; i++) { - src.add(i); + final int value = i; + src.add(value); } final ResizableIntArray dst = new ResizableIntArray(DEFAULT_CAPACITY); @@ -204,119 +215,126 @@ public class ResizableIntArrayTests extends AndroidTestCase { } public void testAppend() { - final int srcLen = DEFAULT_CAPACITY; - final ResizableIntArray src = new ResizableIntArray(srcLen); - for (int i = 0; i < srcLen; i++) { - src.add(i); + final int srcLength = DEFAULT_CAPACITY; + final ResizableIntArray src = new ResizableIntArray(srcLength); + for (int i = 0; i < srcLength; i++) { + final int value = i; + src.add(value); } final ResizableIntArray dst = new ResizableIntArray(DEFAULT_CAPACITY * 2); final int[] array = dst.getPrimitiveArray(); - final int dstLen = DEFAULT_CAPACITY / 2; - for (int i = 0; i < dstLen; i++) { + final int dstLength = DEFAULT_CAPACITY / 2; + for (int i = 0; i < dstLength; i++) { final int value = -i - 1; dst.add(value); } final ResizableIntArray dstCopy = new ResizableIntArray(dst.getLength()); dstCopy.copy(dst); - dst.append(src, 0, 0); - assertEquals("length after append zero", dstLen, dst.getLength()); + final int startPos = 0; + dst.append(src, startPos, 0 /* length */); + assertEquals("length after append zero", dstLength, dst.getLength()); assertSame("array after append zero", array, dst.getPrimitiveArray()); - assertIntArrayEquals("values after append zero", - dstCopy.getPrimitiveArray(), 0, dst.getPrimitiveArray(), 0, dstLen); + assertIntArrayEquals("values after append zero", dstCopy.getPrimitiveArray(), startPos, + dst.getPrimitiveArray(), startPos, dstLength); - dst.append(src, 0, srcLen); - assertEquals("length after append", dstLen + srcLen, dst.getLength()); + dst.append(src, startPos, srcLength); + assertEquals("length after append", dstLength + srcLength, dst.getLength()); assertSame("array after append", array, dst.getPrimitiveArray()); assertTrue("primitive length after append", - dst.getPrimitiveArray().length >= dstLen + srcLen); - assertIntArrayEquals("original values after append", - dstCopy.getPrimitiveArray(), 0, dst.getPrimitiveArray(), 0, dstLen); - assertIntArrayEquals("appended values after append", - src.getPrimitiveArray(), 0, dst.getPrimitiveArray(), dstLen, srcLen); + dst.getPrimitiveArray().length >= dstLength + srcLength); + assertIntArrayEquals("original values after append", dstCopy.getPrimitiveArray(), startPos, + dst.getPrimitiveArray(), startPos, dstLength); + assertIntArrayEquals("appended values after append", src.getPrimitiveArray(), startPos, + dst.getPrimitiveArray(), dstLength, srcLength); - dst.append(src, 0, srcLen); - assertEquals("length after 2nd append", dstLen + srcLen * 2, dst.getLength()); + dst.append(src, startPos, srcLength); + assertEquals("length after 2nd append", dstLength + srcLength * 2, dst.getLength()); assertNotSame("array after 2nd append", array, dst.getPrimitiveArray()); assertTrue("primitive length after 2nd append", - dst.getPrimitiveArray().length >= dstLen + srcLen * 2); + dst.getPrimitiveArray().length >= dstLength + srcLength * 2); assertIntArrayEquals("original values after 2nd append", - dstCopy.getPrimitiveArray(), 0, dst.getPrimitiveArray(), 0, dstLen); + dstCopy.getPrimitiveArray(), startPos, dst.getPrimitiveArray(), startPos, + dstLength); assertIntArrayEquals("appended values after 2nd append", - src.getPrimitiveArray(), 0, dst.getPrimitiveArray(), dstLen, srcLen); + src.getPrimitiveArray(), startPos, dst.getPrimitiveArray(), dstLength, + srcLength); assertIntArrayEquals("appended values after 2nd append", - src.getPrimitiveArray(), 0, dst.getPrimitiveArray(), dstLen + srcLen, srcLen); + src.getPrimitiveArray(), startPos, dst.getPrimitiveArray(), dstLength + srcLength, + srcLength); } public void testFill() { - final int srcLen = DEFAULT_CAPACITY; - final ResizableIntArray src = new ResizableIntArray(srcLen); - for (int i = 0; i < srcLen; i++) { - src.add(i); + final int srcLength = DEFAULT_CAPACITY; + final ResizableIntArray src = new ResizableIntArray(srcLength); + for (int i = 0; i < srcLength; i++) { + final int value = i; + src.add(value); } final int[] array = src.getPrimitiveArray(); - final int startPos = srcLen / 3; - final int length = srcLen / 3; + final int startPos = srcLength / 3; + final int length = srcLength / 3; final int endPos = startPos + length; assertTrue(startPos >= 1); - final int value = 123; + final int fillValue = 123; try { - src.fill(value, -1, length); + src.fill(fillValue, -1 /* startPos */, length); fail("fill from -1 shouldn't succeed"); } catch (IllegalArgumentException e) { // success } try { - src.fill(value, startPos, -1); + src.fill(fillValue, startPos, -1 /* length */); fail("fill negative length shouldn't succeed"); } catch (IllegalArgumentException e) { // success } - src.fill(value, startPos, length); - assertEquals("length after fill", srcLen, src.getLength()); + src.fill(fillValue, startPos, length); + assertEquals("length after fill", srcLength, src.getLength()); assertSame("array after fill", array, src.getPrimitiveArray()); - for (int i = 0; i < srcLen; i++) { - final int v = src.get(i); + for (int i = 0; i < srcLength; i++) { + final int value = i; if (i >= startPos && i < endPos) { - assertEquals("new values after fill at " + i, value, v); + assertEquals("new values after fill at " + i, fillValue, src.get(i)); } else { - assertEquals("unmodified values after fill at " + i, i, v); + assertEquals("unmodified values after fill at " + i, value, src.get(i)); } } - final int length2 = srcLen * 2 - startPos; + final int length2 = srcLength * 2 - startPos; final int largeEnd = startPos + length2; - assertTrue(largeEnd > srcLen); - final int value2 = 456; - src.fill(value2, startPos, length2); + assertTrue(largeEnd > srcLength); + final int fillValue2 = 456; + src.fill(fillValue2, startPos, length2); assertEquals("length after large fill", largeEnd, src.getLength()); assertNotSame("array after large fill", array, src.getPrimitiveArray()); for (int i = 0; i < largeEnd; i++) { - final int v = src.get(i); + final int value = i; if (i >= startPos && i < largeEnd) { - assertEquals("new values after large fill at " + i, value2, v); + assertEquals("new values after large fill at " + i, fillValue2, src.get(i)); } else { - assertEquals("unmodified values after large fill at " + i, i, v); + assertEquals("unmodified values after large fill at " + i, value, src.get(i)); } } final int startPos2 = largeEnd + length2; final int endPos2 = startPos2 + length2; - final int value3 = 789; - src.fill(value3, startPos2, length2); + final int fillValue3 = 789; + src.fill(fillValue3, startPos2, length2); assertEquals("length after disjoint fill", endPos2, src.getLength()); for (int i = 0; i < endPos2; i++) { - final int v = src.get(i); + final int value = i; if (i >= startPos2 && i < endPos2) { - assertEquals("new values after disjoint fill at " + i, value3, v); + assertEquals("new values after disjoint fill at " + i, fillValue3, src.get(i)); } else if (i >= startPos && i < largeEnd) { - assertEquals("unmodified values after disjoint fill at " + i, value2, v); + assertEquals("unmodified values after disjoint fill at " + i, + fillValue2, src.get(i)); } else if (i < startPos) { - assertEquals("unmodified values after disjoint fill at " + i, i, v); + assertEquals("unmodified values after disjoint fill at " + i, value, src.get(i)); } else { - assertEquals("gap values after disjoint fill at " + i, 0, v); + assertEquals("gap values after disjoint fill at " + i, 0, src.get(i)); } } } @@ -346,12 +364,14 @@ public class ResizableIntArrayTests extends AndroidTestCase { final int limit = DEFAULT_CAPACITY * 10; final int shiftAmount = 20; for (int i = 0; i < limit; ++i) { - src.add(i, i); + final int value = i; + src.addAt(i, value); assertEquals("length after add at " + i, i + 1, src.getLength()); } src.shift(shiftAmount); for (int i = 0; i < limit - shiftAmount; ++i) { - assertEquals("value at " + i, i + shiftAmount, src.get(i)); + final int oldValue = i + shiftAmount; + assertEquals("value at " + i, oldValue, src.get(i)); } } } diff --git a/tests/src/com/android/inputmethod/latin/utils/ResourceUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/ResourceUtilsTests.java index 1ae22e307..3eb704093 100644 --- a/tests/src/com/android/inputmethod/latin/utils/ResourceUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/ResourceUtilsTests.java @@ -19,43 +19,10 @@ package com.android.inputmethod.latin.utils; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; -import com.android.inputmethod.latin.utils.ResourceUtils.DeviceOverridePatternSyntaxError; - import java.util.HashMap; @SmallTest public class ResourceUtilsTests extends AndroidTestCase { - public void testFindDefaultConstant() { - final String[] nullArray = null; - final String[] emptyArray = {}; - final String[] array = { - "HARDWARE=grouper,0.3", - "HARDWARE=mako,0.4", - ",defaultValue1", - "HARDWARE=manta,0.2", - ",defaultValue2", - }; - - try { - assertNull(ResourceUtils.findDefaultConstant(nullArray)); - assertNull(ResourceUtils.findDefaultConstant(emptyArray)); - assertEquals(ResourceUtils.findDefaultConstant(array), "defaultValue1"); - } catch (final DeviceOverridePatternSyntaxError e) { - fail(e.getMessage()); - } - - final String[] errorArray = { - "HARDWARE=grouper,0.3", - "no_comma" - }; - try { - final String defaultValue = ResourceUtils.findDefaultConstant(errorArray); - fail("exception should be thrown: defaultValue=" + defaultValue); - } catch (final DeviceOverridePatternSyntaxError e) { - assertEquals("Array element has no comma: no_comma", e.getMessage()); - } - } - public void testFindConstantForKeyValuePairsSimple() { final HashMap<String,String> anyKeyValue = CollectionUtils.newHashMap(); anyKeyValue.put("anyKey", "anyValue"); diff --git a/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java index 4e396a1cf..e55c32bd0 100644 --- a/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java @@ -16,17 +16,17 @@ package com.android.inputmethod.latin.utils; -import com.android.inputmethod.latin.settings.SettingsValues; - import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; +import com.android.inputmethod.latin.Constants; + import java.util.Arrays; import java.util.List; import java.util.Locale; @SmallTest -public class StringUtilsTests extends AndroidTestCase { +public class StringAndJsonUtilsTests extends AndroidTestCase { public void testContainsInArray() { assertFalse("empty array", StringUtils.containsInArray("key", new String[0])); assertFalse("not in 1 element", StringUtils.containsInArray("key", new String[] { @@ -44,7 +44,7 @@ public class StringUtilsTests extends AndroidTestCase { })); } - public void testContainsInExtraValues() { + public void testContainsInCommaSplittableText() { assertFalse("null", StringUtils.containsInCommaSplittableText("key", null)); assertFalse("empty", StringUtils.containsInCommaSplittableText("key", "")); assertFalse("not in 1 element", @@ -56,7 +56,28 @@ public class StringUtilsTests extends AndroidTestCase { assertTrue("in 2 elements", StringUtils.containsInCommaSplittableText("key", "key1,key")); } - public void testAppendToExtraValuesIfNotExists() { + public void testJoinCommaSplittableText() { + assertEquals("2 nulls", "", + StringUtils.joinCommaSplittableText(null, null)); + assertEquals("null and empty", "", + StringUtils.joinCommaSplittableText(null, "")); + assertEquals("empty and null", "", + StringUtils.joinCommaSplittableText("", null)); + assertEquals("2 empties", "", + StringUtils.joinCommaSplittableText("", "")); + assertEquals("text and null", "text", + StringUtils.joinCommaSplittableText("text", null)); + assertEquals("text and empty", "text", + StringUtils.joinCommaSplittableText("text", "")); + assertEquals("null and text", "text", + StringUtils.joinCommaSplittableText(null, "text")); + assertEquals("empty and text", "text", + StringUtils.joinCommaSplittableText("", "text")); + assertEquals("2 texts", "text1,text2", + StringUtils.joinCommaSplittableText("text1", "text2")); + } + + public void testAppendToCommaSplittableTextIfNotExists() { assertEquals("null", "key", StringUtils.appendToCommaSplittableTextIfNotExists("key", null)); assertEquals("empty", "key", @@ -77,7 +98,7 @@ public class StringUtilsTests extends AndroidTestCase { StringUtils.appendToCommaSplittableTextIfNotExists("key", "key1,key,key3")); } - public void testRemoveFromExtraValuesIfExists() { + public void testRemoveFromCommaSplittableTextIfExists() { assertEquals("null", "", StringUtils.removeFromCommaSplittableTextIfExists("key", null)); assertEquals("empty", "", StringUtils.removeFromCommaSplittableTextIfExists("key", "")); @@ -187,54 +208,47 @@ public class StringUtilsTests extends AndroidTestCase { assertTrue(StringUtils.isIdenticalAfterDowncase("")); } - public void testLooksValidForDictionaryInsertion() { - final SettingsValues settings = - SettingsValues.makeDummySettingsValuesForTest(Locale.ENGLISH); - assertTrue(StringUtils.looksValidForDictionaryInsertion("aochaueo", settings)); - assertFalse(StringUtils.looksValidForDictionaryInsertion("", settings)); - assertTrue(StringUtils.looksValidForDictionaryInsertion("ao-ch'aueo", settings)); - assertFalse(StringUtils.looksValidForDictionaryInsertion("2908743256", settings)); - assertTrue(StringUtils.looksValidForDictionaryInsertion("31aochaueo", settings)); - assertFalse(StringUtils.looksValidForDictionaryInsertion("akeo raeoch oerch .", settings)); - assertFalse(StringUtils.looksValidForDictionaryInsertion("!!!", settings)); - } - - private static void checkCapitalize(final String src, final String dst, final String separators, - final Locale locale) { - assertEquals(dst, StringUtils.capitalizeEachWord(src, separators, locale)); + private static void checkCapitalize(final String src, final String dst, + final int[] sortedSeparators, final Locale locale) { + assertEquals(dst, StringUtils.capitalizeEachWord(src, sortedSeparators, locale)); assert(src.equals(dst) - == StringUtils.isIdenticalAfterCapitalizeEachWord(src, separators)); + == StringUtils.isIdenticalAfterCapitalizeEachWord(src, sortedSeparators)); } + private static final int[] SPACE = { Constants.CODE_SPACE }; + private static final int[] SPACE_PERIOD = StringUtils.toSortedCodePointArray(" ."); + private static final int[] SENTENCE_SEPARATORS = + StringUtils.toSortedCodePointArray(" \n.!?*()&"); + private static final int[] WORD_SEPARATORS = StringUtils.toSortedCodePointArray(" \n.!?*,();&"); + public void testCapitalizeEachWord() { - checkCapitalize("", "", " ", Locale.ENGLISH); - checkCapitalize("test", "Test", " ", Locale.ENGLISH); - checkCapitalize(" test", " Test", " ", Locale.ENGLISH); - checkCapitalize("Test", "Test", " ", Locale.ENGLISH); - checkCapitalize(" Test", " Test", " ", Locale.ENGLISH); - checkCapitalize(".Test", ".test", " ", Locale.ENGLISH); - checkCapitalize(".Test", ".Test", " .", Locale.ENGLISH); - checkCapitalize(".Test", ".Test", ". ", Locale.ENGLISH); - checkCapitalize("test and retest", "Test And Retest", " .", Locale.ENGLISH); - checkCapitalize("Test and retest", "Test And Retest", " .", Locale.ENGLISH); - checkCapitalize("Test And Retest", "Test And Retest", " .", Locale.ENGLISH); - checkCapitalize("Test And.Retest ", "Test And.Retest ", " .", Locale.ENGLISH); - checkCapitalize("Test And.retest ", "Test And.Retest ", " .", Locale.ENGLISH); - checkCapitalize("Test And.retest ", "Test And.retest ", " ", Locale.ENGLISH); - checkCapitalize("Test And.Retest ", "Test And.retest ", " ", Locale.ENGLISH); - checkCapitalize("test and ietest", "Test And İetest", " .", new Locale("tr")); - checkCapitalize("test and ietest", "Test And Ietest", " .", Locale.ENGLISH); - checkCapitalize("Test&Retest", "Test&Retest", " \n.!?*()&", Locale.ENGLISH); - checkCapitalize("Test&retest", "Test&Retest", " \n.!?*()&", Locale.ENGLISH); - checkCapitalize("test&Retest", "Test&Retest", " \n.!?*()&", Locale.ENGLISH); + checkCapitalize("", "", SPACE, Locale.ENGLISH); + checkCapitalize("test", "Test", SPACE, Locale.ENGLISH); + checkCapitalize(" test", " Test", SPACE, Locale.ENGLISH); + checkCapitalize("Test", "Test", SPACE, Locale.ENGLISH); + checkCapitalize(" Test", " Test", SPACE, Locale.ENGLISH); + checkCapitalize(".Test", ".test", SPACE, Locale.ENGLISH); + checkCapitalize(".Test", ".Test", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("test and retest", "Test And Retest", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("Test and retest", "Test And Retest", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("Test And Retest", "Test And Retest", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("Test And.Retest ", "Test And.Retest ", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("Test And.retest ", "Test And.Retest ", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("Test And.retest ", "Test And.retest ", SPACE, Locale.ENGLISH); + checkCapitalize("Test And.Retest ", "Test And.retest ", SPACE, Locale.ENGLISH); + checkCapitalize("test and ietest", "Test And İetest", SPACE_PERIOD, new Locale("tr")); + checkCapitalize("test and ietest", "Test And Ietest", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("Test&Retest", "Test&Retest", SENTENCE_SEPARATORS, Locale.ENGLISH); + checkCapitalize("Test&retest", "Test&Retest", SENTENCE_SEPARATORS, Locale.ENGLISH); + checkCapitalize("test&Retest", "Test&Retest", SENTENCE_SEPARATORS, Locale.ENGLISH); checkCapitalize("rest\nrecreation! And in the end...", - "Rest\nRecreation! And In The End...", " \n.!?*,();&", Locale.ENGLISH); + "Rest\nRecreation! And In The End...", WORD_SEPARATORS, Locale.ENGLISH); checkCapitalize("lorem ipsum dolor sit amet", "Lorem Ipsum Dolor Sit Amet", - " \n.,!?*()&;", Locale.ENGLISH); + WORD_SEPARATORS, Locale.ENGLISH); checkCapitalize("Lorem!Ipsum (Dolor) Sit * Amet", "Lorem!Ipsum (Dolor) Sit * Amet", - " \n,.;!?*()&", Locale.ENGLISH); + WORD_SEPARATORS, Locale.ENGLISH); checkCapitalize("Lorem!Ipsum (dolor) Sit * Amet", "Lorem!Ipsum (Dolor) Sit * Amet", - " \n,.;!?*()&", Locale.ENGLISH); + WORD_SEPARATORS, Locale.ENGLISH); } public void testLooksLikeURL() { @@ -271,11 +285,25 @@ public class StringUtilsTests extends AndroidTestCase { assertTrue(bytesStr.equals(bytesStr2)); } - public void testJsonStringUtils() { + public void testContainsOnlyWhitespace() { + assertTrue(StringUtils.containsOnlyWhitespace(" ")); + assertTrue(StringUtils.containsOnlyWhitespace("")); + assertTrue(StringUtils.containsOnlyWhitespace(" \n\t\t")); + // U+2002 : EN SPACE + // U+2003 : EM SPACE + // U+3000 : IDEOGRAPHIC SPACE (commonly "double-width space") + assertTrue(StringUtils.containsOnlyWhitespace("\u2002\u2003\u3000")); + assertFalse(StringUtils.containsOnlyWhitespace(" a ")); + assertFalse(StringUtils.containsOnlyWhitespace(". ")); + assertFalse(StringUtils.containsOnlyWhitespace(".")); + assertTrue(StringUtils.containsOnlyWhitespace("")); + } + + public void testJsonUtils() { final Object[] objs = new Object[] { 1, "aaa", "bbb", 3 }; final List<Object> objArray = Arrays.asList(objs); - final String str = StringUtils.listToJsonStr(objArray); - final List<Object> newObjArray = StringUtils.jsonStrToList(str); + final String str = JsonUtils.listToJsonStr(objArray); + final List<Object> newObjArray = JsonUtils.jsonStrToList(str); for (int i = 0; i < objs.length; ++i) { assertEquals(objs[i], newObjArray.get(i)); } diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java index 856b2dbda..25f57eba6 100644 --- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java @@ -20,9 +20,9 @@ import android.content.Context; import android.content.res.Resources; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; +import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; -import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; import java.util.ArrayList; @@ -30,7 +30,7 @@ import java.util.Locale; @SmallTest public class SubtypeLocaleUtilsTests extends AndroidTestCase { - // Locale to subtypes list. + // All input method subtypes of LatinIME. private final ArrayList<InputMethodSubtype> mSubtypesList = CollectionUtils.newArrayList(); private RichInputMethodManager mRichImm; @@ -41,7 +41,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { InputMethodSubtype ES_US; InputMethodSubtype FR; InputMethodSubtype FR_CA; + InputMethodSubtype FR_CH; InputMethodSubtype DE; + InputMethodSubtype DE_CH; InputMethodSubtype ZZ; InputMethodSubtype DE_QWERTY; InputMethodSubtype FR_QWERTZ; @@ -60,6 +62,13 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { mRes = context.getResources(); SubtypeLocaleUtils.init(context); + final InputMethodInfo imi = mRichImm.getInputMethodInfoOfThisIme(); + final int subtypeCount = imi.getSubtypeCount(); + for (int index = 0; index < subtypeCount; index++) { + final InputMethodSubtype subtype = imi.getSubtypeAt(index); + mSubtypesList.add(subtype); + } + EN_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( Locale.US.toString(), "qwerty"); EN_GB = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( @@ -70,8 +79,12 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { Locale.FRENCH.toString(), "azerty"); FR_CA = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( Locale.CANADA_FRENCH.toString(), "qwerty"); + FR_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "fr_CH", "swiss"); DE = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( Locale.GERMAN.toString(), "qwertz"); + DE_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "de_CH", "swiss"); ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( SubtypeLocaleUtils.NO_LANGUAGE, "qwerty"); DE_QWERTY = AdditionalSubtypeUtils.createAdditionalSubtype( @@ -88,19 +101,19 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.NO_LANGUAGE, "azerty", null); ZZ_PC = AdditionalSubtypeUtils.createAdditionalSubtype( SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty", null); - } public void testAllFullDisplayName() { for (final InputMethodSubtype subtype : mSubtypesList) { - final String subtypeName = - SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype); + final String subtypeName = SubtypeLocaleUtils + .getSubtypeDisplayNameInSystemLocale(subtype); if (SubtypeLocaleUtils.isNoLanguage(subtype)) { - final String noLanguage = mRes.getString(R.string.subtype_no_language); - assertTrue(subtypeName, subtypeName.contains(noLanguage)); + final String layoutName = SubtypeLocaleUtils + .getKeyboardLayoutSetDisplayName(subtype); + assertTrue(subtypeName, subtypeName.contains(layoutName)); } else { - final String languageName = - SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale()); + final String languageName = SubtypeLocaleUtils + .getSubtypeLocaleDisplayNameInSystemLocale(subtype.getLocale()); assertTrue(subtypeName, subtypeName.contains(languageName)); } } @@ -112,7 +125,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { assertEquals("es_US", "spanish", SubtypeLocaleUtils.getKeyboardLayoutSetName(ES_US)); assertEquals("fr ", "azerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR)); assertEquals("fr_CA", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_CA)); + assertEquals("fr_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_CH)); assertEquals("de ", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE)); + assertEquals("de_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE_CH)); assertEquals("zz ", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ)); } @@ -125,7 +140,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { // es_US spanish F Spanish (US) exception // fr azerty F French // fr_CA qwerty F French (Canada) + // fr_CH swiss F French (Switzerland) // de qwertz F German + // de_CH swiss F German (Switzerland) // zz qwerty F Alphabet (QWERTY) // fr qwertz T French (QWERTZ) // de qwerty T German (QWERTY) @@ -148,8 +165,12 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR)); assertEquals("fr_CA", "French (Canada)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CA)); + assertEquals("fr_CH", "French (Switzerland)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CH)); assertEquals("de ", "German", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE)); + assertEquals("de_CH", "German (Switzerland)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH)); assertEquals("zz ", "Alphabet (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ)); return null; @@ -189,7 +210,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { // es_US spanish F Espagnol (États-Unis) exception // fr azerty F Français // fr_CA qwerty F Français (Canada) + // fr_CH swiss F Français (Suisse) // de qwertz F Allemand + // de_CH swiss F Allemand (Suisse) // zz qwerty F Aucune langue (QWERTY) // fr qwertz T Français (QWERTZ) // de qwerty T Allemand (QWERTY) @@ -212,8 +235,12 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR)); assertEquals("fr_CA", "Français (Canada)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CA)); + assertEquals("fr_CH", "Français (Suisse)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CH)); assertEquals("de ", "Allemand", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE)); + assertEquals("de_CH", "Allemand (Suisse)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH)); assertEquals("zz ", "Alphabet latin (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ)); return null; @@ -246,11 +273,11 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { public void testAllFullDisplayNameForSpacebar() { for (final InputMethodSubtype subtype : mSubtypesList) { - final String subtypeName = - SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype); + final String subtypeName = SubtypeLocaleUtils + .getSubtypeDisplayNameInSystemLocale(subtype); final String spacebarText = SubtypeLocaleUtils.getFullDisplayName(subtype); - final String languageName = - SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale()); + final String languageName = SubtypeLocaleUtils + .getSubtypeLocaleDisplayName(subtype.getLocale()); if (SubtypeLocaleUtils.isNoLanguage(subtype)) { assertFalse(subtypeName, spacebarText.contains(languageName)); } else { @@ -261,15 +288,16 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { public void testAllMiddleDisplayNameForSpacebar() { for (final InputMethodSubtype subtype : mSubtypesList) { - final String subtypeName = - SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype); + final String subtypeName = SubtypeLocaleUtils + .getSubtypeDisplayNameInSystemLocale(subtype); final String spacebarText = SubtypeLocaleUtils.getMiddleDisplayName(subtype); if (SubtypeLocaleUtils.isNoLanguage(subtype)) { assertEquals(subtypeName, - SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype), spacebarText); + SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype), spacebarText); } else { + final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype); assertEquals(subtypeName, - SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale()), + SubtypeLocaleUtils.getSubtypeLocaleDisplayName(locale.getLanguage()), spacebarText); } } @@ -277,8 +305,8 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { public void testAllShortDisplayNameForSpacebar() { for (final InputMethodSubtype subtype : mSubtypesList) { - final String subtypeName = - SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype); + final String subtypeName = SubtypeLocaleUtils + .getSubtypeDisplayNameInSystemLocale(subtype); final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype); final String spacebarText = SubtypeLocaleUtils.getShortDisplayName(subtype); final String languageCode = StringUtils.capitalizeFirstCodePoint( @@ -300,7 +328,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { // es_US spanish F Es Español Español (EE.UU.) exception // fr azerty F Fr Français Français // fr_CA qwerty F Fr Français Français (Canada) + // fr_CH swiss F Fr Français Français (Suisse) // de qwertz F De Deutsch Deutsch + // de_CH swiss F De Deutsch Deutsch (Schweiz) // zz qwerty F QWERTY QWERTY // fr qwertz T Fr Français Français // de qwerty T De Deutsch Deutsch @@ -317,7 +347,11 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { assertEquals("fr ", "Français", SubtypeLocaleUtils.getFullDisplayName(FR)); assertEquals("fr_CA", "Français (Canada)", SubtypeLocaleUtils.getFullDisplayName(FR_CA)); + assertEquals("fr_CH", "Français (Suisse)", + SubtypeLocaleUtils.getFullDisplayName(FR_CH)); assertEquals("de ", "Deutsch", SubtypeLocaleUtils.getFullDisplayName(DE)); + assertEquals("de_CH", "Deutsch (Schweiz)", + SubtypeLocaleUtils.getFullDisplayName(DE_CH)); assertEquals("zz ", "QWERTY", SubtypeLocaleUtils.getFullDisplayName(ZZ)); assertEquals("en_US", "English", SubtypeLocaleUtils.getMiddleDisplayName(EN_US)); @@ -325,7 +359,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { assertEquals("es_US", "Español", SubtypeLocaleUtils.getMiddleDisplayName(ES_US)); assertEquals("fr ", "Français", SubtypeLocaleUtils.getMiddleDisplayName(FR)); assertEquals("fr_CA", "Français", SubtypeLocaleUtils.getMiddleDisplayName(FR_CA)); + assertEquals("fr_CH", "Français", SubtypeLocaleUtils.getMiddleDisplayName(FR_CH)); assertEquals("de ", "Deutsch", SubtypeLocaleUtils.getMiddleDisplayName(DE)); + assertEquals("de_CH", "Deutsch", SubtypeLocaleUtils.getMiddleDisplayName(DE_CH)); assertEquals("zz ", "QWERTY", SubtypeLocaleUtils.getMiddleDisplayName(ZZ)); assertEquals("en_US", "En", SubtypeLocaleUtils.getShortDisplayName(EN_US)); @@ -333,7 +369,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { assertEquals("es_US", "Es", SubtypeLocaleUtils.getShortDisplayName(ES_US)); assertEquals("fr ", "Fr", SubtypeLocaleUtils.getShortDisplayName(FR)); assertEquals("fr_CA", "Fr", SubtypeLocaleUtils.getShortDisplayName(FR_CA)); + assertEquals("fr_CH", "Fr", SubtypeLocaleUtils.getShortDisplayName(FR_CH)); assertEquals("de ", "De", SubtypeLocaleUtils.getShortDisplayName(DE)); + assertEquals("de_CH", "De", SubtypeLocaleUtils.getShortDisplayName(DE_CH)); assertEquals("zz ", "", SubtypeLocaleUtils.getShortDisplayName(ZZ)); return null; } @@ -384,4 +422,27 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { public void testAdditionalSubtypeForSpacebarInFrench() { testsAdditionalSubtypesForSpacebar.runInLocale(mRes, Locale.FRENCH); } + + public void testIsRtlLanguage() { + // Known Right-to-Left language subtypes. + final InputMethodSubtype ARABIC = mRichImm + .findSubtypeByLocaleAndKeyboardLayoutSet("ar", "arabic"); + assertNotNull("Arabic", ARABIC); + final InputMethodSubtype FARSI = mRichImm + .findSubtypeByLocaleAndKeyboardLayoutSet("fa", "farsi"); + assertNotNull("Farsi", FARSI); + final InputMethodSubtype HEBREW = mRichImm + .findSubtypeByLocaleAndKeyboardLayoutSet("iw", "hebrew"); + assertNotNull("Hebrew", HEBREW); + + for (final InputMethodSubtype subtype : mSubtypesList) { + final String subtypeName = SubtypeLocaleUtils + .getSubtypeDisplayNameInSystemLocale(subtype); + if (subtype.equals(ARABIC) || subtype.equals(FARSI) || subtype.equals(HEBREW)) { + assertTrue(subtypeName, SubtypeLocaleUtils.isRtlLanguage(subtype)); + } else { + assertFalse(subtypeName, SubtypeLocaleUtils.isRtlLanguage(subtype)); + } + } + } } diff --git a/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java deleted file mode 100644 index 1944fd332..000000000 --- a/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.inputmethod.latin.utils; - -import android.content.Context; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; - -import com.android.inputmethod.latin.makedict.DictDecoder; -import com.android.inputmethod.latin.makedict.DictEncoder; -import com.android.inputmethod.latin.makedict.FormatSpec; -import com.android.inputmethod.latin.makedict.FusionDictionary; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; -import com.android.inputmethod.latin.makedict.Ver3DictDecoder; -import com.android.inputmethod.latin.makedict.Ver3DictEncoder; -import com.android.inputmethod.latin.personalization.UserHistoryDictionaryBigramList; -import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.BigramDictionaryInterface; -import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.OnAddWordListener; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; - -/** - * Unit tests for UserHistoryDictIOUtils - */ -@LargeTest -public class UserHistoryDictIOUtilsTests extends AndroidTestCase - implements BigramDictionaryInterface { - - private static final String TAG = UserHistoryDictIOUtilsTests.class.getSimpleName(); - private static final int UNIGRAM_FREQUENCY = 50; - private static final int BIGRAM_FREQUENCY = 100; - private static final ArrayList<String> NOT_HAVE_BIGRAM = new ArrayList<String>(); - private static final FormatSpec.FormatOptions FORMAT_OPTIONS = new FormatSpec.FormatOptions(2); - private static final String TEST_DICT_FILE_EXTENSION = ".testDict"; - - /** - * Return same frequency for all words and bigrams - */ - @Override - public int getFrequency(String word1, String word2) { - if (word1 == null) return UNIGRAM_FREQUENCY; - return BIGRAM_FREQUENCY; - } - - // Utilities for Testing - - private void addWord(final String word, - final HashMap<String, ArrayList<String> > addedWords) { - if (!addedWords.containsKey(word)) { - addedWords.put(word, new ArrayList<String>()); - } - } - - private void addBigram(final String word1, final String word2, - final HashMap<String, ArrayList<String> > addedWords) { - addWord(word1, addedWords); - addWord(word2, addedWords); - addedWords.get(word1).add(word2); - } - - private void addBigramToBigramList(final String word1, final String word2, - final HashMap<String, ArrayList<String> > addedWords, - final UserHistoryDictionaryBigramList bigramList) { - bigramList.addBigram(null, word1); - bigramList.addBigram(word1, word2); - - addBigram(word1, word2, addedWords); - } - - private void checkWordInFusionDict(final FusionDictionary dict, final String word, - final ArrayList<String> expectedBigrams) { - final PtNode ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray, word); - assertNotNull(ptNode); - assertTrue(ptNode.isTerminal()); - - for (final String bigram : expectedBigrams) { - assertNotNull(ptNode.getBigram(bigram)); - } - } - - private void checkWordsInFusionDict(final FusionDictionary dict, - final HashMap<String, ArrayList<String> > bigrams) { - for (final String word : bigrams.keySet()) { - if (bigrams.containsKey(word)) { - checkWordInFusionDict(dict, word, bigrams.get(word)); - } else { - checkWordInFusionDict(dict, word, NOT_HAVE_BIGRAM); - } - } - } - - private void checkWordInBigramList( - final UserHistoryDictionaryBigramList bigramList, final String word, - final ArrayList<String> expectedBigrams) { - // check unigram - final HashMap<String,Byte> unigramMap = bigramList.getBigrams(null); - assertTrue(unigramMap.containsKey(word)); - - // check bigrams - final ArrayList<String> actualBigrams = new ArrayList<String>( - bigramList.getBigrams(word).keySet()); - - Collections.sort(expectedBigrams); - Collections.sort(actualBigrams); - assertEquals(expectedBigrams, actualBigrams); - } - - private void checkWordsInBigramList(final UserHistoryDictionaryBigramList bigramList, - final HashMap<String, ArrayList<String> > addedWords) { - for (final String word : addedWords.keySet()) { - if (addedWords.containsKey(word)) { - checkWordInBigramList(bigramList, word, addedWords.get(word)); - } else { - checkWordInBigramList(bigramList, word, NOT_HAVE_BIGRAM); - } - } - } - - private void writeDictToFile(final File file, - final UserHistoryDictionaryBigramList bigramList) { - final DictEncoder dictEncoder = new Ver3DictEncoder(file); - UserHistoryDictIOUtils.writeDictionary(dictEncoder, this, bigramList, FORMAT_OPTIONS); - } - - private void readDictFromFile(final File file, final OnAddWordListener listener) { - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file, DictDecoder.USE_BYTEARRAY); - try { - dictDecoder.openDictBuffer(); - } catch (FileNotFoundException e) { - Log.e(TAG, "file not found", e); - } catch (IOException e) { - Log.e(TAG, "IOException", e); - } - UserHistoryDictIOUtils.readDictionaryBinary(dictDecoder, listener); - } - - public void testGenerateFusionDictionary() { - final UserHistoryDictionaryBigramList originalList = new UserHistoryDictionaryBigramList(); - - final HashMap<String, ArrayList<String> > addedWords = - new HashMap<String, ArrayList<String>>(); - addBigramToBigramList("this", "is", addedWords, originalList); - addBigramToBigramList("this", "was", addedWords, originalList); - addBigramToBigramList("hello", "world", addedWords, originalList); - - final FusionDictionary fusionDict = - UserHistoryDictIOUtils.constructFusionDictionary(this, originalList); - - checkWordsInFusionDict(fusionDict, addedWords); - } - - public void testReadAndWrite() { - final Context context = getContext(); - - File file = null; - try { - file = File.createTempFile("testReadAndWrite", TEST_DICT_FILE_EXTENSION, - getContext().getCacheDir()); - } catch (IOException e) { - Log.d(TAG, "IOException while creating a temporary file", e); - } - assertNotNull(file); - - // make original dictionary - final UserHistoryDictionaryBigramList originalList = new UserHistoryDictionaryBigramList(); - final HashMap<String, ArrayList<String>> addedWords = CollectionUtils.newHashMap(); - addBigramToBigramList("this" , "is" , addedWords, originalList); - addBigramToBigramList("this" , "was" , addedWords, originalList); - addBigramToBigramList("is" , "not" , addedWords, originalList); - addBigramToBigramList("hello", "world", addedWords, originalList); - - // write to file - writeDictToFile(file, originalList); - - // make result dict. - final UserHistoryDictionaryBigramList resultList = new UserHistoryDictionaryBigramList(); - final OnAddWordListener listener = new OnAddWordListener() { - @Override - public void setUnigram(final String word, final String shortcutTarget, - final int frequency, final int shortcutFreq) { - Log.d(TAG, "in: setUnigram: " + word + "," + frequency); - resultList.addBigram(null, word, (byte)frequency); - } - @Override - public void setBigram(final String word1, final String word2, final int frequency) { - Log.d(TAG, "in: setBigram: " + word1 + "," + word2 + "," + frequency); - resultList.addBigram(word1, word2, (byte)frequency); - } - }; - - // load from file - readDictFromFile(file, listener); - checkWordsInBigramList(resultList, addedWords); - - // add new bigram - addBigramToBigramList("hello", "java", addedWords, resultList); - - // rewrite - writeDictToFile(file, resultList); - final UserHistoryDictionaryBigramList resultList2 = new UserHistoryDictionaryBigramList(); - final OnAddWordListener listener2 = new OnAddWordListener() { - @Override - public void setUnigram(final String word, final String shortcutTarget, - final int frequency, final int shortcutFreq) { - Log.d(TAG, "in: setUnigram: " + word + "," + frequency); - resultList2.addBigram(null, word, (byte)frequency); - } - @Override - public void setBigram(final String word1, final String word2, final int frequency) { - Log.d(TAG, "in: setBigram: " + word1 + "," + word2 + "," + frequency); - resultList2.addBigram(word1, word2, (byte)frequency); - } - }; - - // load from file - readDictFromFile(file, listener2); - checkWordsInBigramList(resultList2, addedWords); - } -} |