1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.inputmethod.keyboard.layout.tests; 18 19 import android.util.Log; 20 import android.view.inputmethod.InputMethodSubtype; 21 22 import com.android.inputmethod.keyboard.Key; 23 import com.android.inputmethod.keyboard.Keyboard; 24 import com.android.inputmethod.keyboard.KeyboardId; 25 import com.android.inputmethod.keyboard.KeyboardLayoutSet; 26 import com.android.inputmethod.keyboard.KeyboardLayoutSetTestsBase; 27 import com.android.inputmethod.keyboard.KeyboardTheme; 28 import com.android.inputmethod.keyboard.layout.LayoutBase; 29 import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase; 30 import com.android.inputmethod.keyboard.layout.expected.ActualKeyboardBuilder; 31 import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; 32 import com.android.inputmethod.keyboard.layout.expected.ExpectedKey.ExpectedAdditionalMoreKey; 33 import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; 34 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; 35 36 import java.util.Arrays; 37 38 /** 39 * Base class for keyboard layout unit test. 40 */ 41 abstract class LayoutTestsBase extends KeyboardLayoutSetTestsBase { 42 private LayoutBase mLayout; 43 private InputMethodSubtype mSubtype; 44 private String mLogTag; 45 private KeyboardLayoutSet mKeyboardLayoutSet; 46 47 @Override 48 protected void setUp() throws Exception { 49 super.setUp(); 50 51 mLayout = getLayout(); 52 mSubtype = getSubtype(mLayout.getLocale(), mLayout.getName()); 53 mLogTag = SubtypeLocaleUtils.getSubtypeNameForLogging(mSubtype) + "/" 54 + (isPhone() ? "phone" : "tablet"); 55 // TODO: Test with language switch key enabled and disabled. 56 mKeyboardLayoutSet = createKeyboardLayoutSet(mSubtype, null /* editorInfo */, 57 true /* voiceInputKeyEnabled */, true /* languageSwitchKeyEnabled */, 58 false /* splitLayoutEnabled */); 59 } 60 61 @Override 62 protected int getKeyboardThemeForTests() { 63 return KeyboardTheme.THEME_ID_KLP; 64 } 65 66 // Those helper methods have a lower case name to be readable when defining expected keyboard 67 // layouts. 68 69 // Helper method to create an {@link ExpectedKey} object that has the label. 70 static ExpectedKey key(final String label, final ExpectedKey ... moreKeys) { 71 return AbstractLayoutBase.key(label, moreKeys); 72 } 73 74 // Helper method to create an {@link ExpectedKey} object that has the label and the output text. 75 static ExpectedKey key(final String label, final String outputText, 76 final ExpectedKey ... moreKeys) { 77 return AbstractLayoutBase.key(label, outputText, moreKeys); 78 } 79 80 // Helper method to create an {@link ExpectedKey} object that has new "more keys". 81 static ExpectedKey key(final ExpectedKey key, final ExpectedKey ... moreKeys) { 82 return AbstractLayoutBase.key(key, moreKeys); 83 } 84 85 // Helper method to create an {@link ExpectedAdditionalMoreKey} object for an 86 // "additional more key" that has the label. 87 public static ExpectedAdditionalMoreKey additionalMoreKey(final String label) { 88 return AbstractLayoutBase.additionalMoreKey(label); 89 } 90 91 // Helper method to create an {@link ExpectedKey} object for a "more key" that has the label. 92 static ExpectedKey moreKey(final String label) { 93 return AbstractLayoutBase.moreKey(label); 94 } 95 96 // Helper method to create an {@link ExpectedKey} object for a "more key" that has the label 97 // and the output text. 98 static ExpectedKey moreKey(final String label, final String outputText) { 99 return AbstractLayoutBase.moreKey(label, outputText); 100 } 101 102 // Helper method to create {@link ExpectedKey} array by joining {@link ExpectedKey}, 103 // {@link ExpectedKey} array, and {@link String}. 104 static ExpectedKey[] joinMoreKeys(final Object ... moreKeys) { 105 return AbstractLayoutBase.joinKeys(moreKeys); 106 } 107 108 // Helper method to create {@link ExpectedKey} array by joining {@link ExpectedKey}, 109 // {@link ExpectedKey} array, and {@link String}. 110 static ExpectedKey[] joinKeys(final Object ... keys) { 111 return AbstractLayoutBase.joinKeys(keys); 112 } 113 114 // Keyboard layout for testing subtype. 115 abstract LayoutBase getLayout(); 116 117 ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { 118 return builder; 119 } 120 121 // TODO: Add phone, phone symbols, number, number password layout tests. 122 123 public final void testLayouts() { 124 doKeyboardTests(KeyboardId.ELEMENT_ALPHABET); 125 doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED); 126 doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED); 127 doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED); 128 doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED); 129 doKeyboardTests(KeyboardId.ELEMENT_SYMBOLS); 130 doKeyboardTests(KeyboardId.ELEMENT_SYMBOLS_SHIFTED); 131 } 132 133 // Comparing expected keyboard and actual keyboard. 134 private void doKeyboardTests(final int elementId) { 135 final ExpectedKey[][] expectedKeyboard = mLayout.getLayout(isPhone(), elementId); 136 // Skip test if no keyboard is defined. 137 if (expectedKeyboard == null) { 138 return; 139 } 140 final String tag = mLogTag + "/" + KeyboardId.elementIdToName(elementId); 141 // Create actual keyboard object. 142 final Keyboard keyboard = mKeyboardLayoutSet.getKeyboard(elementId); 143 // Create actual keyboard to be compared with the expected keyboard. 144 final Key[][] actualKeyboard = ActualKeyboardBuilder.buildKeyboard( 145 keyboard.getSortedKeys()); 146 147 // Dump human readable definition of expected/actual keyboards. 148 Log.d(tag, "expected=\n" + ExpectedKeyboardBuilder.toString(expectedKeyboard)); 149 Log.d(tag, "actual =\n" + ActualKeyboardBuilder.toString(actualKeyboard)); 150 // Test both keyboards have the same number of rows. 151 assertEquals(tag + " labels" 152 + "\nexpected=" + ExpectedKeyboardBuilder.toString(expectedKeyboard) 153 + "\nactual =" + ActualKeyboardBuilder.toString(actualKeyboard), 154 expectedKeyboard.length, actualKeyboard.length); 155 for (int r = 0; r < actualKeyboard.length; r++) { 156 final int row = r + 1; 157 // Test both keyboards' rows have the same number of columns. 158 assertEquals(tag + " labels row=" + row 159 + "\nexpected=" + Arrays.toString(expectedKeyboard[r]) 160 + "\nactual =" + ActualKeyboardBuilder.toString(actualKeyboard[r]), 161 expectedKeyboard[r].length, actualKeyboard[r].length); 162 for (int c = 0; c < actualKeyboard[r].length; c++) { 163 final int column = c + 1; 164 final Key actualKey = actualKeyboard[r][c]; 165 final ExpectedKey expectedKey = expectedKeyboard[r][c]; 166 // Test both keyboards' keys have the same visual outlook and key output. 167 assertTrue(tag + " labels row,column=" + row + "," + column 168 + "\nexpected=" + expectedKey 169 + "\nactual =" + ActualKeyboardBuilder.toString(actualKey), 170 expectedKey.equalsTo(actualKey)); 171 } 172 } 173 } 174 } 175