From c39c912a331c9993438783c6eb03910aa314813d Mon Sep 17 00:00:00 2001
From: "Tadashi G. Takaoka" <takaoka@google.com>
Date: Thu, 6 Mar 2014 17:21:07 +0900
Subject: [PATCH] Add ExpectedKey for testing keyboard layouts

Bug: 13017434
Change-Id: I1c3b2c9cd1b86bdd782fc522b83380ec112f863b
---
 .../keyboard/layout/expected/ExpectedKey.java | 186 ++++++++++++++++++
 .../layout/expected/ExpectedKeyOutput.java    | 138 +++++++++++++
 .../layout/expected/ExpectedKeyVisual.java    | 135 +++++++++++++
 3 files changed, 459 insertions(+)
 create mode 100644 tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java
 create mode 100644 tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java
 create mode 100644 tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java

diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java
new file mode 100644
index 0000000000..e22d75cd71
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout.expected;
+
+import com.android.inputmethod.keyboard.Key;
+import com.android.inputmethod.keyboard.internal.MoreKeySpec;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * This class represents an expected key.
+ */
+public class ExpectedKey {
+    static ExpectedKey EMPTY_KEY = newInstance("");
+
+    // A key that has a string label and may have "more keys".
+    static ExpectedKey newInstance(final String label, final ExpectedKey ... moreKeys) {
+        return newInstance(label, label, moreKeys);
+    }
+
+    // A key that has a string label and a different output text and may have "more keys".
+    static ExpectedKey newInstance(final String label, final String outputText,
+            final ExpectedKey ... moreKeys) {
+        return newInstance(ExpectedKeyVisual.newInstance(label),
+                ExpectedKeyOutput.newInstance(outputText), moreKeys);
+    }
+
+    // A key that has a string label and a code point output and may have "more keys".
+    static ExpectedKey newInstance(final String label, final int code,
+            final ExpectedKey ... moreKeys) {
+        return newInstance(ExpectedKeyVisual.newInstance(label),
+                ExpectedKeyOutput.newInstance(code), moreKeys);
+    }
+
+    // A key that has an icon and a code point output and may have "more keys".
+    static ExpectedKey newInstance(final int iconId, final int code,
+            final ExpectedKey ... moreKeys) {
+        return newInstance(ExpectedKeyVisual.newInstance(iconId),
+                ExpectedKeyOutput.newInstance(code), moreKeys);
+    }
+
+    static ExpectedKey newInstance(final ExpectedKeyVisual visual, final ExpectedKeyOutput output,
+            final ExpectedKey ... moreKeys) {
+        if (moreKeys.length == 0) {
+            return new ExpectedKey(visual, output);
+        }
+        return new ExpectedKeyWithMoreKeys(visual, output, moreKeys);
+    }
+
+    private static final ExpectedKey[] EMPTY_KEYS = new ExpectedKey[0];
+
+    // The expected visual outlook of this key.
+    private final ExpectedKeyVisual mVisual;
+    // The expected output of this key.
+    private final ExpectedKeyOutput mOutput;
+
+    public final ExpectedKeyVisual getVisual() {
+        return mVisual;
+    }
+
+    public final ExpectedKeyOutput getOutput() {
+        return mOutput;
+    }
+
+    public ExpectedKey[] getMoreKeys() {
+        // This key has no "more keys".
+        return EMPTY_KEYS;
+    }
+
+    protected ExpectedKey(final ExpectedKeyVisual visual, final ExpectedKeyOutput output) {
+        mVisual = visual;
+        mOutput = output;
+    }
+
+    public ExpectedKey toUpperCase(Locale locale) {
+        return newInstance(mVisual.toUpperCase(locale), mOutput.toUpperCase(locale));
+    }
+
+    public boolean equalsTo(final Key key) {
+        // This key has no "more keys".
+        return mVisual.equalsTo(key) && mOutput.equalsTo(key) && key.getMoreKeys() == null;
+    }
+
+    public boolean equalsTo(final MoreKeySpec moreKeySpec) {
+        return mVisual.equalsTo(moreKeySpec) && mOutput.equalsTo(moreKeySpec);
+    }
+
+    @Override
+    public boolean equals(final Object object) {
+        if (object instanceof ExpectedKey) {
+            final ExpectedKey key = (ExpectedKey)object;
+            return mVisual.equalsTo(key.mVisual) && mOutput.equalsTo(key.mOutput)
+                    && Arrays.equals(getMoreKeys(), key.getMoreKeys());
+        }
+        return false;
+    }
+
+    private static int hashCode(final Object ... objects) {
+        return Arrays.hashCode(objects);
+    }
+
+    @Override
+    public int hashCode() {
+        return hashCode(mVisual, mOutput, getMoreKeys());
+    }
+
+    @Override
+    public String toString() {
+        if (mVisual.equalsTo(mOutput)) {
+            return mVisual.toString();
+        }
+        return mVisual + "|" + mOutput;
+    }
+
+    /**
+     * This class represents an expected key that has "more keys".
+     */
+    private static final class ExpectedKeyWithMoreKeys extends ExpectedKey {
+        private final ExpectedKey[] mMoreKeys;
+
+        ExpectedKeyWithMoreKeys(final ExpectedKeyVisual visual,
+                final ExpectedKeyOutput output, final ExpectedKey ... moreKeys) {
+            super(visual, output);
+            mMoreKeys = moreKeys;
+        }
+
+        @Override
+        public ExpectedKey toUpperCase(final Locale locale) {
+            final ExpectedKey[] upperCaseMoreKeys = new ExpectedKey[mMoreKeys.length];
+            for (int i = 0; i < mMoreKeys.length; i++) {
+                upperCaseMoreKeys[i] = mMoreKeys[i].toUpperCase(locale);
+            }
+            return newInstance(getVisual().toUpperCase(locale), getOutput().toUpperCase(locale),
+                    upperCaseMoreKeys);
+        }
+
+        @Override
+        public ExpectedKey[] getMoreKeys() {
+            return mMoreKeys;
+        }
+
+        @Override
+        public boolean equalsTo(final Key key) {
+            if (getVisual().equalsTo(key) && getOutput().equalsTo(key)) {
+                final MoreKeySpec[] moreKeys = key.getMoreKeys();
+                // This key should have at least one "more key".
+                if (moreKeys == null || moreKeys.length != mMoreKeys.length) {
+                    return false;
+                }
+                for (int index = 0; index < moreKeys.length; index++) {
+                    if (!mMoreKeys[index].equalsTo(moreKeys[index])) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean equalsTo(final MoreKeySpec moreKeySpec) {
+            // MoreKeySpec has no "more keys".
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + "^" + Arrays.toString(mMoreKeys);
+        }
+    }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java
new file mode 100644
index 0000000000..1be51e60b0
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout.expected;
+
+import com.android.inputmethod.keyboard.Key;
+import com.android.inputmethod.keyboard.internal.MoreKeySpec;
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.utils.StringUtils;
+
+import java.util.Locale;
+
+/**
+ * This class represents an expected output of a key.
+ *
+ * There are two types of expected output, an integer code point and a string output text.
+ */
+abstract class ExpectedKeyOutput {
+    static ExpectedKeyOutput newInstance(final int code) {
+        return new Code(code);
+    }
+
+    static ExpectedKeyOutput newInstance(final String outputText) {
+        // If the <code>outputText</code> is one code point string, use {@link CodePoint} object.
+        if (StringUtils.codePointCount(outputText) == 1) {
+            return new Code(outputText.codePointAt(0));
+        }
+        return new Text(outputText);
+    }
+
+    abstract ExpectedKeyOutput toUpperCase(final Locale locale);
+    abstract boolean equalsTo(final String text);
+    abstract boolean equalsTo(final Key key);
+    abstract boolean equalsTo(final MoreKeySpec moreKeySpec);
+    abstract boolean equalsTo(final ExpectedKeyOutput output);
+
+    /**
+     * This class represents an integer code point.
+     */
+    private static class Code extends ExpectedKeyOutput {
+        // UNICODE code point or a special negative value defined in {@link Constants}.
+        private final int mCode;
+
+        Code(final int code) { mCode = code; }
+
+        @Override
+        ExpectedKeyOutput toUpperCase(final Locale locale) {
+            if (Constants.isLetterCode(mCode)) {
+                final String codeString = StringUtils.newSingleCodePointString(mCode);
+                // A letter may have an upper case counterpart that consists of multiple code
+                // points, for instance the upper case of "ß" is "SS".
+                return newInstance(codeString.toUpperCase(locale));
+            }
+            // A special negative value has no upper case.
+            return this;
+        }
+
+        @Override
+        boolean equalsTo(final String text) {
+            return StringUtils.codePointCount(text) == 1 && text.codePointAt(0) == mCode;
+        }
+
+        @Override
+        boolean equalsTo(final Key key) {
+            return mCode == key.getCode();
+        }
+
+        @Override
+        boolean equalsTo(final MoreKeySpec moreKeySpec) {
+            return mCode == moreKeySpec.mCode;
+        }
+
+        @Override
+        boolean equalsTo(final ExpectedKeyOutput output) {
+            return (output instanceof Code) && mCode == ((Code)output).mCode;
+        }
+
+        @Override
+        public String toString() {
+            return Constants.isLetterCode(mCode) ? StringUtils.newSingleCodePointString(mCode)
+                    : Constants.printableCode(mCode);
+        }
+    }
+
+    /**
+     * This class represents a string output text.
+     */
+    private static class Text extends ExpectedKeyOutput {
+        private final String mText;
+
+        Text(final String text) { mText = text; }
+
+        @Override
+        ExpectedKeyOutput toUpperCase(final Locale locale) {
+            return newInstance(mText.toUpperCase(locale));
+        }
+
+        @Override
+        boolean equalsTo(final String text) {
+            return text.equals(text);
+        }
+
+        @Override
+        boolean equalsTo(final Key key) {
+            return key.getCode() == Constants.CODE_OUTPUT_TEXT
+                    && mText.equals(key.getOutputText());
+        }
+
+        @Override
+        boolean equalsTo(final MoreKeySpec moreKeySpec) {
+            return moreKeySpec.mCode == Constants.CODE_OUTPUT_TEXT
+                    && mText.equals(moreKeySpec.mOutputText);
+        }
+
+        @Override
+        boolean equalsTo(final ExpectedKeyOutput output) {
+            return (output instanceof Text) && mText == ((Text)output).mText;
+        }
+
+        @Override
+        public String toString() {
+            return mText;
+        }
+    }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java
new file mode 100644
index 0000000000..0a0da32b61
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.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 com.android.inputmethod.keyboard.layout.expected;
+
+import com.android.inputmethod.keyboard.Key;
+import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
+import com.android.inputmethod.keyboard.internal.MoreKeySpec;
+
+import java.util.Locale;
+
+/**
+ * This class represents an expected visual outlook of a key.
+ *
+ * There are two types of expected visual, an integer icon id and a string label.
+ */
+abstract class ExpectedKeyVisual {
+    static ExpectedKeyVisual newInstance(final String label) {
+        return new Label(label);
+    }
+
+    static ExpectedKeyVisual newInstance(final int iconId) {
+        return new Icon(iconId);
+    }
+
+    abstract ExpectedKeyVisual toUpperCase(final Locale locale);
+    abstract boolean equalsTo(final String text);
+    abstract boolean equalsTo(final Key key);
+    abstract boolean equalsTo(final MoreKeySpec moreKeySpec);
+    abstract boolean equalsTo(final ExpectedKeyOutput output);
+    abstract boolean equalsTo(final ExpectedKeyVisual visual);
+
+    /**
+     * This class represents an integer icon id.
+     */
+    private static class Icon extends ExpectedKeyVisual {
+        private final int mIconId;
+
+        Icon(final int iconId) {
+            mIconId = iconId;
+        }
+
+        @Override
+        ExpectedKeyVisual toUpperCase(final Locale locale) {
+            return this;
+        }
+
+        @Override
+        boolean equalsTo(final String text) {
+            return false;
+        }
+
+        @Override
+        boolean equalsTo(final Key key) {
+            return mIconId == key.getIconId();
+        }
+
+        @Override
+        boolean equalsTo(final MoreKeySpec moreKeySpec) {
+            return mIconId == moreKeySpec.mIconId;
+        }
+
+        @Override
+        boolean equalsTo(final ExpectedKeyOutput output) {
+            return false;
+        }
+
+        @Override
+        boolean equalsTo(final ExpectedKeyVisual visual) {
+            return (visual instanceof Icon) && mIconId == ((Icon)visual).mIconId;
+        }
+
+        @Override
+        public String toString() {
+            return KeyboardIconsSet.getIconName(mIconId);
+        }
+    }
+
+    /**
+     * This class represents a string label.
+     */
+    private static class Label extends ExpectedKeyVisual {
+        private final String mLabel;
+
+        Label(final String label) { mLabel = label; }
+
+        @Override
+        ExpectedKeyVisual toUpperCase(final Locale locale) {
+            return new Label(mLabel.toUpperCase(locale));
+        }
+
+        @Override
+        boolean equalsTo(final String text) {
+            return mLabel.equals(text);
+        }
+
+        @Override
+        boolean equalsTo(final Key key) {
+            return mLabel.equals(key.getLabel());
+        }
+
+        @Override
+        boolean equalsTo(final MoreKeySpec moreKeySpec) {
+            return mLabel.equals(moreKeySpec.mLabel);
+        }
+
+        @Override
+        boolean equalsTo(final ExpectedKeyOutput output) {
+            return output.equalsTo(mLabel);
+        }
+
+        @Override
+        boolean equalsTo(final ExpectedKeyVisual visual) {
+            return (visual instanceof Label) && mLabel.equals(((Label)visual).mLabel);
+        }
+
+        @Override
+        public String toString() {
+            return mLabel;
+        }
+    }
+}
-- 
GitLab