aboutsummaryrefslogtreecommitdiffstats
path: root/tests/src/org/kelar/inputmethod/latin/utils
diff options
context:
space:
mode:
authorAmin Bandali <bandali@kelar.org>2024-12-16 21:45:41 -0500
committerAmin Bandali <bandali@kelar.org>2025-01-11 14:17:35 -0500
commite9a0e66716dab4dd3184d009d8920de1961efdfa (patch)
tree02dcc096643d74645bf28459c2834c3d4a2ad7f2 /tests/src/org/kelar/inputmethod/latin/utils
parentfb3b9360d70596d7e921de8bf7d3ca99564a077e (diff)
downloadlatinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.tar.gz
latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.tar.xz
latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.zip
Rename to Kelar Keyboard (org.kelar.inputmethod.latin)
Diffstat (limited to 'tests/src/org/kelar/inputmethod/latin/utils')
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/AdditionalSubtypeUtilsTests.java185
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/AsyncResultHolderTests.java84
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/ByteArrayDictBuffer.java81
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/CapsModeUtilsTests.java162
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/CollectionUtilsTests.java104
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/DictionaryInfoUtilsTests.java77
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/ExecutorUtilsTests.java65
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/ImportantNoticeUtilsTests.java135
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/JsonUtilsTests.java43
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/LanguageOnSpacebarUtilsTests.java227
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/RecapitalizeStatusTests.java207
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/ResourceUtilsTests.java163
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/SpannableStringUtilsTests.java244
-rw-r--r--tests/src/org/kelar/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java498
14 files changed, 2275 insertions, 0 deletions
diff --git a/tests/src/org/kelar/inputmethod/latin/utils/AdditionalSubtypeUtilsTests.java b/tests/src/org/kelar/inputmethod/latin/utils/AdditionalSubtypeUtilsTests.java
new file mode 100644
index 000000000..7c929c7a1
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/AdditionalSubtypeUtilsTests.java
@@ -0,0 +1,185 @@
+/*
+ * 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 org.kelar.inputmethod.latin.utils;
+
+import static org.kelar.inputmethod.latin.common.Constants.Subtype.ExtraValue.ASCII_CAPABLE;
+import static org.kelar.inputmethod.latin.common.Constants.Subtype.ExtraValue.EMOJI_CAPABLE;
+import static org.kelar.inputmethod.latin.common.Constants.Subtype.ExtraValue.IS_ADDITIONAL_SUBTYPE;
+import static org.kelar.inputmethod.latin.common.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
+import static org.kelar.inputmethod.latin.common.Constants.Subtype.ExtraValue.UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME;
+import static org.kelar.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.Build;
+import android.view.inputmethod.InputMethodSubtype;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.kelar.inputmethod.compat.InputMethodSubtypeCompatUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AdditionalSubtypeUtilsTests {
+
+ /**
+ * Predictable subtype ID for en_US dvorak layout. This is actually a hash code calculated as
+ * follows.
+ * <code>
+ * final boolean isAuxiliary = false;
+ * final boolean overrideImplicitlyEnabledSubtype = false;
+ * final int SUBTYPE_ID_EN_US_DVORAK = Arrays.hashCode(new Object[] {
+ * "en_US",
+ * "keyboard",
+ * "KeyboardLayoutSet=dvorak"
+ * + ",AsciiCapable"
+ * + ",UntranslatableReplacementStringInSubtypeName=Dvorak"
+ * + ",EmojiCapable"
+ * + ",isAdditionalSubtype",
+ * isAuxiliary,
+ * overrideImplicitlyEnabledSubtype });
+ * </code>
+ */
+ private static int SUBTYPE_ID_EN_US_DVORAK = 0xb3c0cc56;
+ private static String EXTRA_VALUE_EN_US_DVORAK_ICS =
+ "KeyboardLayoutSet=dvorak" +
+ ",AsciiCapable" +
+ ",isAdditionalSubtype";
+ private static String EXTRA_VALUE_EN_US_DVORAK_JELLY_BEAN =
+ "KeyboardLayoutSet=dvorak" +
+ ",AsciiCapable" +
+ ",UntranslatableReplacementStringInSubtypeName=Dvorak" +
+ ",isAdditionalSubtype";
+ private static String EXTRA_VALUE_EN_US_DVORAK_KITKAT =
+ "KeyboardLayoutSet=dvorak" +
+ ",AsciiCapable" +
+ ",UntranslatableReplacementStringInSubtypeName=Dvorak" +
+ ",EmojiCapable" +
+ ",isAdditionalSubtype";
+
+ /**
+ * Predictable subtype ID for azerty layout. This is actually a hash code calculated as follows.
+ * <code>
+ * final boolean isAuxiliary = false;
+ * final boolean overrideImplicitlyEnabledSubtype = false;
+ * final int SUBTYPE_ID_ZZ_AZERTY = Arrays.hashCode(new Object[] {
+ * "zz",
+ * "keyboard",
+ * "KeyboardLayoutSet=azerty"
+ * + ",AsciiCapable"
+ * + ",EmojiCapable"
+ * + ",isAdditionalSubtype",
+ * isAuxiliary,
+ * overrideImplicitlyEnabledSubtype });
+ * </code>
+ */
+ private static int SUBTYPE_ID_ZZ_AZERTY = 0x5b6be697;
+ private static String EXTRA_VALUE_ZZ_AZERTY_ICS =
+ "KeyboardLayoutSet=azerty" +
+ ",AsciiCapable" +
+ ",isAdditionalSubtype";
+ private static String EXTRA_VALUE_ZZ_AZERTY_KITKAT =
+ "KeyboardLayoutSet=azerty" +
+ ",AsciiCapable" +
+ ",EmojiCapable" +
+ ",isAdditionalSubtype";
+
+ @Before
+ public void setUp() throws Exception {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ SubtypeLocaleUtils.init(context);
+ }
+
+ private static void assertEnUsDvorak(InputMethodSubtype subtype) {
+ assertEquals("en_US", subtype.getLocale());
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ assertEquals(EXTRA_VALUE_EN_US_DVORAK_KITKAT, subtype.getExtraValue());
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ assertEquals(EXTRA_VALUE_EN_US_DVORAK_JELLY_BEAN, subtype.getExtraValue());
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ assertEquals(EXTRA_VALUE_EN_US_DVORAK_ICS, subtype.getExtraValue());
+ }
+ assertTrue(subtype.containsExtraValueKey(ASCII_CAPABLE));
+ assertTrue(InputMethodSubtypeCompatUtils.isAsciiCapable(subtype));
+ // TODO: Enable following test
+ // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ // assertTrue(InputMethodSubtypeCompatUtils.isAsciiCapableWithAPI(subtype));
+ // }
+ assertTrue(subtype.containsExtraValueKey(EMOJI_CAPABLE));
+ assertTrue(subtype.containsExtraValueKey(IS_ADDITIONAL_SUBTYPE));
+ assertEquals("dvorak", subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET));
+ assertEquals("Dvorak", subtype.getExtraValueOf(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME));
+ assertEquals(KEYBOARD_MODE, subtype.getMode());
+ assertEquals(SUBTYPE_ID_EN_US_DVORAK, subtype.hashCode());
+ }
+
+ private static void assertAzerty(InputMethodSubtype subtype) {
+ assertEquals("zz", subtype.getLocale());
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ assertEquals(EXTRA_VALUE_ZZ_AZERTY_KITKAT, subtype.getExtraValue());
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ assertEquals(EXTRA_VALUE_ZZ_AZERTY_ICS, subtype.getExtraValue());
+ }
+ assertTrue(subtype.containsExtraValueKey(ASCII_CAPABLE));
+ assertTrue(InputMethodSubtypeCompatUtils.isAsciiCapable(subtype));
+ // TODO: Enable following test
+ // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ // assertTrue(InputMethodSubtypeCompatUtils.isAsciiCapableWithAPI(subtype));
+ // }
+ assertTrue(subtype.containsExtraValueKey(EMOJI_CAPABLE));
+ assertTrue(subtype.containsExtraValueKey(IS_ADDITIONAL_SUBTYPE));
+ assertEquals("azerty", subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET));
+ assertFalse(subtype.containsExtraValueKey(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME));
+ assertEquals(KEYBOARD_MODE, subtype.getMode());
+ assertEquals(SUBTYPE_ID_ZZ_AZERTY, subtype.hashCode());
+ }
+
+ @Test
+ public void testRestorable() {
+ final InputMethodSubtype EN_US_DVORAK =
+ AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.US.toString(), "dvorak");
+ final InputMethodSubtype ZZ_AZERTY =
+ AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ SubtypeLocaleUtils.NO_LANGUAGE, "azerty");
+ assertEnUsDvorak(EN_US_DVORAK);
+ assertAzerty(ZZ_AZERTY);
+
+ // Make sure the subtype can be stored and restored in a deterministic manner.
+ final InputMethodSubtype[] subtypes = { EN_US_DVORAK, ZZ_AZERTY };
+ final String prefSubtype = AdditionalSubtypeUtils.createPrefSubtypes(subtypes);
+ final InputMethodSubtype[] restoredSubtypes =
+ AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefSubtype);
+ assertEquals(2, restoredSubtypes.length);
+ final InputMethodSubtype restored_EN_US_DVORAK = restoredSubtypes[0];
+ final InputMethodSubtype restored_ZZ_AZERTY = restoredSubtypes[1];
+
+ assertEnUsDvorak(restored_EN_US_DVORAK);
+ assertAzerty(restored_ZZ_AZERTY);
+ }
+}
diff --git a/tests/src/org/kelar/inputmethod/latin/utils/AsyncResultHolderTests.java b/tests/src/org/kelar/inputmethod/latin/utils/AsyncResultHolderTests.java
new file mode 100644
index 000000000..b85e4f38c
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/AsyncResultHolderTests.java
@@ -0,0 +1,84 @@
+/*
+ * 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 org.kelar.inputmethod.latin.utils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.util.Log;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AsyncResultHolderTests {
+ static final String TAG = AsyncResultHolderTests.class.getSimpleName();
+
+ private static final int TIMEOUT_IN_MILLISECONDS = 500;
+ private static final int MARGIN_IN_MILLISECONDS = 250;
+ private static final int DEFAULT_VALUE = 2;
+ private static final int SET_VALUE = 1;
+
+ private static <T> void setAfterGivenTime(final AsyncResultHolder<T> holder, final T value,
+ final long time) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(time);
+ } catch (InterruptedException e) {
+ Log.d(TAG, "Exception while sleeping", e);
+ }
+ holder.set(value);
+ }
+ }).start();
+ }
+
+ @Test
+ public void testGetWithoutSet() {
+ final AsyncResultHolder<Integer> holder = new AsyncResultHolder<>("Test");
+ final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
+ assertEquals(DEFAULT_VALUE, resultValue);
+ }
+
+ @Test
+ public void testGetBeforeSet() {
+ final AsyncResultHolder<Integer> holder = new AsyncResultHolder<>("Test");
+ setAfterGivenTime(holder, SET_VALUE, TIMEOUT_IN_MILLISECONDS + MARGIN_IN_MILLISECONDS);
+ final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
+ assertEquals(DEFAULT_VALUE, resultValue);
+ }
+
+ @Test
+ public void testGetAfterSet() {
+ final AsyncResultHolder<Integer> holder = new AsyncResultHolder<>("Test");
+ holder.set(SET_VALUE);
+ final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
+ assertEquals(SET_VALUE, resultValue);
+ }
+
+ @Test
+ public void testGetBeforeTimeout() {
+ final AsyncResultHolder<Integer> holder = new AsyncResultHolder<>("Test");
+ setAfterGivenTime(holder, SET_VALUE, TIMEOUT_IN_MILLISECONDS - MARGIN_IN_MILLISECONDS);
+ final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
+ assertEquals(SET_VALUE, resultValue);
+ }
+}
diff --git a/tests/src/org/kelar/inputmethod/latin/utils/ByteArrayDictBuffer.java b/tests/src/org/kelar/inputmethod/latin/utils/ByteArrayDictBuffer.java
new file mode 100644
index 000000000..6c0854824
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/ByteArrayDictBuffer.java
@@ -0,0 +1,81 @@
+/*
+ * 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 org.kelar.inputmethod.latin.utils;
+
+import org.kelar.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
+
+/**
+ * This class provides an implementation for the FusionDictionary buffer interface that is backed
+ * by a simpled byte array. It allows to create a binary dictionary in memory.
+ */
+public final class ByteArrayDictBuffer implements DictBuffer {
+ private byte[] mBuffer;
+ private int mPosition;
+
+ public ByteArrayDictBuffer(final byte[] buffer) {
+ mBuffer = buffer;
+ mPosition = 0;
+ }
+
+ @Override
+ public int readUnsignedByte() {
+ return mBuffer[mPosition++] & 0xFF;
+ }
+
+ @Override
+ public int readUnsignedShort() {
+ final int retval = readUnsignedByte();
+ return (retval << 8) + readUnsignedByte();
+ }
+
+ @Override
+ public int readUnsignedInt24() {
+ final int retval = readUnsignedShort();
+ return (retval << 8) + readUnsignedByte();
+ }
+
+ @Override
+ public int readInt() {
+ final int retval = readUnsignedShort();
+ return (retval << 16) + readUnsignedShort();
+ }
+
+ @Override
+ public int position() {
+ return mPosition;
+ }
+
+ @Override
+ public void position(int position) {
+ mPosition = position;
+ }
+
+ @Override
+ public void put(final byte b) {
+ mBuffer[mPosition++] = b;
+ }
+
+ @Override
+ public int limit() {
+ return mBuffer.length - 1;
+ }
+
+ @Override
+ public int capacity() {
+ return mBuffer.length;
+ }
+}
diff --git a/tests/src/org/kelar/inputmethod/latin/utils/CapsModeUtilsTests.java b/tests/src/org/kelar/inputmethod/latin/utils/CapsModeUtilsTests.java
new file mode 100644
index 000000000..75463929f
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/CapsModeUtilsTests.java
@@ -0,0 +1,162 @@
+/*
+ * 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 org.kelar.inputmethod.latin.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.res.Resources;
+import android.text.TextUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.kelar.inputmethod.latin.common.LocaleUtils;
+import org.kelar.inputmethod.latin.settings.SpacingAndPunctuations;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CapsModeUtilsTests {
+ private static void onePathForCaps(final CharSequence cs, final int expectedResult,
+ final int mask, final SpacingAndPunctuations sp, final boolean hasSpaceBefore) {
+ final int oneTimeResult = expectedResult & mask;
+ assertEquals("After >" + cs + "<", oneTimeResult,
+ CapsModeUtils.getCapsMode(cs, mask, sp, hasSpaceBefore));
+ }
+
+ private static void allPathsForCaps(final CharSequence cs, final int expectedResult,
+ 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, 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);
+ }
+
+ @Test
+ public void testGetCapsMode() {
+ final int c = TextUtils.CAP_MODE_CHARACTERS;
+ final int w = TextUtils.CAP_MODE_WORDS;
+ final int s = TextUtils.CAP_MODE_SENTENCES;
+ final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() {
+ @Override
+ protected SpacingAndPunctuations job(final Resources res) {
+ return new SpacingAndPunctuations(res);
+ }
+ };
+ final Resources res = InstrumentationRegistry.getTargetContext().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, sp, true);
+ allPathsForCaps("Word.", c | w | s, sp, true);
+
+ // Tests after some whitespace
+ 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);
+
+ // 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);
+
+ // Test armenian period
+ sp = job.runInLocale(res, LocaleUtils.constructLocaleFromString("hy_AM"));
+ assertTrue("Period is not sentence separator in Armenian",
+ !sp.isSentenceSeparator('.'));
+ assertTrue("Sentence separator is Armenian period in Armenian",
+ sp.isSentenceSeparator(0x589));
+ // No space : capitalize only if MODE_CHARACTERS
+ allPathsForCaps("Word", c, sp, false);
+ allPathsForCaps("Word.", c, sp, false);
+ // Space, but no armenian period : capitalize if MODE_WORDS but not SENTENCES
+ allPathsForCaps("Word. ", c | w, sp, false);
+ // Armenian period : capitalize if MODE_SENTENCES
+ allPathsForCaps("Word\u0589 ", c | w | s, sp, false);
+
+ // Test for sentence terminators
+ sp = job.runInLocale(res, Locale.ENGLISH);
+ allPathsForCaps("Word? ", c | w | s, sp, false);
+ allPathsForCaps("Word?", c | w | s, sp, true);
+ allPathsForCaps("Word?", c, sp, false);
+ allPathsForCaps("Word! ", c | w | s, sp, false);
+ allPathsForCaps("Word!", c | w | s, sp, true);
+ allPathsForCaps("Word!", c, sp, false);
+ allPathsForCaps("Word; ", c | w, sp, false);
+ allPathsForCaps("Word;", c | w, sp, true);
+ allPathsForCaps("Word;", c, sp, false);
+ // Test for sentence terminators in Greek
+ sp = job.runInLocale(res, LocaleUtils.constructLocaleFromString("el"));
+ allPathsForCaps("Word? ", c | w | s, sp, false);
+ allPathsForCaps("Word?", c | w | s, sp, true);
+ allPathsForCaps("Word?", c, sp, false);
+ allPathsForCaps("Word! ", c | w | s, sp, false);
+ allPathsForCaps("Word!", c | w | s, sp, true);
+ allPathsForCaps("Word!", c, sp, false);
+ // In Greek ";" is the question mark and it terminates the sentence
+ allPathsForCaps("Word; ", c | w | s, sp, false);
+ allPathsForCaps("Word;", c | w | s, sp, true);
+ allPathsForCaps("Word;", c, sp, false);
+ }
+}
diff --git a/tests/src/org/kelar/inputmethod/latin/utils/CollectionUtilsTests.java b/tests/src/org/kelar/inputmethod/latin/utils/CollectionUtilsTests.java
new file mode 100644
index 000000000..390e88828
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/CollectionUtilsTests.java
@@ -0,0 +1,104 @@
+/*
+ * 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 org.kelar.inputmethod.latin.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.kelar.inputmethod.latin.common.CollectionUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Tests for {@link CollectionUtils}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CollectionUtilsTests {
+ /**
+ * Tests that {@link CollectionUtils#arrayAsList(Object[],int,int)} fails as expected
+ * with some invalid inputs.
+ */
+ @Test
+ public void testArrayAsListFailure() {
+ final String[] array = { "0", "1" };
+ // Negative start
+ try {
+ CollectionUtils.arrayAsList(array, -1, 1);
+ fail("Failed to catch start < 0");
+ } catch (final IllegalArgumentException e) {
+ assertEquals("Invalid start: -1 end: 1 with array.length: 2", e.getMessage());
+ }
+ // start > end
+ try {
+ CollectionUtils.arrayAsList(array, 1, -1);
+ fail("Failed to catch start > end");
+ } catch (final IllegalArgumentException e) {
+ assertEquals("Invalid start: 1 end: -1 with array.length: 2", e.getMessage());
+ }
+ // end > array.length
+ try {
+ CollectionUtils.arrayAsList(array, 1, 3);
+ fail("Failed to catch end > array.length");
+ } catch (final IllegalArgumentException e) {
+ assertEquals("Invalid start: 1 end: 3 with array.length: 2", e.getMessage());
+ }
+ }
+
+ /**
+ * Tests that {@link CollectionUtils#arrayAsList(Object[],int,int)} gives the expected
+ * results for a few valid inputs.
+ */
+ @Test
+ public void testArrayAsList() {
+ final ArrayList<String> empty = new ArrayList<>();
+ assertEquals(empty, CollectionUtils.arrayAsList(new String[] {}, 0, 0));
+ final String[] array = { "0", "1", "2", "3", "4" };
+ assertEquals(empty, CollectionUtils.arrayAsList(array, 0, 0));
+ assertEquals(empty, CollectionUtils.arrayAsList(array, 1, 1));
+ assertEquals(empty, CollectionUtils.arrayAsList(array, array.length, array.length));
+ final ArrayList<String> expected123 = new ArrayList<>(Arrays.asList("1", "2", "3"));
+ assertEquals(expected123, CollectionUtils.arrayAsList(array, 1, 4));
+ }
+
+ /**
+ * Tests that {@link CollectionUtils#isNullOrEmpty(java.util.Collection)} gives the expected
+ * results for a few cases.
+ */
+ @Test
+ public void testIsNullOrEmpty() {
+ assertTrue(CollectionUtils.isNullOrEmpty((List<String>) null));
+ assertTrue(CollectionUtils.isNullOrEmpty((Map<String, String>) null));
+ assertTrue(CollectionUtils.isNullOrEmpty(new ArrayList<String>()));
+ assertTrue(CollectionUtils.isNullOrEmpty(new HashMap<String, String>()));
+ assertFalse(CollectionUtils.isNullOrEmpty(Collections.singletonList("Not empty")));
+ assertFalse(CollectionUtils.isNullOrEmpty(Collections.singletonMap("Not", "empty")));
+ }
+}
diff --git a/tests/src/org/kelar/inputmethod/latin/utils/DictionaryInfoUtilsTests.java b/tests/src/org/kelar/inputmethod/latin/utils/DictionaryInfoUtilsTests.java
new file mode 100644
index 000000000..4c30750f5
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/DictionaryInfoUtilsTests.java
@@ -0,0 +1,77 @@
+/*
+ * 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 org.kelar.inputmethod.latin.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.res.Resources;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.kelar.inputmethod.latin.common.LocaleUtils;
+import org.kelar.inputmethod.latin.settings.SpacingAndPunctuations;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DictionaryInfoUtilsTests {
+ @Test
+ public void testLooksValidForDictionaryInsertion() {
+ final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() {
+ @Override
+ protected SpacingAndPunctuations job(final Resources res) {
+ return new SpacingAndPunctuations(res);
+ }
+ };
+ final Resources res = InstrumentationRegistry.getTargetContext().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));
+ }
+
+ @Test
+ public void testGetMainDictId() {
+ assertEquals("main:en",
+ DictionaryInfoUtils.getMainDictId(LocaleUtils.constructLocaleFromString("en")));
+ assertEquals("main:en_us",
+ DictionaryInfoUtils.getMainDictId(LocaleUtils.constructLocaleFromString("en_US")));
+ assertEquals("main:en_gb",
+ DictionaryInfoUtils.getMainDictId(LocaleUtils.constructLocaleFromString("en_GB")));
+
+ assertEquals("main:es",
+ DictionaryInfoUtils.getMainDictId(LocaleUtils.constructLocaleFromString("es")));
+ assertEquals("main:es_us",
+ DictionaryInfoUtils.getMainDictId(LocaleUtils.constructLocaleFromString("es_US")));
+
+ assertEquals("main:en_us_posix", DictionaryInfoUtils.getMainDictId(
+ LocaleUtils.constructLocaleFromString("en_US_POSIX")));
+ }
+}
diff --git a/tests/src/org/kelar/inputmethod/latin/utils/ExecutorUtilsTests.java b/tests/src/org/kelar/inputmethod/latin/utils/ExecutorUtilsTests.java
new file mode 100644
index 000000000..440e527f1
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/ExecutorUtilsTests.java
@@ -0,0 +1,65 @@
+/*
+ * 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 org.kelar.inputmethod.latin.utils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.util.Log;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Unit tests for {@link ExecutorUtils}.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ExecutorUtilsTests {
+ private static final String TAG = ExecutorUtilsTests.class.getSimpleName();
+
+ private static final int NUM_OF_TASKS = 10;
+ private static final int DELAY_FOR_WAITING_TASKS_MILLISECONDS = 500;
+
+ @Test
+ public void testExecute() {
+ final ExecutorService executor =
+ ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD);
+ final AtomicInteger v = new AtomicInteger(0);
+ for (int i = 0; i < NUM_OF_TASKS; ++i) {
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ v.incrementAndGet();
+ }
+ });
+ }
+ try {
+ executor.awaitTermination(DELAY_FOR_WAITING_TASKS_MILLISECONDS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Log.d(TAG, "Exception while sleeping.", e);
+ }
+
+ assertEquals(NUM_OF_TASKS, v.get());
+ }
+}
diff --git a/tests/src/org/kelar/inputmethod/latin/utils/ImportantNoticeUtilsTests.java b/tests/src/org/kelar/inputmethod/latin/utils/ImportantNoticeUtilsTests.java
new file mode 100644
index 000000000..65abd16fd
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/ImportantNoticeUtilsTests.java
@@ -0,0 +1,135 @@
+/*
+ * 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 org.kelar.inputmethod.latin.utils;
+
+import static org.kelar.inputmethod.latin.utils.ImportantNoticeUtils.KEY_TIMESTAMP_OF_CONTACTS_NOTICE;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.kelar.inputmethod.latin.settings.SettingsValues;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ImportantNoticeUtilsTests {
+
+ private ImportantNoticePreferences mImportantNoticePreferences;
+
+ @Mock private SettingsValues mMockSettingsValues;
+
+ private Context getContext() {
+ return InstrumentationRegistry.getTargetContext();
+ }
+
+ private static class ImportantNoticePreferences {
+ private final SharedPreferences mPref;
+
+ private Long mLastTime;
+
+ public ImportantNoticePreferences(final Context context) {
+ mPref = ImportantNoticeUtils.getImportantNoticePreferences(context);
+ }
+
+ private Integer getInt(final String key) {
+ if (mPref.contains(key)) {
+ return mPref.getInt(key, 0);
+ }
+ return null;
+ }
+
+ public Long getLong(final String key) {
+ if (mPref.contains(key)) {
+ return mPref.getLong(key, 0);
+ }
+ return null;
+ }
+
+ private void putInt(final String key, final Integer value) {
+ if (value == null) {
+ removePreference(key);
+ } else {
+ mPref.edit().putInt(key, value).apply();
+ }
+ }
+
+ private void putLong(final String key, final Long value) {
+ if (value == null) {
+ removePreference(key);
+ } else {
+ mPref.edit().putLong(key, value).apply();
+ }
+ }
+
+ private void removePreference(final String key) {
+ mPref.edit().remove(key).apply();
+ }
+
+ public void save() {
+ mLastTime = getLong(KEY_TIMESTAMP_OF_CONTACTS_NOTICE);
+ }
+
+ public void restore() {
+ putLong(KEY_TIMESTAMP_OF_CONTACTS_NOTICE, mLastTime);
+ }
+
+ public void clear() {
+ removePreference(KEY_TIMESTAMP_OF_CONTACTS_NOTICE);
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mImportantNoticePreferences = new ImportantNoticePreferences(getContext());
+ mImportantNoticePreferences.save();
+ when(mMockSettingsValues.isPersonalizationEnabled()).thenReturn(true);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mImportantNoticePreferences.restore();
+ }
+
+ @Test
+ public void testPersonalizationSetting() {
+ mImportantNoticePreferences.clear();
+
+ // Personalization enabled.
+ when(mMockSettingsValues.isPersonalizationEnabled()).thenReturn(true);
+ assertEquals("Current boolean with personalization enabled", true,
+ ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
+
+ // Personalization disabled.
+ when(mMockSettingsValues.isPersonalizationEnabled()).thenReturn(false);
+ assertEquals("Current boolean with personalization disabled", false,
+ ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
+ }
+}
diff --git a/tests/src/org/kelar/inputmethod/latin/utils/JsonUtilsTests.java b/tests/src/org/kelar/inputmethod/latin/utils/JsonUtilsTests.java
new file mode 100644
index 000000000..5a323ef51
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/JsonUtilsTests.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.kelar.inputmethod.latin.utils;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class JsonUtilsTests {
+ @Test
+ public void testJsonUtils() {
+ final Object[] objs = new Object[] { 1, "aaa", "bbb", 3 };
+ final List<Object> objArray = Arrays.asList(objs);
+ 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/org/kelar/inputmethod/latin/utils/LanguageOnSpacebarUtilsTests.java b/tests/src/org/kelar/inputmethod/latin/utils/LanguageOnSpacebarUtilsTests.java
new file mode 100644
index 000000000..007c69fd2
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/LanguageOnSpacebarUtilsTests.java
@@ -0,0 +1,227 @@
+/*
+ * 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 org.kelar.inputmethod.latin.utils;
+
+import static org.kelar.inputmethod.latin.utils.LanguageOnSpacebarUtils.FORMAT_TYPE_FULL_LOCALE;
+import static org.kelar.inputmethod.latin.utils.LanguageOnSpacebarUtils.FORMAT_TYPE_LANGUAGE_ONLY;
+import static org.kelar.inputmethod.latin.utils.LanguageOnSpacebarUtils.FORMAT_TYPE_NONE;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.view.inputmethod.InputMethodSubtype;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.kelar.inputmethod.latin.RichInputMethodManager;
+import org.kelar.inputmethod.latin.RichInputMethodSubtype;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+import javax.annotation.Nonnull;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LanguageOnSpacebarUtilsTests {
+ private RichInputMethodManager mRichImm;
+
+ RichInputMethodSubtype EN_US_QWERTY;
+ RichInputMethodSubtype EN_GB_QWERTY;
+ RichInputMethodSubtype FR_AZERTY;
+ RichInputMethodSubtype FR_CA_QWERTY;
+ RichInputMethodSubtype FR_CH_SWISS;
+ RichInputMethodSubtype FR_CH_QWERTY;
+ RichInputMethodSubtype FR_CH_QWERTZ;
+ RichInputMethodSubtype IW_HEBREW;
+ RichInputMethodSubtype ZZ_QWERTY;
+
+ @Before
+ public void setUp() throws Exception {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ RichInputMethodManager.init(context);
+ mRichImm = RichInputMethodManager.getInstance();
+
+ EN_US_QWERTY = findSubtypeOf(Locale.US.toString(), "qwerty");
+ EN_GB_QWERTY = findSubtypeOf(Locale.UK.toString(), "qwerty");
+ FR_AZERTY = findSubtypeOf(Locale.FRENCH.toString(), "azerty");
+ FR_CA_QWERTY = findSubtypeOf(Locale.CANADA_FRENCH.toString(), "qwerty");
+ FR_CH_SWISS = findSubtypeOf("fr_CH", "swiss");
+ FR_CH_QWERTZ = new RichInputMethodSubtype(
+ AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype("fr_CH", "qwertz"));
+ FR_CH_QWERTY = new RichInputMethodSubtype(
+ AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype("fr_CH", "qwerty"));
+ IW_HEBREW = findSubtypeOf("iw", "hebrew");
+ ZZ_QWERTY = findSubtypeOf(SubtypeLocaleUtils.NO_LANGUAGE, "qwerty");
+ }
+
+ @Nonnull
+ private RichInputMethodSubtype findSubtypeOf(final String localeString,
+ final String keyboardLayoutSetName) {
+ final InputMethodSubtype subtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ localeString, keyboardLayoutSetName);
+ if (subtype == null) {
+ throw new RuntimeException("Can't find subtype of " + localeString + " with "
+ + keyboardLayoutSetName);
+ }
+ return new RichInputMethodSubtype(subtype);
+ }
+
+ private static void enableSubtypes(final RichInputMethodSubtype ... subtypes) {
+ final ArrayList<InputMethodSubtype> enabledSubtypes = new ArrayList<>();
+ for (final RichInputMethodSubtype subtype : subtypes) {
+ enabledSubtypes.add(subtype.getRawSubtype());
+ }
+ LanguageOnSpacebarUtils.setEnabledSubtypes(enabledSubtypes);
+ }
+
+ private static void assertFormatType(final RichInputMethodSubtype subtype,
+ final boolean implicitlyEnabledSubtype, final Locale systemLocale,
+ final int expectedFormat) {
+ LanguageOnSpacebarUtils.onSubtypeChanged(subtype, implicitlyEnabledSubtype, systemLocale);
+ assertEquals(subtype.getLocale() + " implicitly=" + implicitlyEnabledSubtype
+ + " in " + systemLocale, expectedFormat,
+ LanguageOnSpacebarUtils.getLanguageOnSpacebarFormatType(subtype));
+ }
+
+ @Test
+ public void testOneSubtypeImplicitlyEnabled() {
+ enableSubtypes(EN_US_QWERTY);
+ assertFormatType(EN_US_QWERTY, true, Locale.US, FORMAT_TYPE_NONE);
+
+ enableSubtypes(EN_GB_QWERTY);
+ assertFormatType(EN_GB_QWERTY, true, Locale.UK, FORMAT_TYPE_NONE);
+
+ enableSubtypes(FR_AZERTY);
+ assertFormatType(FR_AZERTY, true, Locale.FRANCE, FORMAT_TYPE_NONE);
+
+ enableSubtypes(FR_CA_QWERTY);
+ assertFormatType(FR_CA_QWERTY, true, Locale.CANADA_FRENCH, FORMAT_TYPE_NONE);
+ }
+
+ @Test
+ public void testOneSubtypeExplicitlyEnabled() {
+ enableSubtypes(EN_US_QWERTY);
+ assertFormatType(EN_US_QWERTY, false, Locale.UK, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(EN_US_QWERTY, false, Locale.FRANCE, FORMAT_TYPE_LANGUAGE_ONLY);
+
+ enableSubtypes(EN_GB_QWERTY);
+ assertFormatType(EN_GB_QWERTY, false, Locale.US, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(EN_GB_QWERTY, false, Locale.FRANCE, FORMAT_TYPE_LANGUAGE_ONLY);
+
+ enableSubtypes(FR_AZERTY);
+ assertFormatType(FR_AZERTY, false, Locale.US, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_AZERTY, false, Locale.CANADA_FRENCH, FORMAT_TYPE_LANGUAGE_ONLY);
+
+ enableSubtypes(FR_CA_QWERTY);
+ assertFormatType(FR_CA_QWERTY, false, Locale.US, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CA_QWERTY, false, Locale.FRANCE, FORMAT_TYPE_LANGUAGE_ONLY);
+ }
+
+ @Test
+ public void testOneSubtypeImplicitlyEnabledWithNoLanguageSubtype() {
+ final Locale Locale_IW = new Locale("iw");
+ enableSubtypes(IW_HEBREW, ZZ_QWERTY);
+ // TODO: Should this be FORMAT_TYPE_NONE?
+ assertFormatType(IW_HEBREW, true, Locale_IW, FORMAT_TYPE_LANGUAGE_ONLY);
+ // TODO: Should this be FORMAT_TYPE_NONE?
+ assertFormatType(ZZ_QWERTY, true, Locale_IW, FORMAT_TYPE_FULL_LOCALE);
+ }
+
+ @Test
+ public void testTwoSubtypesExplicitlyEnabled() {
+ enableSubtypes(EN_US_QWERTY, FR_AZERTY);
+ assertFormatType(EN_US_QWERTY, false, Locale.US, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_AZERTY, false, Locale.US, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(EN_US_QWERTY, false, Locale.FRANCE, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_AZERTY, false, Locale.FRANCE, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(EN_US_QWERTY, false, Locale.JAPAN, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_AZERTY, false, Locale.JAPAN, FORMAT_TYPE_LANGUAGE_ONLY);
+
+ enableSubtypes(EN_US_QWERTY, ZZ_QWERTY);
+ assertFormatType(EN_US_QWERTY, false, Locale.US, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(ZZ_QWERTY, false, Locale.US, FORMAT_TYPE_FULL_LOCALE);
+ assertFormatType(EN_US_QWERTY, false, Locale.FRANCE, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(ZZ_QWERTY, false, Locale.FRANCE, FORMAT_TYPE_FULL_LOCALE);
+
+ }
+
+ @Test
+ public void testMultiSubtypeWithSameLanuageAndSameLayout() {
+ // Explicitly enable en_US, en_GB, fr_FR, and no language keyboards.
+ enableSubtypes(EN_US_QWERTY, EN_GB_QWERTY, FR_CA_QWERTY, ZZ_QWERTY);
+
+ assertFormatType(EN_US_QWERTY, false, Locale.US, FORMAT_TYPE_FULL_LOCALE);
+ assertFormatType(EN_GB_QWERTY, false, Locale.US, FORMAT_TYPE_FULL_LOCALE);
+ assertFormatType(FR_CA_QWERTY, false, Locale.US, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(ZZ_QWERTY, false, Locale.US, FORMAT_TYPE_FULL_LOCALE);
+
+ assertFormatType(EN_US_QWERTY, false, Locale.JAPAN, FORMAT_TYPE_FULL_LOCALE);
+ assertFormatType(EN_GB_QWERTY, false, Locale.JAPAN, FORMAT_TYPE_FULL_LOCALE);
+ assertFormatType(FR_CA_QWERTY, false, Locale.JAPAN, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(ZZ_QWERTY, false, Locale.JAPAN, FORMAT_TYPE_FULL_LOCALE);
+ }
+
+ @Test
+ public void testMultiSubtypesWithSameLanguageButHaveDifferentLayout() {
+ enableSubtypes(FR_AZERTY, FR_CA_QWERTY, FR_CH_SWISS, FR_CH_QWERTZ);
+
+ assertFormatType(FR_AZERTY, false, Locale.FRANCE, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CA_QWERTY, false, Locale.FRANCE, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CH_SWISS, false, Locale.FRANCE, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CH_QWERTZ, false, Locale.FRANCE, FORMAT_TYPE_LANGUAGE_ONLY);
+
+ assertFormatType(FR_AZERTY, false, Locale.CANADA_FRENCH, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CA_QWERTY, false, Locale.CANADA_FRENCH, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CH_SWISS, false, Locale.CANADA_FRENCH, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CH_QWERTZ, false, Locale.CANADA_FRENCH, FORMAT_TYPE_LANGUAGE_ONLY);
+
+ assertFormatType(FR_AZERTY, false, Locale.JAPAN, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CA_QWERTY, false, Locale.JAPAN, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CH_SWISS, false, Locale.JAPAN, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CH_QWERTZ, false, Locale.JAPAN, FORMAT_TYPE_LANGUAGE_ONLY);
+ }
+
+ @Test
+ public void testMultiSubtypesWithSameLanguageAndMayHaveSameLayout() {
+ enableSubtypes(FR_AZERTY, FR_CA_QWERTY, FR_CH_SWISS, FR_CH_QWERTY, FR_CH_QWERTZ);
+
+ assertFormatType(FR_AZERTY, false, Locale.FRANCE, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CA_QWERTY, false, Locale.FRANCE, FORMAT_TYPE_FULL_LOCALE);
+ assertFormatType(FR_CH_SWISS, false, Locale.FRANCE, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CH_QWERTY, false, Locale.FRANCE, FORMAT_TYPE_FULL_LOCALE);
+ assertFormatType(FR_CH_QWERTZ, false, Locale.FRANCE, FORMAT_TYPE_LANGUAGE_ONLY);
+
+ assertFormatType(FR_AZERTY, false, Locale.CANADA_FRENCH, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CA_QWERTY, false, Locale.CANADA_FRENCH, FORMAT_TYPE_FULL_LOCALE);
+ assertFormatType(FR_CH_SWISS, false, Locale.CANADA_FRENCH, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CH_QWERTY, false, Locale.CANADA_FRENCH, FORMAT_TYPE_FULL_LOCALE);
+ assertFormatType(FR_CH_QWERTZ, false, Locale.CANADA_FRENCH, FORMAT_TYPE_LANGUAGE_ONLY);
+
+ assertFormatType(FR_AZERTY, false, Locale.JAPAN, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CA_QWERTY, false, Locale.JAPAN, FORMAT_TYPE_FULL_LOCALE);
+ assertFormatType(FR_CH_SWISS, false, Locale.JAPAN, FORMAT_TYPE_LANGUAGE_ONLY);
+ assertFormatType(FR_CH_QWERTY, false, Locale.JAPAN, FORMAT_TYPE_FULL_LOCALE);
+ assertFormatType(FR_CH_QWERTZ, false, Locale.JAPAN, FORMAT_TYPE_LANGUAGE_ONLY);
+ }
+}
diff --git a/tests/src/org/kelar/inputmethod/latin/utils/RecapitalizeStatusTests.java b/tests/src/org/kelar/inputmethod/latin/utils/RecapitalizeStatusTests.java
new file mode 100644
index 000000000..1ce091b0b
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/RecapitalizeStatusTests.java
@@ -0,0 +1,207 @@
+/*
+ * 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 org.kelar.inputmethod.latin.utils;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.kelar.inputmethod.latin.common.Constants;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RecapitalizeStatusTests {
+ private static final int[] SPACE = { Constants.CODE_SPACE };
+
+ @Test
+ public void testTrim() {
+ final RecapitalizeStatus status = new RecapitalizeStatus();
+ status.start(30, 40, "abcdefghij", Locale.ENGLISH, SPACE);
+ status.trim();
+ assertEquals("abcdefghij", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(40, status.getNewCursorEnd());
+
+ status.start(30, 44, " abcdefghij", Locale.ENGLISH, SPACE);
+ status.trim();
+ assertEquals("abcdefghij", status.getRecapitalizedString());
+ assertEquals(34, status.getNewCursorStart());
+ assertEquals(44, status.getNewCursorEnd());
+
+ status.start(30, 40, "abcdefgh ", Locale.ENGLISH, SPACE);
+ status.trim();
+ assertEquals("abcdefgh", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(38, status.getNewCursorEnd());
+
+ status.start(30, 45, " abcdefghij ", Locale.ENGLISH, SPACE);
+ status.trim();
+ assertEquals("abcdefghij", status.getRecapitalizedString());
+ assertEquals(33, status.getNewCursorStart());
+ assertEquals(43, status.getNewCursorEnd());
+ }
+
+ @Test
+ public void testRotate() {
+ final RecapitalizeStatus status = new RecapitalizeStatus();
+ status.start(29, 40, "abcd efghij", Locale.ENGLISH, SPACE);
+ status.rotate();
+ assertEquals("Abcd Efghij", status.getRecapitalizedString());
+ assertEquals(29, status.getNewCursorStart());
+ assertEquals(40, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("ABCD EFGHIJ", status.getRecapitalizedString());
+ status.rotate();
+ assertEquals("abcd efghij", status.getRecapitalizedString());
+ status.rotate();
+ assertEquals("Abcd Efghij", status.getRecapitalizedString());
+
+ status.start(29, 40, "Abcd Efghij", Locale.ENGLISH, SPACE);
+ status.rotate();
+ assertEquals("ABCD EFGHIJ", status.getRecapitalizedString());
+ assertEquals(29, status.getNewCursorStart());
+ assertEquals(40, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("abcd efghij", status.getRecapitalizedString());
+ status.rotate();
+ assertEquals("Abcd Efghij", status.getRecapitalizedString());
+ status.rotate();
+ assertEquals("ABCD EFGHIJ", status.getRecapitalizedString());
+
+ status.start(29, 40, "ABCD EFGHIJ", Locale.ENGLISH, SPACE);
+ status.rotate();
+ assertEquals("abcd efghij", status.getRecapitalizedString());
+ assertEquals(29, status.getNewCursorStart());
+ assertEquals(40, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("Abcd Efghij", status.getRecapitalizedString());
+ status.rotate();
+ assertEquals("ABCD EFGHIJ", status.getRecapitalizedString());
+ status.rotate();
+ assertEquals("abcd efghij", status.getRecapitalizedString());
+
+ status.start(29, 39, "AbCDefghij", Locale.ENGLISH, SPACE);
+ status.rotate();
+ assertEquals("abcdefghij", status.getRecapitalizedString());
+ assertEquals(29, status.getNewCursorStart());
+ assertEquals(39, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("Abcdefghij", status.getRecapitalizedString());
+ status.rotate();
+ assertEquals("ABCDEFGHIJ", status.getRecapitalizedString());
+ status.rotate();
+ assertEquals("AbCDefghij", status.getRecapitalizedString());
+ status.rotate();
+ assertEquals("abcdefghij", status.getRecapitalizedString());
+
+ status.start(29, 40, "Abcd efghij", Locale.ENGLISH, SPACE);
+ status.rotate();
+ assertEquals("abcd efghij", status.getRecapitalizedString());
+ assertEquals(29, status.getNewCursorStart());
+ assertEquals(40, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("Abcd Efghij", status.getRecapitalizedString());
+ status.rotate();
+ assertEquals("ABCD EFGHIJ", status.getRecapitalizedString());
+ status.rotate();
+ assertEquals("Abcd efghij", status.getRecapitalizedString());
+ status.rotate();
+ assertEquals("abcd efghij", status.getRecapitalizedString());
+
+ status.start(30, 34, "grüß", Locale.GERMAN, SPACE);
+ status.rotate();
+ assertEquals("Grüß", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(34, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("GRÜSS", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(35, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("grüß", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(34, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("Grüß", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(34, status.getNewCursorEnd());
+
+ status.start(30, 33, "œuf", Locale.FRENCH, SPACE);
+ status.rotate();
+ assertEquals("Œuf", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(33, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("ŒUF", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(33, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("œuf", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(33, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("Œuf", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(33, status.getNewCursorEnd());
+
+ status.start(30, 33, "œUf", Locale.FRENCH, SPACE);
+ status.rotate();
+ assertEquals("œuf", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(33, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("Œuf", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(33, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("ŒUF", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(33, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("œUf", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(33, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("œuf", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(33, status.getNewCursorEnd());
+
+ status.start(30, 35, "école", Locale.FRENCH, SPACE);
+ status.rotate();
+ assertEquals("École", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(35, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("ÉCOLE", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(35, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("école", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(35, status.getNewCursorEnd());
+ status.rotate();
+ assertEquals("École", status.getRecapitalizedString());
+ assertEquals(30, status.getNewCursorStart());
+ assertEquals(35, status.getNewCursorEnd());
+ }
+}
diff --git a/tests/src/org/kelar/inputmethod/latin/utils/ResourceUtilsTests.java b/tests/src/org/kelar/inputmethod/latin/utils/ResourceUtilsTests.java
new file mode 100644
index 000000000..7e7f24d49
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/ResourceUtilsTests.java
@@ -0,0 +1,163 @@
+/*
+ * 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 org.kelar.inputmethod.latin.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ResourceUtilsTests {
+ @Test
+ public void testFindConstantForKeyValuePairsSimple() {
+ final HashMap<String,String> anyKeyValue = new HashMap<>();
+ anyKeyValue.put("anyKey", "anyValue");
+ final HashMap<String,String> nullKeyValue = null;
+ final HashMap<String,String> emptyKeyValue = new HashMap<>();
+
+ final String[] nullArray = null;
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(anyKeyValue, nullArray));
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(emptyKeyValue, nullArray));
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(nullKeyValue, nullArray));
+
+ final String[] emptyArray = {};
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(anyKeyValue, emptyArray));
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(emptyKeyValue, emptyArray));
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(nullKeyValue, emptyArray));
+
+ final String HARDWARE_KEY = "HARDWARE";
+ final String[] array = {
+ ",defaultValue",
+ "HARDWARE=grouper,0.3",
+ "HARDWARE=mako,0.4",
+ "HARDWARE=manta,0.2",
+ "HARDWARE=mako,0.5",
+ };
+
+ final HashMap<String,String> keyValues = new HashMap<>();
+ keyValues.put(HARDWARE_KEY, "grouper");
+ assertEquals("0.3", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+ keyValues.put(HARDWARE_KEY, "mako");
+ assertEquals("0.4", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+ keyValues.put(HARDWARE_KEY, "manta");
+ assertEquals("0.2", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+
+ keyValues.clear();
+ keyValues.put("hardware", "grouper");
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+
+ keyValues.clear();
+ keyValues.put(HARDWARE_KEY, "MAKO");
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+ keyValues.put(HARDWARE_KEY, "mantaray");
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(emptyKeyValue, array));
+ }
+
+ @Test
+ public void testFindConstantForKeyValuePairsCombined() {
+ final String HARDWARE_KEY = "HARDWARE";
+ final String MODEL_KEY = "MODEL";
+ final String MANUFACTURER_KEY = "MANUFACTURER";
+ final String[] array = {
+ ",defaultValue",
+ "no_comma",
+ "error_pattern,0.1",
+ "HARDWARE=grouper:MANUFACTURER=asus,0.3",
+ "HARDWARE=mako:MODEL=Nexus 4,0.4",
+ "HARDWARE=manta:MODEL=Nexus 10:MANUFACTURER=samsung,0.2"
+ };
+ final String[] failArray = {
+ ",defaultValue",
+ "HARDWARE=grouper:MANUFACTURER=ASUS,0.3",
+ "HARDWARE=mako:MODEL=Nexus_4,0.4",
+ "HARDWARE=mantaray:MODEL=Nexus 10:MANUFACTURER=samsung,0.2"
+ };
+
+ final HashMap<String,String> keyValues = new HashMap<>();
+ keyValues.put(HARDWARE_KEY, "grouper");
+ keyValues.put(MODEL_KEY, "Nexus 7");
+ keyValues.put(MANUFACTURER_KEY, "asus");
+ assertEquals("0.3", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray));
+
+ keyValues.clear();
+ keyValues.put(HARDWARE_KEY, "mako");
+ keyValues.put(MODEL_KEY, "Nexus 4");
+ keyValues.put(MANUFACTURER_KEY, "LGE");
+ assertEquals("0.4", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray));
+
+ keyValues.clear();
+ keyValues.put(HARDWARE_KEY, "manta");
+ keyValues.put(MODEL_KEY, "Nexus 10");
+ keyValues.put(MANUFACTURER_KEY, "samsung");
+ assertEquals("0.2", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray));
+ keyValues.put(HARDWARE_KEY, "mantaray");
+ assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+ assertEquals("0.2", ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray));
+ }
+
+ @Test
+ public void testFindConstantForKeyValuePairsRegexp() {
+ final String HARDWARE_KEY = "HARDWARE";
+ final String MODEL_KEY = "MODEL";
+ final String MANUFACTURER_KEY = "MANUFACTURER";
+ final String[] array = {
+ ",defaultValue",
+ "no_comma",
+ "HARDWARE=error_regexp:MANUFACTURER=error[regexp,0.1",
+ "HARDWARE=grouper|tilapia:MANUFACTURER=asus,0.3",
+ "HARDWARE=[mM][aA][kK][oO]:MODEL=Nexus 4,0.4",
+ "HARDWARE=manta.*:MODEL=Nexus 10:MANUFACTURER=samsung,0.2"
+ };
+
+ final HashMap<String,String> keyValues = new HashMap<>();
+ keyValues.put(HARDWARE_KEY, "grouper");
+ keyValues.put(MODEL_KEY, "Nexus 7");
+ keyValues.put(MANUFACTURER_KEY, "asus");
+ assertEquals("0.3", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+ keyValues.put(HARDWARE_KEY, "tilapia");
+ assertEquals("0.3", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+
+ keyValues.clear();
+ keyValues.put(HARDWARE_KEY, "mako");
+ keyValues.put(MODEL_KEY, "Nexus 4");
+ keyValues.put(MANUFACTURER_KEY, "LGE");
+ assertEquals("0.4", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+ keyValues.put(HARDWARE_KEY, "MAKO");
+ assertEquals("0.4", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+
+ keyValues.clear();
+ keyValues.put(HARDWARE_KEY, "manta");
+ keyValues.put(MODEL_KEY, "Nexus 10");
+ keyValues.put(MANUFACTURER_KEY, "samsung");
+ assertEquals("0.2", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+ keyValues.put(HARDWARE_KEY, "mantaray");
+ assertEquals("0.2", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
+ }
+}
diff --git a/tests/src/org/kelar/inputmethod/latin/utils/SpannableStringUtilsTests.java b/tests/src/org/kelar/inputmethod/latin/utils/SpannableStringUtilsTests.java
new file mode 100644
index 000000000..f5546a04d
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/SpannableStringUtilsTests.java
@@ -0,0 +1,244 @@
+/*
+ * 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 org.kelar.inputmethod.latin.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.SpannedString;
+import android.text.style.SuggestionSpan;
+import android.text.style.URLSpan;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SpannableStringUtilsTests {
+
+ private Context getContext() {
+ return InstrumentationRegistry.getTargetContext();
+ }
+
+ @Test
+ public void testConcatWithSuggestionSpansOnly() {
+ SpannableStringBuilder s = new SpannableStringBuilder("test string\ntest string\n"
+ + "test string\ntest string\ntest string\ntest string\ntest string\ntest string\n"
+ + "test string\ntest string\n");
+ final int N = 10;
+ for (int i = 0; i < N; ++i) {
+ // Put a PARAGRAPH-flagged span that should not be found in the result.
+ s.setSpan(new SuggestionSpan(getContext(),
+ new String[] {"" + i}, Spanned.SPAN_PARAGRAPH),
+ i * 12, i * 12 + 12, Spanned.SPAN_PARAGRAPH);
+ // Put a normal suggestion span that should be found in the result.
+ s.setSpan(new SuggestionSpan(getContext(), new String[] {"" + i}, 0), i, i * 2, 0);
+ // Put a URL span than should not be found in the result.
+ s.setSpan(new URLSpan("http://a"), i, i * 2, 0);
+ }
+
+ final CharSequence a = s.subSequence(0, 15);
+ final CharSequence b = s.subSequence(15, s.length());
+ final Spanned result =
+ (Spanned)SpannableStringUtils.concatWithNonParagraphSuggestionSpansOnly(a, b);
+
+ Object[] spans = result.getSpans(0, result.length(), SuggestionSpan.class);
+ for (int i = 0; i < spans.length; i++) {
+ final int flags = result.getSpanFlags(spans[i]);
+ assertEquals("Should not find a span with PARAGRAPH flag",
+ flags & Spanned.SPAN_PARAGRAPH, 0);
+ assertTrue("Should be a SuggestionSpan", spans[i] instanceof SuggestionSpan);
+ }
+ }
+
+ private static void assertSpanCount(final int expectedCount, final CharSequence cs) {
+ final int actualCount;
+ if (cs instanceof Spanned) {
+ final Spanned spanned = (Spanned) cs;
+ actualCount = spanned.getSpans(0, spanned.length(), Object.class).length;
+ } else {
+ actualCount = 0;
+ }
+ assertEquals(expectedCount, actualCount);
+ }
+
+ private static void assertSpan(final CharSequence cs, final Object expectedSpan,
+ final int expectedStart, final int expectedEnd, final int expectedFlags) {
+ assertTrue(cs instanceof Spanned);
+ final Spanned spanned = (Spanned) cs;
+ final Object[] actualSpans = spanned.getSpans(0, spanned.length(), Object.class);
+ for (Object actualSpan : actualSpans) {
+ if (actualSpan == expectedSpan) {
+ final int actualStart = spanned.getSpanStart(actualSpan);
+ final int actualEnd = spanned.getSpanEnd(actualSpan);
+ final int actualFlags = spanned.getSpanFlags(actualSpan);
+ assertEquals(expectedStart, actualStart);
+ assertEquals(expectedEnd, actualEnd);
+ assertEquals(expectedFlags, actualFlags);
+ return;
+ }
+ }
+ assertTrue(false);
+ }
+
+ @Test
+ public void testSplitCharSequenceWithSpan() {
+ // text: " a bcd efg hij "
+ // span1: ^^^^^^^
+ // span2: ^^^^^
+ // span3: ^
+ final SpannableString spannableString = new SpannableString(" a bcd efg hij ");
+ final Object span1 = new Object();
+ final Object span2 = new Object();
+ final Object span3 = new Object();
+ final int SPAN1_FLAGS = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
+ final int SPAN2_FLAGS = Spanned.SPAN_EXCLUSIVE_INCLUSIVE;
+ final int SPAN3_FLAGS = Spanned.SPAN_INCLUSIVE_INCLUSIVE;
+ spannableString.setSpan(span1, 0, 7, SPAN1_FLAGS);
+ spannableString.setSpan(span2, 0, 5, SPAN2_FLAGS);
+ spannableString.setSpan(span3, 12, 13, SPAN3_FLAGS);
+ final CharSequence[] charSequencesFromSpanned = SpannableStringUtils.split(
+ spannableString, " ", true /* preserveTrailingEmptySegmengs */);
+ final CharSequence[] charSequencesFromString = SpannableStringUtils.split(
+ spannableString.toString(), " ", true /* preserveTrailingEmptySegmengs */);
+
+
+ assertEquals(7, charSequencesFromString.length);
+ assertEquals(7, charSequencesFromSpanned.length);
+
+ // text: ""
+ // span1: ^
+ // span2: ^
+ // span3:
+ assertEquals("", charSequencesFromString[0].toString());
+ assertSpanCount(0, charSequencesFromString[0]);
+ assertEquals("", charSequencesFromSpanned[0].toString());
+ assertSpanCount(2, charSequencesFromSpanned[0]);
+ assertSpan(charSequencesFromSpanned[0], span1, 0, 0, SPAN1_FLAGS);
+ assertSpan(charSequencesFromSpanned[0], span2, 0, 0, SPAN2_FLAGS);
+
+ // text: "a"
+ // span1: ^
+ // span2: ^
+ // span3:
+ assertEquals("a", charSequencesFromString[1].toString());
+ assertSpanCount(0, charSequencesFromString[1]);
+ assertEquals("a", charSequencesFromSpanned[1].toString());
+ assertSpanCount(2, charSequencesFromSpanned[1]);
+ assertSpan(charSequencesFromSpanned[1], span1, 0, 1, SPAN1_FLAGS);
+ assertSpan(charSequencesFromSpanned[1], span2, 0, 1, SPAN2_FLAGS);
+
+ // text: "bcd"
+ // span1: ^^^
+ // span2: ^^
+ // span3:
+ assertEquals("bcd", charSequencesFromString[2].toString());
+ assertSpanCount(0, charSequencesFromString[2]);
+ assertEquals("bcd", charSequencesFromSpanned[2].toString());
+ assertSpanCount(2, charSequencesFromSpanned[2]);
+ assertSpan(charSequencesFromSpanned[2], span1, 0, 3, SPAN1_FLAGS);
+ assertSpan(charSequencesFromSpanned[2], span2, 0, 2, SPAN2_FLAGS);
+
+ // text: "efg"
+ // span1:
+ // span2:
+ // span3:
+ assertEquals("efg", charSequencesFromString[3].toString());
+ assertSpanCount(0, charSequencesFromString[3]);
+ assertEquals("efg", charSequencesFromSpanned[3].toString());
+ assertSpanCount(0, charSequencesFromSpanned[3]);
+
+ // text: "hij"
+ // span1:
+ // span2:
+ // span3: ^
+ assertEquals("hij", charSequencesFromString[4].toString());
+ assertSpanCount(0, charSequencesFromString[4]);
+ assertEquals("hij", charSequencesFromSpanned[4].toString());
+ assertSpanCount(1, charSequencesFromSpanned[4]);
+ assertSpan(charSequencesFromSpanned[4], span3, 1, 2, SPAN3_FLAGS);
+
+ // text: ""
+ // span1:
+ // span2:
+ // span3:
+ assertEquals("", charSequencesFromString[5].toString());
+ assertSpanCount(0, charSequencesFromString[5]);
+ assertEquals("", charSequencesFromSpanned[5].toString());
+ assertSpanCount(0, charSequencesFromSpanned[5]);
+
+ // text: ""
+ // span1:
+ // span2:
+ // span3:
+ assertEquals("", charSequencesFromString[6].toString());
+ assertSpanCount(0, charSequencesFromString[6]);
+ assertEquals("", charSequencesFromSpanned[6].toString());
+ assertSpanCount(0, charSequencesFromSpanned[6]);
+ }
+
+ @Test
+ public void testSplitCharSequencePreserveTrailingEmptySegmengs() {
+ assertEquals(1, SpannableStringUtils.split("", " ",
+ false /* preserveTrailingEmptySegmengs */).length);
+ assertEquals(1, SpannableStringUtils.split(new SpannedString(""), " ",
+ false /* preserveTrailingEmptySegmengs */).length);
+
+ assertEquals(1, SpannableStringUtils.split("", " ",
+ true /* preserveTrailingEmptySegmengs */).length);
+ assertEquals(1, SpannableStringUtils.split(new SpannedString(""), " ",
+ true /* preserveTrailingEmptySegmengs */).length);
+
+ assertEquals(0, SpannableStringUtils.split(" ", " ",
+ false /* preserveTrailingEmptySegmengs */).length);
+ assertEquals(0, SpannableStringUtils.split(new SpannedString(" "), " ",
+ false /* preserveTrailingEmptySegmengs */).length);
+
+ assertEquals(2, SpannableStringUtils.split(" ", " ",
+ true /* preserveTrailingEmptySegmengs */).length);
+ assertEquals(2, SpannableStringUtils.split(new SpannedString(" "), " ",
+ true /* preserveTrailingEmptySegmengs */).length);
+
+ assertEquals(3, SpannableStringUtils.split("a b c ", " ",
+ false /* preserveTrailingEmptySegmengs */).length);
+ assertEquals(3, SpannableStringUtils.split(new SpannedString("a b c "), " ",
+ false /* preserveTrailingEmptySegmengs */).length);
+
+ assertEquals(5, SpannableStringUtils.split("a b c ", " ",
+ true /* preserveTrailingEmptySegmengs */).length);
+ assertEquals(5, SpannableStringUtils.split(new SpannedString("a b c "), " ",
+ true /* preserveTrailingEmptySegmengs */).length);
+
+ assertEquals(6, SpannableStringUtils.split("a b ", " ",
+ false /* preserveTrailingEmptySegmengs */).length);
+ assertEquals(6, SpannableStringUtils.split(new SpannedString("a b "), " ",
+ false /* preserveTrailingEmptySegmengs */).length);
+
+ assertEquals(7, SpannableStringUtils.split("a b ", " ",
+ true /* preserveTrailingEmptySegmengs */).length);
+ assertEquals(7, SpannableStringUtils.split(new SpannedString("a b "), " ",
+ true /* preserveTrailingEmptySegmengs */).length);
+ }
+}
diff --git a/tests/src/org/kelar/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/org/kelar/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
new file mode 100644
index 000000000..77b960a95
--- /dev/null
+++ b/tests/src/org/kelar/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2011 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 org.kelar.inputmethod.latin.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.kelar.inputmethod.latin.R;
+import org.kelar.inputmethod.latin.RichInputMethodManager;
+import org.kelar.inputmethod.latin.RichInputMethodSubtype;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SubtypeLocaleUtilsTests {
+ // All input method subtypes of LatinIME.
+ private final ArrayList<RichInputMethodSubtype> mSubtypesList = new ArrayList<>();
+
+ private RichInputMethodManager mRichImm;
+ private Resources mRes;
+ private InputMethodSubtype mSavedAddtionalSubtypes[];
+
+ InputMethodSubtype EN_US;
+ InputMethodSubtype EN_GB;
+ InputMethodSubtype ES_US;
+ InputMethodSubtype FR;
+ InputMethodSubtype FR_CA;
+ InputMethodSubtype FR_CH;
+ InputMethodSubtype DE;
+ InputMethodSubtype DE_CH;
+ InputMethodSubtype HI;
+ InputMethodSubtype SR;
+ InputMethodSubtype ZZ;
+ InputMethodSubtype DE_QWERTY;
+ InputMethodSubtype FR_QWERTZ;
+ InputMethodSubtype EN_US_AZERTY;
+ InputMethodSubtype EN_UK_DVORAK;
+ InputMethodSubtype ES_US_COLEMAK;
+ InputMethodSubtype ZZ_AZERTY;
+ InputMethodSubtype ZZ_PC;
+
+ // These are preliminary subtypes and may not exist.
+ InputMethodSubtype HI_LATN; // Hinglish
+ InputMethodSubtype SR_LATN; // Serbian Latin
+ InputMethodSubtype HI_LATN_DVORAK; // Hinglis Dvorak
+ InputMethodSubtype SR_LATN_QWERTY; // Serbian Latin Qwerty
+
+ @Before
+ public void setUp() throws Exception {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ mRes = context.getResources();
+ RichInputMethodManager.init(context);
+ mRichImm = RichInputMethodManager.getInstance();
+
+ // Save and reset additional subtypes
+ mSavedAddtionalSubtypes = mRichImm.getAdditionalSubtypes();
+ final InputMethodSubtype[] predefinedAddtionalSubtypes =
+ AdditionalSubtypeUtils.createAdditionalSubtypesArray(
+ AdditionalSubtypeUtils.createPrefSubtypes(
+ mRes.getStringArray(R.array.predefined_subtypes)));
+ mRichImm.setAdditionalInputMethodSubtypes(predefinedAddtionalSubtypes);
+
+ 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(new RichInputMethodSubtype(subtype));
+ }
+
+ EN_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ Locale.US.toString(), "qwerty");
+ EN_GB = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ Locale.UK.toString(), "qwerty");
+ ES_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ "es_US", "spanish");
+ FR = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ 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");
+ HI = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ "hi", "hindi");
+ SR = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ "sr", "south_slavic");
+ ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ SubtypeLocaleUtils.NO_LANGUAGE, "qwerty");
+ DE_QWERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.GERMAN.toString(), "qwerty");
+ FR_QWERTZ = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.FRENCH.toString(), "qwertz");
+ EN_US_AZERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.US.toString(), "azerty");
+ EN_UK_DVORAK = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ Locale.UK.toString(), "dvorak");
+ ES_US_COLEMAK = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ "es_US", "colemak");
+ ZZ_AZERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ SubtypeLocaleUtils.NO_LANGUAGE, "azerty");
+ ZZ_PC = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty");
+
+ HI_LATN = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet("hi_ZZ", "qwerty");
+ if (HI_LATN != null) {
+ HI_LATN_DVORAK = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ "hi_ZZ", "dvorak");
+ }
+ SR_LATN = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet("sr_ZZ", "serbian_qwertz");
+ if (SR_LATN != null) {
+ SR_LATN_QWERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ "sr_ZZ", "qwerty");
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ // Restore additional subtypes.
+ mRichImm.setAdditionalInputMethodSubtypes(mSavedAddtionalSubtypes);
+ }
+
+ @Test
+ public void testAllFullDisplayName() {
+ for (final RichInputMethodSubtype subtype : mSubtypesList) {
+ final String subtypeName = SubtypeLocaleUtils
+ .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype());
+ if (subtype.isNoLanguage()) {
+ final String layoutName = SubtypeLocaleUtils
+ .getKeyboardLayoutSetDisplayName(subtype.getRawSubtype());
+ assertTrue(subtypeName, subtypeName.contains(layoutName));
+ } else {
+ final String languageName = SubtypeLocaleUtils
+ .getSubtypeLocaleDisplayNameInSystemLocale(subtype.getLocale().toString());
+ assertTrue(subtypeName, subtypeName.contains(languageName));
+ }
+ }
+ }
+
+ @Test
+ public void testKeyboardLayoutSetName() {
+ assertEquals("en_US", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(EN_US));
+ assertEquals("en_GB", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(EN_GB));
+ 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("hi", "hindi", SubtypeLocaleUtils.getKeyboardLayoutSetName(HI));
+ assertEquals("sr", "south_slavic", SubtypeLocaleUtils.getKeyboardLayoutSetName(SR));
+ assertEquals("zz", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ));
+
+ assertEquals("de qwerty", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE_QWERTY));
+ assertEquals("fr qwertz", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_QWERTZ));
+ assertEquals("en_US azerty", "azerty",
+ SubtypeLocaleUtils.getKeyboardLayoutSetName(EN_US_AZERTY));
+ assertEquals("en_UK dvorak", "dvorak",
+ SubtypeLocaleUtils.getKeyboardLayoutSetName(EN_UK_DVORAK));
+ assertEquals("es_US colemak", "colemak",
+ SubtypeLocaleUtils.getKeyboardLayoutSetName(ES_US_COLEMAK));
+ assertEquals("zz azerty", "azerty",
+ SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ_AZERTY));
+
+ // These are preliminary subtypes and may not exist.
+ if (HI_LATN != null) {
+ assertEquals("hi_ZZ", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(HI_LATN));
+ assertEquals("hi_ZZ dvorak", "dvorak",
+ SubtypeLocaleUtils.getKeyboardLayoutSetName(HI_LATN_DVORAK));
+ }
+ if (SR_LATN != null) {
+ assertEquals("sr_ZZ", "serbian_qwertz",
+ SubtypeLocaleUtils.getKeyboardLayoutSetName(SR_LATN));
+ assertEquals("sr_ZZ qwerty", "qwerty",
+ SubtypeLocaleUtils.getKeyboardLayoutSetName(SR_LATN_QWERTY));
+ }
+ }
+
+ // InputMethodSubtype's display name in system locale (en_US).
+ // isAdditionalSubtype (T=true, F=false)
+ // locale layout | display name
+ // ------ -------------- - ----------------------
+ // en_US qwerty F English (US) exception
+ // en_GB qwerty F English (UK) exception
+ // 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)
+ // hi hindi F Hindi
+ // hi_ZZ qwerty F Hinglish exception
+ // sr south_slavic F Serbian
+ // sr_ZZ serbian_qwertz F Serbian (Latin) exception
+ // zz qwerty F Alphabet (QWERTY)
+ // fr qwertz T French (QWERTZ)
+ // de qwerty T German (QWERTY)
+ // en_US azerty T English (US) (AZERTY) exception
+ // en_UK dvorak T English (UK) (Dvorak) exception
+ // es_US colemak T Spanish (US) (Colemak) exception
+ // hi_ZZ dvorak T Hinglish (Dvorka) exception
+ // sr_ZZ qwerty T Serbian (QWERTY) exception
+ // zz pc T Alphabet (PC)
+
+ @Test
+ public void testPredefinedSubtypesInEnglishSystemLocale() {
+ final RunInLocale<Void> tests = new RunInLocale<Void>() {
+ @Override
+ protected Void job(final Resources res) {
+ assertEquals("en_US", "English (US)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_US));
+ assertEquals("en_GB", "English (UK)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_GB));
+ assertEquals("es_US", "Spanish (US)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ES_US));
+ assertEquals("fr", "French",
+ 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("hi", "Hindi",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI));
+ assertEquals("sr", "Serbian",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR));
+ assertEquals("zz", "Alphabet (QWERTY)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ));
+ // These are preliminary subtypes and may not exist.
+ if (HI_LATN != null) {
+ assertEquals("hi_ZZ", "Hinglish",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN));
+ }
+ if (SR_LATN != null) {
+ assertEquals("sr_ZZ", "Serbian (Latin)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN));
+ }
+ return null;
+ }
+ };
+ tests.runInLocale(mRes, Locale.ENGLISH);
+ }
+
+ @Test
+ public void testAdditionalSubtypesInEnglishSystemLocale() {
+ final RunInLocale<Void> tests = new RunInLocale<Void>() {
+ @Override
+ protected Void job(final Resources res) {
+ assertEquals("fr qwertz", "French (QWERTZ)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_QWERTZ));
+ assertEquals("de qwerty", "German (QWERTY)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_QWERTY));
+ assertEquals("en_US azerty", "English (US) (AZERTY)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_US_AZERTY));
+ assertEquals("en_UK dvorak","English (UK) (Dvorak)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_UK_DVORAK));
+ assertEquals("es_US colemak", "Spanish (US) (Colemak)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ES_US_COLEMAK));
+ assertEquals("zz azerty", "Alphabet (AZERTY)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_AZERTY));
+ assertEquals("zz pc", "Alphabet (PC)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_PC));
+ // These are preliminary subtypes and may not exist.
+ if (HI_LATN_DVORAK != null) {
+ assertEquals("hi_ZZ", "Hinglish (Dvorak)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN_DVORAK));
+ }
+ if (SR_LATN_QWERTY != null) {
+ assertEquals("sr_ZZ", "Serbian (QWERTY)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN_QWERTY));
+ }
+ return null;
+ }
+ };
+ tests.runInLocale(mRes, Locale.ENGLISH);
+ }
+
+ // InputMethodSubtype's display name in system locale (fr).
+ // isAdditionalSubtype (T=true, F=false)
+ // locale layout | display name
+ // ------ ------- - ----------------------
+ // en_US qwerty F Anglais (États-Unis) exception
+ // en_GB qwerty F Anglais (Royaume-Uni) exception
+ // 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)
+ // hi hindi F Hindi exception
+ // hi_ZZ qwerty F Hindi/Anglais exception
+ // sr south_slavic F Serbe exception
+ // sr_ZZ serbian_qwertz F Serbe (latin) exception
+ // zz qwerty F Alphabet latin (QWERTY)
+ // fr qwertz T Français (QWERTZ)
+ // de qwerty T Allemand (QWERTY)
+ // en_US azerty T Anglais (États-Unis) (AZERTY) exception
+ // en_UK dvorak T Anglais (Royaume-Uni) (Dvorak) exception
+ // es_US colemak T Espagnol (États-Unis) (Colemak) exception
+ // hi_ZZ dvorak T Hindi/Anglais (Dvorka) exception
+ // sr_ZZ qwerty T Serbe (QWERTY) exception
+ // zz pc T Alphabet latin (PC)
+
+ @Test
+ public void testPredefinedSubtypesInFrenchSystemLocale() {
+ final RunInLocale<Void> tests = new RunInLocale<Void>() {
+ @Override
+ protected Void job(final Resources res) {
+ assertEquals("en_US", "Anglais (États-Unis)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_US));
+ assertEquals("en_GB", "Anglais (Royaume-Uni)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_GB));
+ assertEquals("es_US", "Espagnol (États-Unis)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ES_US));
+ assertEquals("fr", "Français",
+ 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("hi", "Hindi",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI));
+ assertEquals("sr", "Serbe",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR));
+ assertEquals("zz", "Alphabet latin (QWERTY)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ));
+ // These are preliminary subtypes and may not exist.
+ if (HI_LATN != null) {
+ assertEquals("hi_ZZ", "Hindi/Anglais",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN));
+ }
+ if (SR_LATN != null) {
+ assertEquals("sr_ZZ", "Serbe (latin)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN));
+ }
+ return null;
+ }
+ };
+ tests.runInLocale(mRes, Locale.FRENCH);
+ }
+
+ @Test
+ public void testAdditionalSubtypesInFrenchSystemLocale() {
+ final RunInLocale<Void> tests = new RunInLocale<Void>() {
+ @Override
+ protected Void job(final Resources res) {
+ assertEquals("fr qwertz", "Français (QWERTZ)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_QWERTZ));
+ assertEquals("de qwerty", "Allemand (QWERTY)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_QWERTY));
+ assertEquals("en_US azerty", "Anglais (États-Unis) (AZERTY)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_US_AZERTY));
+ assertEquals("en_UK dvorak", "Anglais (Royaume-Uni) (Dvorak)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_UK_DVORAK));
+ assertEquals("es_US colemak", "Espagnol (États-Unis) (Colemak)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ES_US_COLEMAK));
+ assertEquals("zz azerty", "Alphabet latin (AZERTY)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_AZERTY));
+ assertEquals("zz pc", "Alphabet latin (PC)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_PC));
+ // These are preliminary subtypes and may not exist.
+ if (HI_LATN_DVORAK != null) {
+ assertEquals("hi_ZZ", "Hindi/Anglais (Dvorak)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN_DVORAK));
+ }
+ if (SR_LATN_QWERTY != null) {
+ assertEquals("sr_ZZ", "Serbe (QWERTY)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN_QWERTY));
+ }
+ return null;
+ }
+ };
+ tests.runInLocale(mRes, Locale.FRENCH);
+ }
+
+ // InputMethodSubtype's display name in system locale (hi).
+ // isAdditionalSubtype (T=true, F=false)
+ // locale layout | display name
+ // ------ ------- - ----------------------
+ // hi hindi F हिन्दी
+ // hi_ZZ qwerty F हिंग्लिश
+ // hi_ZZ dvorak T हिंग्लिश (Dvorak)
+
+ @Test
+ public void testHinglishSubtypesInHindiSystemLocale() {
+ final RunInLocale<Void> tests = new RunInLocale<Void>() {
+ @Override
+ protected Void job (final Resources res) {
+ assertEquals("hi", "हिन्दी",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI));
+ // These are preliminary subtypes and may not exist.
+ if (HI_LATN != null) {
+ assertEquals("hi_ZZ", "हिंग्लिश",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN));
+ assertEquals("hi_ZZ", "हिंग्लिश (Dvorak)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN_DVORAK));
+ }
+ return null;
+ }
+ };
+ tests.runInLocale(mRes, new Locale("hi"));
+ }
+
+ // InputMethodSubtype's display name in system locale (sr).
+ // isAdditionalSubtype (T=true, F=false)
+ // locale layout | display name
+ // ------ -------------- - ----------------------
+ // sr south_slavic F Српски
+ // sr_ZZ serbian_qwertz F Српски (латиница)
+ // sr_ZZ qwerty T Српски (QWERTY)
+
+ @Test
+ public void testSerbianLatinSubtypesInSerbianSystemLocale() {
+ final RunInLocale<Void> tests = new RunInLocale<Void>() {
+ @Override
+ protected Void job (final Resources res) {
+ assertEquals("sr", "Српски",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR));
+ // These are preliminary subtypes and may not exist.
+ if (SR_LATN != null) {
+ assertEquals("sr_ZZ", "Српски (латиница)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN));
+ assertEquals("sr_ZZ", "Српски (QWERTY)",
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN_QWERTY));
+ }
+ return null;
+ }
+ };
+ tests.runInLocale(mRes, new Locale("sr"));
+ }
+
+ @Test
+ 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 RichInputMethodSubtype subtype : mSubtypesList) {
+ final InputMethodSubtype rawSubtype = subtype.getRawSubtype();
+ final String subtypeName = SubtypeLocaleUtils
+ .getSubtypeDisplayNameInSystemLocale(rawSubtype);
+ if (rawSubtype.equals(ARABIC) || rawSubtype.equals(FARSI)
+ || rawSubtype.equals(HEBREW)) {
+ assertTrue(subtypeName, subtype.isRtlSubtype());
+ } else {
+ assertFalse(subtypeName, subtype.isRtlSubtype());
+ }
+ }
+ }
+}