UserHistoryDictionaryTests.java revision e5a35711b854aedeeea2f45105b941b9deee49bc
184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada/* 284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * Copyright (C) 2012 The Android Open Source Project 384d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * 484d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * Licensed under the Apache License, Version 2.0 (the "License"); 584d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * you may not use this file except in compliance with the License. 684d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * You may obtain a copy of the License at 784d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * 884d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * http://www.apache.org/licenses/LICENSE-2.0 984d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * 1084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * Unless required by applicable law or agreed to in writing, software 1184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * distributed under the License is distributed on an "AS IS" BASIS, 1284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1384d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * See the License for the specific language governing permissions and 1484d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * limitations under the License. 1584d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada */ 1684d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada 17ffcbbaf12788a9fc9398607a548e552d7d2bf05eSatoshi Kataokapackage com.android.inputmethod.latin.personalization; 1884d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada 1984d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadaimport android.content.SharedPreferences; 2084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadaimport android.preference.PreferenceManager; 2184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadaimport android.test.AndroidTestCase; 22b4598f7d05d6afd01ddc7ea0bed71dda837d1debTadashi G. Takaokaimport android.test.suitebuilder.annotation.LargeTest; 2384d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadaimport android.util.Log; 2484d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada 258aaae56cf6694ec75043be56f1c7812a343b24d5Yuichiro Hanadaimport com.android.inputmethod.latin.ExpandableBinaryDictionary; 26e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CollectionUtils; 27e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasa 286def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanadaimport java.io.File; 2984d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadaimport java.util.ArrayList; 3084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadaimport java.util.List; 3184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadaimport java.util.Random; 3284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadaimport java.util.Set; 330d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanadaimport java.util.concurrent.TimeUnit; 3484d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada 3584d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada/** 3684d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * Unit tests for UserHistoryDictionary 3784d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada */ 38b4598f7d05d6afd01ddc7ea0bed71dda837d1debTadashi G. Takaoka@LargeTest 3984d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadapublic class UserHistoryDictionaryTests extends AndroidTestCase { 4084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada private static final String TAG = UserHistoryDictionaryTests.class.getSimpleName(); 4184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada private SharedPreferences mPrefs; 4284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada 4384d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada private static final String[] CHARACTERS = { 4484d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", 4584d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" 4684d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada }; 4784d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada 480d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada private static final int MIN_USER_HISTORY_DICTIONARY_FILE_SIZE = 1000; 490d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada 5084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada @Override 5184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada public void setUp() { 5284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada mPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 5384d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada } 5484d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada 5584d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada /** 5684d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * Generates a random word. 5784d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada */ 5884d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada private String generateWord(final int value) { 5984d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada final int lengthOfChars = CHARACTERS.length; 6084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada StringBuilder builder = new StringBuilder(); 6184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada long lvalue = Math.abs((long)value); 6284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada while (lvalue > 0) { 6384d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada builder.append(CHARACTERS[(int)(lvalue % lengthOfChars)]); 6484d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada lvalue /= lengthOfChars; 6584d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada } 6684d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada return builder.toString(); 6784d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada } 6884d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada 6984d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada private List<String> generateWords(final int number, final Random random) { 7084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada final Set<String> wordSet = CollectionUtils.newHashSet(); 7184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada while (wordSet.size() < number) { 7284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada wordSet.add(generateWord(random.nextInt())); 7384d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada } 7484d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada return new ArrayList<String>(wordSet); 7584d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada } 7684d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada 7787d06afc66db68f0b30b36593095511314793517Satoshi Kataoka private void addToDict(final UserHistoryPredictionDictionary dict, final List<String> words) { 7884d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada String prevWord = null; 7984d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada for (String word : words) { 8084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada dict.forceAddWordForTest(prevWord, word, true); 8184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada prevWord = word; 8284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada } 8384d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada } 8484d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada 85e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka /** 86e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka * @param checksContents if true, checks whether written words are actually in the dictionary 87e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka * or not. 88e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka */ 898aaae56cf6694ec75043be56f1c7812a343b24d5Yuichiro Hanada private void addAndWriteRandomWords(final String testFilenameSuffix, final int numberOfWords, 90e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka final Random random, final boolean checksContents) { 910d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada final List<String> words = generateWords(numberOfWords, random); 920d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada final UserHistoryPredictionDictionary dict = 936e04d6593239e841f5dac0d3f32d613967c11e22Keisuke Kuroyanagi PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(), 948aaae56cf6694ec75043be56f1c7812a343b24d5Yuichiro Hanada testFilenameSuffix /* locale */, mPrefs); 950d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada // Add random words to the user history dictionary. 960d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada addToDict(dict, words); 97e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka if (checksContents) { 98e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka try { 99e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka Thread.sleep(TimeUnit.MILLISECONDS.convert(5L, TimeUnit.SECONDS)); 100e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka } catch (InterruptedException e) { 101e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka } 102e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka for (int i = 0; i < 10 && i < numberOfWords; ++i) { 103e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka final String word = words.get(i); 104e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka // This may fail as long as we use tryLock on inserting the bigram words 105e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka assertTrue(dict.isInDictionaryForTests(word)); 106e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka } 107e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka } 1080d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada // write to file. 1090d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada dict.close(); 1100d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada } 1110d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada 11284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada public void testRandomWords() { 1136def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanada File dictFile = null; 1140d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada Log.d(TAG, "This test can be used for profiling."); 1150d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada Log.d(TAG, "Usage: please set UserHistoryDictionary.PROFILE_SAVE_RESTORE to true."); 1168aaae56cf6694ec75043be56f1c7812a343b24d5Yuichiro Hanada final String testFilenameSuffix = "testRandomWords" + System.currentTimeMillis(); 1170d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada final int numberOfWords = 1000; 1180d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada final Random random = new Random(123456); 1196def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanada 1200d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada try { 121e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random, 122e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka true /* checksContents */); 1230d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada } finally { 1246def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanada try { 1250d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada Log.d(TAG, "waiting for writing ..."); 1260d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada Thread.sleep(TimeUnit.MILLISECONDS.convert(5L, TimeUnit.SECONDS)); 1276def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanada } catch (InterruptedException e) { 1286def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanada Log.d(TAG, "InterruptedException: " + e); 1296def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanada } 1306def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanada 1318aaae56cf6694ec75043be56f1c7812a343b24d5Yuichiro Hanada final String fileName = UserHistoryPredictionDictionary.NAME + "." + testFilenameSuffix 1328aaae56cf6694ec75043be56f1c7812a343b24d5Yuichiro Hanada + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; 1330d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada dictFile = new File(getContext().getFilesDir(), fileName); 1346def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanada 1356def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanada if (dictFile != null) { 1360d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada assertTrue(dictFile.exists()); 1370d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada assertTrue(dictFile.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE); 1386def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanada dictFile.delete(); 1396def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanada } 14084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada } 14184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada } 14228a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi 14328a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi public void testStressTestForSwitchingLanguagesAndAddingWords() { 14428a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi final int numberOfLanguages = 2; 1450d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada final int numberOfLanguageSwitching = 80; 1460d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada final int numberOfWordsInsertedForEachLanguageSwitch = 100; 14728a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi 14828a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi final File dictFiles[] = new File[numberOfLanguages]; 14928a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi try { 15028a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi final Random random = new Random(123456); 15128a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi 1520d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada // Create filename suffixes for this test. 1530d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada String testFilenameSuffixes[] = new String[numberOfLanguages]; 15428a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi for (int i = 0; i < numberOfLanguages; i++) { 1550d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada testFilenameSuffixes[i] = "testSwitchingLanguages" + i; 1568aaae56cf6694ec75043be56f1c7812a343b24d5Yuichiro Hanada final String fileName = UserHistoryPredictionDictionary.NAME + "." + 1578aaae56cf6694ec75043be56f1c7812a343b24d5Yuichiro Hanada testFilenameSuffixes[i] + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; 15828a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi dictFiles[i] = new File(getContext().getFilesDir(), fileName); 15928a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi } 16028a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi 1610d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada final long start = System.currentTimeMillis(); 16228a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi 16328a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi for (int i = 0; i < numberOfLanguageSwitching; i++) { 16428a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi final int index = i % numberOfLanguages; 1650d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada // Switch languages to testFilenameSuffixes[index]. 1660d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada addAndWriteRandomWords(testFilenameSuffixes[index], 167e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka numberOfWordsInsertedForEachLanguageSwitch, random, 168e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka false /* checksContents */); 16928a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi } 17028a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi 17128a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi final long end = System.currentTimeMillis(); 17228a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi Log.d(TAG, "testStressTestForSwitchingLanguageAndAddingWords took " 1730d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada + (end - start) + " ms"); 1740d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada } finally { 17528a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi try { 17628a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi Log.d(TAG, "waiting for writing ..."); 1770d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada Thread.sleep(TimeUnit.MILLISECONDS.convert(5L, TimeUnit.SECONDS)); 17828a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi } catch (InterruptedException e) { 17928a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi Log.d(TAG, "InterruptedException: " + e); 18028a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi } 18128a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi for (final File file : dictFiles) { 18228a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi if (file != null) { 1830d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada assertTrue(file.exists()); 1840d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada assertTrue(file.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE); 18528a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi file.delete(); 18628a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi } 18728a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi } 18828a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi } 18928a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi } 19084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada} 191