UserHistoryDictionaryTests.java revision 0bc66daae36ef7a1f2db1e2fd5c22abfe1b20163
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.inputmethod.latin.personalization; 18 19import android.test.AndroidTestCase; 20import android.test.suitebuilder.annotation.LargeTest; 21import android.util.Log; 22 23import com.android.inputmethod.latin.BinaryDictionary; 24import com.android.inputmethod.latin.ExpandableBinaryDictionary; 25import com.android.inputmethod.latin.utils.CollectionUtils; 26import com.android.inputmethod.latin.utils.FileUtils; 27 28import java.io.File; 29import java.util.ArrayList; 30import java.util.List; 31import java.util.Locale; 32import java.util.Random; 33import java.util.Set; 34import java.util.concurrent.TimeUnit; 35 36/** 37 * Unit tests for UserHistoryDictionary 38 */ 39@LargeTest 40public class UserHistoryDictionaryTests extends AndroidTestCase { 41 private static final String TAG = UserHistoryDictionaryTests.class.getSimpleName(); 42 43 private static final String[] CHARACTERS = { 44 "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", 45 "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" 46 }; 47 48 private int mCurrentTime = 0; 49 50 @Override 51 protected void setUp() throws Exception { 52 super.setUp(); 53 mCurrentTime = 0; 54 setCurrentTimeForTestMode(mCurrentTime); 55 } 56 57 @Override 58 protected void tearDown() throws Exception { 59 stopTestModeInNativeCode(); 60 super.tearDown(); 61 } 62 63 private void forcePassingShortTime() { 64 // 4 days. 65 final int timeToElapse = (int)TimeUnit.DAYS.toSeconds(4); 66 mCurrentTime += timeToElapse; 67 setCurrentTimeForTestMode(mCurrentTime); 68 } 69 70 private void forcePassingLongTime() { 71 // 60 days. 72 final int timeToElapse = (int)TimeUnit.DAYS.toSeconds(60); 73 mCurrentTime += timeToElapse; 74 setCurrentTimeForTestMode(mCurrentTime); 75 } 76 77 private static int setCurrentTimeForTestMode(final int currentTime) { 78 return BinaryDictionary.setCurrentTimeForTest(currentTime); 79 } 80 81 private static int stopTestModeInNativeCode() { 82 return BinaryDictionary.setCurrentTimeForTest(-1); 83 } 84 85 /** 86 * Generates a random word. 87 */ 88 private static String generateWord(final int value) { 89 final int lengthOfChars = CHARACTERS.length; 90 StringBuilder builder = new StringBuilder(); 91 long lvalue = Math.abs((long)value); 92 while (lvalue > 0) { 93 builder.append(CHARACTERS[(int)(lvalue % lengthOfChars)]); 94 lvalue /= lengthOfChars; 95 } 96 return builder.toString(); 97 } 98 99 private static List<String> generateWords(final int number, final Random random) { 100 final Set<String> wordSet = CollectionUtils.newHashSet(); 101 while (wordSet.size() < number) { 102 wordSet.add(generateWord(random.nextInt())); 103 } 104 return new ArrayList<String>(wordSet); 105 } 106 107 private static void addToDict(final UserHistoryDictionary dict, final List<String> words) { 108 String prevWord = null; 109 for (String word : words) { 110 dict.addToDictionary(prevWord, word, true, 111 (int)TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); 112 prevWord = word; 113 } 114 } 115 116 /** 117 * @param checkContents if true, checks whether written words are actually in the dictionary 118 * or not. 119 */ 120 private void addAndWriteRandomWords(final Locale locale, final int numberOfWords, 121 final Random random, final boolean checkContents) { 122 final List<String> words = generateWords(numberOfWords, random); 123 final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary( 124 mContext, locale); 125 // Add random words to the user history dictionary. 126 addToDict(dict, words); 127 if (checkContents) { 128 dict.waitAllTasksForTests(); 129 for (int i = 0; i < numberOfWords; ++i) { 130 final String word = words.get(i); 131 assertTrue(dict.isInUnderlyingBinaryDictionaryForTests(word)); 132 } 133 } 134 // write to file. 135 dict.close(); 136 } 137 138 /** 139 * Clear all entries in the user history dictionary. 140 * @param locale dummy locale for testing. 141 */ 142 private void clearHistory(final Locale locale) { 143 final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary( 144 mContext, locale); 145 dict.waitAllTasksForTests(); 146 dict.clearAndFlushDictionary(); 147 dict.close(); 148 dict.waitAllTasksForTests(); 149 } 150 151 /** 152 * Shut down executer and wait until all operations of user history are done. 153 * @param locale dummy locale for testing. 154 */ 155 private void waitForWriting(final Locale locale) { 156 final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary( 157 mContext, locale); 158 dict.waitAllTasksForTests(); 159 } 160 161 public void testRandomWords() { 162 Log.d(TAG, "This test can be used for profiling."); 163 Log.d(TAG, "Usage: please set UserHistoryDictionary.PROFILE_SAVE_RESTORE to true."); 164 final Locale dummyLocale = new Locale("test_random_words" + System.currentTimeMillis()); 165 final String dictName = ExpandableBinaryDictionary.getDictName( 166 UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */); 167 final File dictFile = ExpandableBinaryDictionary.getDictFile( 168 mContext, dictName, null /* dictFile */); 169 170 final int numberOfWords = 1000; 171 final Random random = new Random(123456); 172 173 try { 174 clearHistory(dummyLocale); 175 addAndWriteRandomWords(dummyLocale, numberOfWords, random, 176 true /* checksContents */); 177 } finally { 178 Log.d(TAG, "waiting for writing ..."); 179 waitForWriting(dummyLocale); 180 assertTrue("check exisiting of " + dictFile, dictFile.exists()); 181 FileUtils.deleteRecursively(dictFile); 182 } 183 } 184 185 public void testStressTestForSwitchingLanguagesAndAddingWords() { 186 final int numberOfLanguages = 2; 187 final int numberOfLanguageSwitching = 80; 188 final int numberOfWordsInsertedForEachLanguageSwitch = 100; 189 190 final File dictFiles[] = new File[numberOfLanguages]; 191 final Locale dummyLocales[] = new Locale[numberOfLanguages]; 192 try { 193 final Random random = new Random(123456); 194 195 // Create filename suffixes for this test. 196 for (int i = 0; i < numberOfLanguages; i++) { 197 dummyLocales[i] = new Locale("test_switching_languages" + i); 198 final String dictName = ExpandableBinaryDictionary.getDictName( 199 UserHistoryDictionary.NAME, dummyLocales[i], null /* dictFile */); 200 dictFiles[i] = ExpandableBinaryDictionary.getDictFile( 201 mContext, dictName, null /* dictFile */); 202 clearHistory(dummyLocales[i]); 203 } 204 205 final long start = System.currentTimeMillis(); 206 207 for (int i = 0; i < numberOfLanguageSwitching; i++) { 208 final int index = i % numberOfLanguages; 209 // Switch languages to testFilenameSuffixes[index]. 210 addAndWriteRandomWords(dummyLocales[index], 211 numberOfWordsInsertedForEachLanguageSwitch, random, 212 false /* checksContents */); 213 } 214 215 final long end = System.currentTimeMillis(); 216 Log.d(TAG, "testStressTestForSwitchingLanguageAndAddingWords took " 217 + (end - start) + " ms"); 218 } finally { 219 Log.d(TAG, "waiting for writing ..."); 220 for (int i = 0; i < numberOfLanguages; i++) { 221 waitForWriting(dummyLocales[i]); 222 } 223 for (final File dictFile : dictFiles) { 224 assertTrue("check exisiting of " + dictFile, dictFile.exists()); 225 FileUtils.deleteRecursively(dictFile); 226 } 227 } 228 } 229 230 public void testAddManyWords() { 231 final Locale dummyLocale = new Locale("test_random_words" + System.currentTimeMillis()); 232 final String dictName = ExpandableBinaryDictionary.getDictName( 233 UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */); 234 final File dictFile = ExpandableBinaryDictionary.getDictFile( 235 mContext, dictName, null /* dictFile */); 236 final int numberOfWords = 10000; 237 final Random random = new Random(123456); 238 clearHistory(dummyLocale); 239 try { 240 addAndWriteRandomWords(dummyLocale, numberOfWords, random, true /* checksContents */); 241 } finally { 242 Log.d(TAG, "waiting for writing ..."); 243 waitForWriting(dummyLocale); 244 assertTrue("check exisiting of " + dictFile, dictFile.exists()); 245 FileUtils.deleteRecursively(dictFile); 246 } 247 } 248 249 public void testDecaying() { 250 final Locale dummyLocale = new Locale("test_decaying" + System.currentTimeMillis()); 251 final int numberOfWords = 5000; 252 final Random random = new Random(123456); 253 clearHistory(dummyLocale); 254 final List<String> words = generateWords(numberOfWords, random); 255 final UserHistoryDictionary dict = 256 PersonalizationHelper.getUserHistoryDictionary(getContext(), dummyLocale); 257 String prevWord = null; 258 for (final String word : words) { 259 dict.addToDictionary(prevWord, word, true, mCurrentTime); 260 prevWord = word; 261 assertTrue(dict.isInUnderlyingBinaryDictionaryForTests(word)); 262 } 263 forcePassingShortTime(); 264 for (final String word : words) { 265 assertTrue(dict.isInUnderlyingBinaryDictionaryForTests(word)); 266 } 267 forcePassingLongTime(); 268 for (final String word : words) { 269 assertFalse(dict.isInUnderlyingBinaryDictionaryForTests(word)); 270 } 271 } 272} 273