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.test.AndroidTestCase;
20b4598f7d05d6afd01ddc7ea0bed71dda837d1debTadashi G. Takaokaimport android.test.suitebuilder.annotation.LargeTest;
2184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadaimport android.util.Log;
2284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada
238aaae56cf6694ec75043be56f1c7812a343b24d5Yuichiro Hanadaimport com.android.inputmethod.latin.ExpandableBinaryDictionary;
24e507d92aa3ee4ae43124c5452f20aa8ed0ecef4cKeisuke Kuroyanagiimport com.android.inputmethod.latin.PrevWordsInfo;
25e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagiimport com.android.inputmethod.latin.PrevWordsInfo.WordInfo;
26e784148ae6872942434eaa55ca32b4c6442cc8e8Keisuke Kuroyanagiimport com.android.inputmethod.latin.utils.BinaryDictionaryUtils;
2717bd4eb0c984125d968ca05a567180c2bd3761f6Keisuke Kuroyanagiimport com.android.inputmethod.latin.utils.DistracterFilter;
280cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaokaimport com.android.inputmethod.latin.utils.FileUtils;
29e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasa
306def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanadaimport java.io.File;
3184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadaimport java.util.ArrayList;
32a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaokaimport java.util.HashSet;
3384d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadaimport java.util.List;
342fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport java.util.Locale;
3584d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadaimport java.util.Random;
360d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanadaimport java.util.concurrent.TimeUnit;
3784d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada
3884d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada/**
3984d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada * Unit tests for UserHistoryDictionary
4084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada */
41b4598f7d05d6afd01ddc7ea0bed71dda837d1debTadashi G. Takaoka@LargeTest
4284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanadapublic class UserHistoryDictionaryTests extends AndroidTestCase {
4384d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada    private static final String TAG = UserHistoryDictionaryTests.class.getSimpleName();
4484d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada
4584d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada    private static final String[] CHARACTERS = {
4684d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada        "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
4784d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada        "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
4884d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada    };
4984d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada
500bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    private int mCurrentTime = 0;
510bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi
520bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    @Override
530bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    protected void setUp() throws Exception {
540bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        super.setUp();
5521f94829994d5a5c2773605fec6b7eeef920c646Keisuke Kuroyanagi        resetCurrentTimeForTestMode();
560bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    }
570bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi
580bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    @Override
590bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    protected void tearDown() throws Exception {
600bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        stopTestModeInNativeCode();
610bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        super.tearDown();
620bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    }
630bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi
6421f94829994d5a5c2773605fec6b7eeef920c646Keisuke Kuroyanagi    private void resetCurrentTimeForTestMode() {
6521f94829994d5a5c2773605fec6b7eeef920c646Keisuke Kuroyanagi        mCurrentTime = 0;
6621f94829994d5a5c2773605fec6b7eeef920c646Keisuke Kuroyanagi        setCurrentTimeForTestMode(mCurrentTime);
6721f94829994d5a5c2773605fec6b7eeef920c646Keisuke Kuroyanagi    }
6821f94829994d5a5c2773605fec6b7eeef920c646Keisuke Kuroyanagi
690bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    private void forcePassingShortTime() {
7021f94829994d5a5c2773605fec6b7eeef920c646Keisuke Kuroyanagi        // 3 days.
7121f94829994d5a5c2773605fec6b7eeef920c646Keisuke Kuroyanagi        final int timeToElapse = (int)TimeUnit.DAYS.toSeconds(3);
720bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        mCurrentTime += timeToElapse;
730bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        setCurrentTimeForTestMode(mCurrentTime);
740bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    }
750bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi
760bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    private void forcePassingLongTime() {
7773a2426d455e6e83dd9402913889f80a0071f0acKeisuke Kuroyanagi        // 365 days.
7873a2426d455e6e83dd9402913889f80a0071f0acKeisuke Kuroyanagi        final int timeToElapse = (int)TimeUnit.DAYS.toSeconds(365);
790bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        mCurrentTime += timeToElapse;
800bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        setCurrentTimeForTestMode(mCurrentTime);
810bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    }
820bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi
830bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    private static int setCurrentTimeForTestMode(final int currentTime) {
84e784148ae6872942434eaa55ca32b4c6442cc8e8Keisuke Kuroyanagi        return BinaryDictionaryUtils.setCurrentTimeForTest(currentTime);
850bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    }
860bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi
870bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    private static int stopTestModeInNativeCode() {
88e784148ae6872942434eaa55ca32b4c6442cc8e8Keisuke Kuroyanagi        return BinaryDictionaryUtils.setCurrentTimeForTest(-1);
890bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    }
900bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi
9184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada    /**
9284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada     * Generates a random word.
9384d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada     */
940cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka    private static String generateWord(final int value) {
9584d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada        final int lengthOfChars = CHARACTERS.length;
9684d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada        StringBuilder builder = new StringBuilder();
9784d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada        long lvalue = Math.abs((long)value);
9884d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada        while (lvalue > 0) {
9984d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada            builder.append(CHARACTERS[(int)(lvalue % lengthOfChars)]);
10084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada            lvalue /= lengthOfChars;
10184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada        }
10284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada        return builder.toString();
10384d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada    }
10484d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada
1050cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka    private static List<String> generateWords(final int number, final Random random) {
106a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka        final HashSet<String> wordSet = new HashSet<>();
10784d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada        while (wordSet.size() < number) {
10884d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada            wordSet.add(generateWord(random.nextInt()));
10984d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada        }
110a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka        return new ArrayList<>(wordSet);
11184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada    }
11284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada
1130cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka    private static void addToDict(final UserHistoryDictionary dict, final List<String> words) {
114a790c5b68324da41428aeb68594d43ca5632f66dKeisuke Kuroyanagi        PrevWordsInfo prevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
11584d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada        for (String word : words) {
116e507d92aa3ee4ae43124c5452f20aa8ed0ecef4cKeisuke Kuroyanagi            UserHistoryDictionary.addToDictionary(dict, prevWordsInfo, word, true,
11717bd4eb0c984125d968ca05a567180c2bd3761f6Keisuke Kuroyanagi                    (int)TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()),
11817bd4eb0c984125d968ca05a567180c2bd3761f6Keisuke Kuroyanagi                    DistracterFilter.EMPTY_DISTRACTER_FILTER);
119e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            prevWordsInfo = prevWordsInfo.getNextPrevWordsInfo(new WordInfo(word));
12084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada        }
12184d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada    }
12284d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada
123e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka    /**
124a328f538c34ad2dafdfa53642085cb1072224d80Yuichiro Hanada     * @param checkContents if true, checks whether written words are actually in the dictionary
125e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka     * or not.
126e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka     */
1270cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka    private void addAndWriteRandomWords(final Locale locale, final int numberOfWords,
128a328f538c34ad2dafdfa53642085cb1072224d80Yuichiro Hanada            final Random random, final boolean checkContents) {
1290d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        final List<String> words = generateWords(numberOfWords, random);
1300cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka        final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary(
1310cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                mContext, locale);
1320d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        // Add random words to the user history dictionary.
1330d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        addToDict(dict, words);
134a328f538c34ad2dafdfa53642085cb1072224d80Yuichiro Hanada        if (checkContents) {
1352fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            dict.waitAllTasksForTests();
136a328f538c34ad2dafdfa53642085cb1072224d80Yuichiro Hanada            for (int i = 0; i < numberOfWords; ++i) {
137e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka                final String word = words.get(i);
1381910392eeddf2c9f4c1d34925e64f8d8772e7dc4Keisuke Kuroyanagi                assertTrue(dict.isInDictionary(word));
139e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka            }
140e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka        }
1410d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        // write to file.
1420d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        dict.close();
1430d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada    }
1440d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada
14511f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi    /**
14611f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi     * Clear all entries in the user history dictionary.
1470cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka     * @param locale dummy locale for testing.
14811f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi     */
1490cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka    private void clearHistory(final Locale locale) {
1500cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka        final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary(
1510cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                mContext, locale);
15268069c55c49d21dcccd0a90369cd0fd61982d8cfKeisuke Kuroyanagi        dict.waitAllTasksForTests();
1532dcb5c1b4d399501fc7645bf933f08f3a0e7e512Keisuke Kuroyanagi        dict.clear();
15411f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi        dict.close();
15568069c55c49d21dcccd0a90369cd0fd61982d8cfKeisuke Kuroyanagi        dict.waitAllTasksForTests();
15611f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi    }
15711f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi
15811f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi    /**
15911f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi     * Shut down executer and wait until all operations of user history are done.
1600cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka     * @param locale dummy locale for testing.
16111f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi     */
1620cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka    private void waitForWriting(final Locale locale) {
1630cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka        final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary(
1640cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                mContext, locale);
1652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        dict.waitAllTasksForTests();
16611f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi    }
16711f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi
16884d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada    public void testRandomWords() {
1690d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        Log.d(TAG, "This test can be used for profiling.");
1700d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        Log.d(TAG, "Usage: please set UserHistoryDictionary.PROFILE_SAVE_RESTORE to true.");
1710cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka        final Locale dummyLocale = new Locale("test_random_words" + System.currentTimeMillis());
1720cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka        final String dictName = ExpandableBinaryDictionary.getDictName(
1730cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */);
1740cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka        final File dictFile = ExpandableBinaryDictionary.getDictFile(
1750cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                mContext, dictName, null /* dictFile */);
17611f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi
1770d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        final int numberOfWords = 1000;
1780d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        final Random random = new Random(123456);
1796def28d1dacb0f02c08d91c8be3ed877624f74abYuichiro Hanada
1800d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        try {
1810cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka            clearHistory(dummyLocale);
1820cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka            addAndWriteRandomWords(dummyLocale, numberOfWords, random,
183e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka                    true /* checksContents */);
1840d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        } finally {
18511f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi            Log.d(TAG, "waiting for writing ...");
1860cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka            waitForWriting(dummyLocale);
1870cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka            assertTrue("check exisiting of " + dictFile, dictFile.exists());
1880cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka            FileUtils.deleteRecursively(dictFile);
18984d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada        }
19084d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada    }
19128a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi
19228a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi    public void testStressTestForSwitchingLanguagesAndAddingWords() {
19328a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi        final int numberOfLanguages = 2;
1940d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        final int numberOfLanguageSwitching = 80;
1950d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        final int numberOfWordsInsertedForEachLanguageSwitch = 100;
19628a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi
19728a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi        final File dictFiles[] = new File[numberOfLanguages];
1980cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka        final Locale dummyLocales[] = new Locale[numberOfLanguages];
19928a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi        try {
20028a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi            final Random random = new Random(123456);
20128a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi
2020d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada            // Create filename suffixes for this test.
20328a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi            for (int i = 0; i < numberOfLanguages; i++) {
2040cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                dummyLocales[i] = new Locale("test_switching_languages" + i);
2050cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                final String dictName = ExpandableBinaryDictionary.getDictName(
2060cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                        UserHistoryDictionary.NAME, dummyLocales[i], null /* dictFile */);
2070cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                dictFiles[i] = ExpandableBinaryDictionary.getDictFile(
2080cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                        mContext, dictName, null /* dictFile */);
2090cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                clearHistory(dummyLocales[i]);
21028a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi            }
21128a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi
2120d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada            final long start = System.currentTimeMillis();
21328a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi
21428a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi            for (int i = 0; i < numberOfLanguageSwitching; i++) {
21528a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi                final int index = i % numberOfLanguages;
2160d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada                // Switch languages to testFilenameSuffixes[index].
2170cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                addAndWriteRandomWords(dummyLocales[index],
218e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka                        numberOfWordsInsertedForEachLanguageSwitch, random,
219e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka                        false /* checksContents */);
22028a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi            }
22128a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi
22228a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi            final long end = System.currentTimeMillis();
22328a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi            Log.d(TAG, "testStressTestForSwitchingLanguageAndAddingWords took "
2240d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada                    + (end - start) + " ms");
2250d70bcc821c22f7001b66f4c7b83842661b8391eYuichiro Hanada        } finally {
22611f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi            Log.d(TAG, "waiting for writing ...");
22711f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi            for (int i = 0; i < numberOfLanguages; i++) {
2280cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                waitForWriting(dummyLocales[i]);
22928a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi            }
2300cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka            for (final File dictFile : dictFiles) {
2310cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                assertTrue("check exisiting of " + dictFile, dictFile.exists());
2320cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                FileUtils.deleteRecursively(dictFile);
23328a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi            }
23428a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi        }
23528a70b63c5748783c3b6fcac551cb69852840474Keisuke Kuroynagi    }
2362e58670da9687fd1fd28c322e03343957d11568cKeisuke Kuroyanagi
2372e58670da9687fd1fd28c322e03343957d11568cKeisuke Kuroyanagi    public void testAddManyWords() {
2380cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka        final Locale dummyLocale = new Locale("test_random_words" + System.currentTimeMillis());
2390cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka        final String dictName = ExpandableBinaryDictionary.getDictName(
2400cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */);
2410cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka        final File dictFile = ExpandableBinaryDictionary.getDictFile(
2420cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka                mContext, dictName, null /* dictFile */);
2432fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final int numberOfWords = 10000;
2442e58670da9687fd1fd28c322e03343957d11568cKeisuke Kuroyanagi        final Random random = new Random(123456);
2450cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka        clearHistory(dummyLocale);
2462e58670da9687fd1fd28c322e03343957d11568cKeisuke Kuroyanagi        try {
2470cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka            addAndWriteRandomWords(dummyLocale, numberOfWords, random, true /* checksContents */);
2482e58670da9687fd1fd28c322e03343957d11568cKeisuke Kuroyanagi        } finally {
24911f7cae094720c3ab47e6c18772b1fc44e9e5372Keisuke Kuroyanagi            Log.d(TAG, "waiting for writing ...");
2500cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka            waitForWriting(dummyLocale);
2510cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka            assertTrue("check exisiting of " + dictFile, dictFile.exists());
2520cda0e8a9ceaeab5a0e918c4fc76f77770d89b2cTadashi G. Takaoka            FileUtils.deleteRecursively(dictFile);
2532e58670da9687fd1fd28c322e03343957d11568cKeisuke Kuroyanagi        }
2542e58670da9687fd1fd28c322e03343957d11568cKeisuke Kuroyanagi    }
2550bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi
2560bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    public void testDecaying() {
2570bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        final Locale dummyLocale = new Locale("test_decaying" + System.currentTimeMillis());
2580bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        final int numberOfWords = 5000;
2590bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        final Random random = new Random(123456);
26021f94829994d5a5c2773605fec6b7eeef920c646Keisuke Kuroyanagi        resetCurrentTimeForTestMode();
2610bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        clearHistory(dummyLocale);
2620bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        final List<String> words = generateWords(numberOfWords, random);
2630bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        final UserHistoryDictionary dict =
2640bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi                PersonalizationHelper.getUserHistoryDictionary(getContext(), dummyLocale);
26521f94829994d5a5c2773605fec6b7eeef920c646Keisuke Kuroyanagi        dict.waitAllTasksForTests();
266e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        PrevWordsInfo prevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
2670bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        for (final String word : words) {
26817bd4eb0c984125d968ca05a567180c2bd3761f6Keisuke Kuroyanagi            UserHistoryDictionary.addToDictionary(dict, prevWordsInfo, word, true, mCurrentTime,
26917bd4eb0c984125d968ca05a567180c2bd3761f6Keisuke Kuroyanagi                    DistracterFilter.EMPTY_DISTRACTER_FILTER);
270e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            prevWordsInfo = prevWordsInfo.getNextPrevWordsInfo(new WordInfo(word));
2711737b7ff5c59b68693b85a410d5b5a901407087eKeisuke Kuroyanagi            dict.waitAllTasksForTests();
2721910392eeddf2c9f4c1d34925e64f8d8772e7dc4Keisuke Kuroyanagi            assertTrue(dict.isInDictionary(word));
2730bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        }
2740bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        forcePassingShortTime();
275d302b98ce63743bde9d8d8c14755b5cf71c4e7a3Keisuke Kuroyanagi        dict.runGCIfRequired();
27621f94829994d5a5c2773605fec6b7eeef920c646Keisuke Kuroyanagi        dict.waitAllTasksForTests();
2770bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        for (final String word : words) {
2781910392eeddf2c9f4c1d34925e64f8d8772e7dc4Keisuke Kuroyanagi            assertTrue(dict.isInDictionary(word));
2790bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        }
2800bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        forcePassingLongTime();
281d302b98ce63743bde9d8d8c14755b5cf71c4e7a3Keisuke Kuroyanagi        dict.runGCIfRequired();
28221f94829994d5a5c2773605fec6b7eeef920c646Keisuke Kuroyanagi        dict.waitAllTasksForTests();
2830bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        for (final String word : words) {
2841910392eeddf2c9f4c1d34925e64f8d8772e7dc4Keisuke Kuroyanagi            assertFalse(dict.isInDictionary(word));
2850bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi        }
2860bc66daae36ef7a1f2db1e2fd5c22abfe1b20163Keisuke Kuroyanagi    }
28784d858ed5e187eb9d4b56b593e1d9287f762bbcaYuichiro Hanada}
288