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.latin.personalization;
18 
19 import android.content.Context;
20 
21 import com.android.inputmethod.latin.BinaryDictionary;
22 import com.android.inputmethod.latin.NgramContext;
23 import com.android.inputmethod.latin.NgramContext.WordInfo;
24 import com.android.inputmethod.latin.common.FileUtils;
25 
26 import java.io.File;
27 import java.io.FilenameFilter;
28 import java.util.ArrayList;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Locale;
32 import java.util.Random;
33 
34 /**
35  * Utility class for helping while running tests involving {@link UserHistoryDictionary}.
36  */
37 public class UserHistoryDictionaryTestsHelper {
38 
39     /**
40      * Locale prefix for generating placeholder locales for tests.
41      */
42     public static final String TEST_LOCALE_PREFIX = "test-";
43 
44     /**
45      * Characters for generating random words.
46      */
47     private static final String[] CHARACTERS = {
48         "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
49         "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
50     };
51 
52     /**
53      * Remove all the test dictionary files created for the given locale.
54      */
removeAllTestDictFiles(final String filter, final Context context)55     public static void removeAllTestDictFiles(final String filter, final Context context) {
56         final FilenameFilter filenameFilter = new FilenameFilter() {
57             @Override
58             public boolean accept(final File dir, final String filename) {
59                 return filename.startsWith(UserHistoryDictionary.NAME + "." + filter);
60             }
61         };
62         FileUtils.deleteFilteredFiles(context.getFilesDir(), filenameFilter);
63     }
64 
65     /**
66      * Generates and writes random words to dictionary. Caller can be assured
67      * that the write tasks would be finished; and its success would be reflected
68      * in the returned boolean.
69      *
70      * @param dict {@link UserHistoryDictionary} to which words should be added.
71      * @param numberOfWords number of words to be added.
72      * @param random helps generate random words.
73      * @param checkContents if true, checks whether written words are actually in the dictionary.
74      * @param currentTime timestamp that would be used for adding the words.
75      * @returns true if all words have been written to dictionary successfully.
76      */
addAndWriteRandomWords(final UserHistoryDictionary dict, final int numberOfWords, final Random random, final boolean checkContents, final int currentTime)77     public static boolean addAndWriteRandomWords(final UserHistoryDictionary dict,
78             final int numberOfWords, final Random random, final boolean checkContents,
79             final int currentTime) {
80         final List<String> words = generateWords(numberOfWords, random);
81         // Add random words to the user history dictionary.
82         addWordsToDictionary(dict, words, currentTime);
83         boolean success = true;
84         if (checkContents) {
85             dict.waitAllTasksForTests();
86             for (int i = 0; i < numberOfWords; ++i) {
87                 final String word = words.get(i);
88                 if (!dict.isInDictionary(word)) {
89                     success = false;
90                     break;
91                 }
92             }
93         }
94         // write to file.
95         dict.close();
96         dict.waitAllTasksForTests();
97         return success;
98     }
99 
addWordsToDictionary(final UserHistoryDictionary dict, final List<String> words, final int timestamp)100     private static void addWordsToDictionary(final UserHistoryDictionary dict,
101             final List<String> words, final int timestamp) {
102         NgramContext ngramContext = NgramContext.getEmptyPrevWordsContext(
103                 BinaryDictionary.MAX_PREV_WORD_COUNT_FOR_N_GRAM);
104         for (final String word : words) {
105             UserHistoryDictionary.addToDictionary(dict, ngramContext, word, true, timestamp);
106             ngramContext = ngramContext.getNextNgramContext(new WordInfo(word));
107         }
108     }
109 
110     /**
111      * Creates unique test locale for using within tests.
112      */
getFakeLocale(final String name)113     public static Locale getFakeLocale(final String name) {
114         return new Locale(TEST_LOCALE_PREFIX + name + System.currentTimeMillis());
115     }
116 
117     /**
118      * Generates random words.
119      *
120      * @param numberOfWords number of words to generate.
121      * @param random salt used for generating random words.
122      */
generateWords(final int numberOfWords, final Random random)123     public static List<String> generateWords(final int numberOfWords, final Random random) {
124         final HashSet<String> wordSet = new HashSet<>();
125         while (wordSet.size() < numberOfWords) {
126             wordSet.add(generateWord(random.nextInt()));
127         }
128         return new ArrayList<>(wordSet);
129     }
130 
131     /**
132      * Generates a random word.
133      */
generateWord(final int value)134     private static String generateWord(final int value) {
135         final int lengthOfChars = CHARACTERS.length;
136         final StringBuilder builder = new StringBuilder();
137         long lvalue = Math.abs((long)value);
138         while (lvalue > 0) {
139             builder.append(CHARACTERS[(int)(lvalue % lengthOfChars)]);
140             lvalue /= lengthOfChars;
141         }
142         return builder.toString();
143     }
144 }
145