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