UserHistoryDictionaryTests.java revision a099a3e341d8de0512c8bb8f4dbe352456f2a4a4
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.content.SharedPreferences;
20import android.preference.PreferenceManager;
21import android.test.AndroidTestCase;
22import android.test.suitebuilder.annotation.LargeTest;
23import android.util.Log;
24
25import com.android.inputmethod.latin.ExpandableBinaryDictionary;
26import com.android.inputmethod.latin.utils.CollectionUtils;
27
28import java.io.File;
29import java.util.ArrayList;
30import java.util.List;
31import java.util.Random;
32import java.util.Set;
33import java.util.concurrent.TimeUnit;
34
35/**
36 * Unit tests for UserHistoryDictionary
37 */
38@LargeTest
39public class UserHistoryDictionaryTests extends AndroidTestCase {
40    private static final String TAG = UserHistoryDictionaryTests.class.getSimpleName();
41    private SharedPreferences mPrefs;
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 static final int MIN_USER_HISTORY_DICTIONARY_FILE_SIZE = 1000;
49    private static final int WAIT_TERMINATING_IN_MILLISECONDS = 100;
50
51    @Override
52    public void setUp() {
53        mPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
54    }
55
56    /**
57     * Generates a random word.
58     */
59    private String generateWord(final int value) {
60        final int lengthOfChars = CHARACTERS.length;
61        StringBuilder builder = new StringBuilder();
62        long lvalue = Math.abs((long)value);
63        while (lvalue > 0) {
64            builder.append(CHARACTERS[(int)(lvalue % lengthOfChars)]);
65            lvalue /= lengthOfChars;
66        }
67        return builder.toString();
68    }
69
70    private List<String> generateWords(final int number, final Random random) {
71        final Set<String> wordSet = CollectionUtils.newHashSet();
72        while (wordSet.size() < number) {
73            wordSet.add(generateWord(random.nextInt()));
74        }
75        return new ArrayList<String>(wordSet);
76    }
77
78    private void addToDict(final UserHistoryPredictionDictionary dict, final List<String> words) {
79        String prevWord = null;
80        for (String word : words) {
81            dict.addToPersonalizationPredictionDictionary(prevWord, word, true);
82            prevWord = word;
83        }
84    }
85
86    /**
87     * @param checksContents if true, checks whether written words are actually in the dictionary
88     * or not.
89     */
90    private void addAndWriteRandomWords(final String testFilenameSuffix, final int numberOfWords,
91            final Random random, final boolean checksContents) {
92        final List<String> words = generateWords(numberOfWords, random);
93        final UserHistoryPredictionDictionary dict =
94                PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(),
95                        testFilenameSuffix /* locale */, mPrefs);
96        // Add random words to the user history dictionary.
97        addToDict(dict, words);
98        if (checksContents) {
99            try {
100                Thread.sleep(TimeUnit.MILLISECONDS.convert(5L, TimeUnit.SECONDS));
101            } catch (InterruptedException e) {
102            }
103            for (int i = 0; i < 10 && i < numberOfWords; ++i) {
104                final String word = words.get(i);
105                // This may fail as long as we use tryLock on inserting the bigram words
106                assertTrue(dict.isInDictionaryForTests(word));
107            }
108        }
109        // write to file.
110        dict.close();
111    }
112
113    public void testRandomWords() {
114        File dictFile = null;
115        Log.d(TAG, "This test can be used for profiling.");
116        Log.d(TAG, "Usage: please set UserHistoryDictionary.PROFILE_SAVE_RESTORE to true.");
117        final String testFilenameSuffix = "testRandomWords" + System.currentTimeMillis();
118        final int numberOfWords = 1000;
119        final Random random = new Random(123456);
120
121        try {
122            addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random,
123                    true /* checksContents */);
124        } finally {
125            try {
126                final UserHistoryPredictionDictionary dict =
127                        PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(),
128                                testFilenameSuffix, mPrefs);
129                Log.d(TAG, "waiting for writing ...");
130                dict.shutdownExecutorForTests();
131                while (!dict.isTerminatedForTests()) {
132                    Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS);
133                }
134            } catch (InterruptedException e) {
135                Log.d(TAG, "InterruptedException: " + e);
136            }
137
138            final String fileName = UserHistoryPredictionDictionary.NAME + "." + testFilenameSuffix
139                    + ExpandableBinaryDictionary.DICT_FILE_EXTENSION;
140            dictFile = new File(getContext().getFilesDir(), fileName);
141
142            if (dictFile != null) {
143                assertTrue(dictFile.exists());
144                assertTrue(dictFile.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE);
145                dictFile.delete();
146            }
147        }
148    }
149
150    public void testStressTestForSwitchingLanguagesAndAddingWords() {
151        final int numberOfLanguages = 2;
152        final int numberOfLanguageSwitching = 80;
153        final int numberOfWordsInsertedForEachLanguageSwitch = 100;
154
155        final File dictFiles[] = new File[numberOfLanguages];
156        final String testFilenameSuffixes[] = new String[numberOfLanguages];
157        try {
158            final Random random = new Random(123456);
159
160            // Create filename suffixes for this test.
161            for (int i = 0; i < numberOfLanguages; i++) {
162                testFilenameSuffixes[i] = "testSwitchingLanguages" + i;
163                final String fileName = UserHistoryPredictionDictionary.NAME + "." +
164                        testFilenameSuffixes[i] + ExpandableBinaryDictionary.DICT_FILE_EXTENSION;
165                dictFiles[i] = new File(getContext().getFilesDir(), fileName);
166            }
167
168            final long start = System.currentTimeMillis();
169
170            for (int i = 0; i < numberOfLanguageSwitching; i++) {
171                final int index = i % numberOfLanguages;
172                // Switch languages to testFilenameSuffixes[index].
173                addAndWriteRandomWords(testFilenameSuffixes[index],
174                        numberOfWordsInsertedForEachLanguageSwitch, random,
175                        false /* checksContents */);
176            }
177
178            final long end = System.currentTimeMillis();
179            Log.d(TAG, "testStressTestForSwitchingLanguageAndAddingWords took "
180                    + (end - start) + " ms");
181        } finally {
182            try {
183                Log.d(TAG, "waiting for writing ...");
184                for (int i = 0; i < numberOfLanguages; i++) {
185                    final UserHistoryPredictionDictionary dict =
186                            PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(),
187                                    testFilenameSuffixes[i], mPrefs);
188                    dict.shutdownExecutorForTests();
189                    while (!dict.isTerminatedForTests()) {
190                        Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS);
191                    }
192                }
193            } catch (InterruptedException e) {
194                Log.d(TAG, "InterruptedException: " + e);
195            }
196            for (final File file : dictFiles) {
197                if (file != null) {
198                    assertTrue(file.exists());
199                    assertTrue(file.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE);
200                    file.delete();
201                }
202            }
203        }
204    }
205}
206