Check contents in user history dictionary tests

Bug: 10667710

Change-Id: I45ebb08cb4ef9a9f6d2da31e2c50e740f88209c2
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index e62a35a..11d6cb2 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -24,6 +24,7 @@
 import com.android.inputmethod.keyboard.ProximityInfo;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.personalization.DynamicPersonalizationDictionaryWriter;
+import com.android.inputmethod.latin.personalization.DynamicPredictionDictionaryBase;
 import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.io.File;
@@ -72,7 +73,7 @@
     private BinaryDictionary mBinaryDictionary;
 
     /** The in-memory dictionary used to generate the binary dictionary. */
-    private AbstractDictionaryWriter mDictionaryWriter;
+    protected AbstractDictionaryWriter mDictionaryWriter;
 
     /**
      * The name of this dictionary, used as the filename for storing the binary dictionary. Multiple
@@ -624,4 +625,35 @@
             mLocalDictionaryController.writeLock().unlock();
         }
     }
+
+    // TODO: Implement native binary methods once the dynamic dictionary implementation is done.
+    @UsedForTesting
+    public boolean isInDictionaryForTests(final String word) {
+        mLocalDictionaryController.writeLock().lock();
+        try {
+            if (mDictType == Dictionary.TYPE_USER_HISTORY) {
+                return ((DynamicPersonalizationDictionaryWriter) mDictionaryWriter)
+                        .isInDictionaryForTests(word);
+            }
+        } finally {
+            mLocalDictionaryController.writeLock().unlock();
+        }
+        return false;
+    }
+
+    // TODO: Remove and use addToPersonalizationPredictionDictionary instead!!!!!!!!!!!!!!!!
+    @UsedForTesting
+    public void forceAddWordForTest(
+            final String word0, final String word1, final boolean isValid) {
+        mLocalDictionaryController.writeLock().lock();
+        try {
+            mDictionaryWriter.addUnigramWord(word1, null /* the "shortcut" parameter is null */,
+                    DynamicPredictionDictionaryBase.FREQUENCY_FOR_TYPED, false /* isNotAWord */);
+            mDictionaryWriter.addBigramWords(word0, word1,
+                    DynamicPredictionDictionaryBase.FREQUENCY_FOR_TYPED, isValid,
+                    0 /* lastTouchedTime */);
+        } finally {
+            mLocalDictionaryController.writeLock().unlock();
+        }
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index 342dcfc..ba7d1a2 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -265,10 +265,10 @@
         return (node == null) ? false : !node.mShortcutOnly;
     }
 
-    public boolean removeBigram(final String word1, final String word2) {
+    public boolean removeBigram(final String word0, final String word1) {
         // Refer to addOrSetBigram() about word1.toLowerCase()
-        final Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null);
-        final Node secondWord = searchWord(mRoots, word2, 0, null);
+        final Node firstWord = searchWord(mRoots, word0.toLowerCase(), 0, null);
+        final Node secondWord = searchWord(mRoots, word1, 0, null);
         LinkedList<NextWord> bigrams = firstWord.mNGrams;
         NextWord bigramNode = null;
         if (bigrams == null || bigrams.size() == 0) {
@@ -297,10 +297,10 @@
         return (node == null) ? -1 : node.mFrequency;
     }
 
-    public NextWord getBigramWord(final String word1, final String word2) {
-        // Refer to addOrSetBigram() about word1.toLowerCase()
-        final Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null);
-        final Node secondWord = searchWord(mRoots, word2, 0, null);
+    public NextWord getBigramWord(final String word0, final String word1) {
+        // Refer to addOrSetBigram() about word0.toLowerCase()
+        final Node firstWord = searchWord(mRoots, word0.toLowerCase(), 0, null);
+        final Node secondWord = searchWord(mRoots, word1, 0, null);
         LinkedList<NextWord> bigrams = firstWord.mNGrams;
         if (bigrams == null || bigrams.size() == 0) {
             return null;
@@ -473,37 +473,41 @@
         }
     }
 
-    public int setBigramAndGetFrequency(final String word1, final String word2,
+    public int setBigramAndGetFrequency(final String word0, final String word1,
             final int frequency) {
-        return setBigramAndGetFrequency(word1, word2, frequency, null /* unused */);
+        return setBigramAndGetFrequency(word0, word1, frequency, null /* unused */);
     }
 
-    public int setBigramAndGetFrequency(final String word1, final String word2,
+    public int setBigramAndGetFrequency(final String word0, final String word1,
             final ForgettingCurveParams fcp) {
-        return setBigramAndGetFrequency(word1, word2, 0 /* unused */, fcp);
+        return setBigramAndGetFrequency(word0, word1, 0 /* unused */, fcp);
     }
 
     /**
      * Adds bigrams to the in-memory trie structure that is being used to retrieve any word
-     * @param word1 the first word of this bigram
-     * @param word2 the second word of this bigram
+     * @param word0 the first word of this bigram
+     * @param word1 the second word of this bigram
      * @param frequency frequency for this bigram
      * @param fcp an instance of ForgettingCurveParams to use for decay policy
      * @return returns the final bigram frequency
      */
-    private int setBigramAndGetFrequency(final String word1, final String word2,
+    private int setBigramAndGetFrequency(final String word0, final String word1,
             final int frequency, final ForgettingCurveParams fcp) {
+        if (TextUtils.isEmpty(word0)) {
+            Log.e(TAG, "Invalid bigram previous word: " + word0);
+            return frequency;
+        }
         // We don't want results to be different according to case of the looked up left hand side
         // word. We do want however to return the correct case for the right hand side.
         // So we want to squash the case of the left hand side, and preserve that of the right
         // hand side word.
-        final String word1Lower = word1.toLowerCase();
-        if (TextUtils.isEmpty(word1Lower) || TextUtils.isEmpty(word2)) {
-            Log.e(TAG, "Invalid bigram pair: " + word1 + ", " + word1Lower + ", " + word2);
+        final String word0Lower = word0.toLowerCase();
+        if (TextUtils.isEmpty(word0Lower) || TextUtils.isEmpty(word1)) {
+            Log.e(TAG, "Invalid bigram pair: " + word0 + ", " + word0Lower + ", " + word1);
             return frequency;
         }
-        final Node firstWord = searchWord(mRoots, word1Lower, 0, null);
-        final Node secondWord = searchWord(mRoots, word2, 0, null);
+        final Node firstWord = searchWord(mRoots, word0Lower, 0, null);
+        final Node secondWord = searchWord(mRoots, word1, 0, null);
         LinkedList<NextWord> bigrams = firstWord.mNGrams;
         if (bigrams == null || bigrams.size() == 0) {
             firstWord.mNGrams = CollectionUtils.newLinkedList();
diff --git a/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java b/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java
index d446606..e43e74d 100644
--- a/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java
+++ b/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 
+import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.keyboard.ProximityInfo;
 import com.android.inputmethod.latin.AbstractDictionaryWriter;
 import com.android.inputmethod.latin.ExpandableDictionary;
@@ -156,4 +157,10 @@
     public boolean isValidWord(final String word) {
         return mExpandableDictionary.isValidWord(word);
     }
+
+    @UsedForTesting
+    public boolean isInDictionaryForTests(final String word) {
+        // TODO: Use native method to determine whether the word is in dictionary or not
+        return mBigramList.containsKey(word);
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java
index a08145b..be4c7c4 100644
--- a/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java
+++ b/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java
@@ -196,12 +196,6 @@
         return mLocale;
     }
 
-    @UsedForTesting
-    /* package for test */ void forceAddWordForTest(
-            final String word0, final String word1, final boolean isValid) {
-        addToPersonalizationPredictionDictionary(word0, word1, isValid);
-    }
-
     public void registerUpdateSession(PersonalizationDictionaryUpdateSession session) {
         session.setPredictionDictionary(this);
         mSessions.add(session);
diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java
index 6c2c9e2..4c1803b 100644
--- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java
+++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java
@@ -97,6 +97,10 @@
         return mBigramMap.isEmpty();
     }
 
+    public boolean containsKey(String word) {
+        return mBigramMap.containsKey(word);
+    }
+
     public Set<String> keySet() {
         return mBigramMap.keySet();
     }
diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
index 1fd1b8a..1a20ec5 100644
--- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
@@ -82,14 +82,29 @@
         }
     }
 
+    /**
+     * @param checksContents if true, checks whether written words are actually in the dictionary
+     * or not.
+     */
     private void addAndWriteRandomWords(final String testFilenameSuffix, final int numberOfWords,
-            final Random random) {
+            final Random random, final boolean checksContents) {
         final List<String> words = generateWords(numberOfWords, random);
         final UserHistoryPredictionDictionary dict =
                 PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(),
                         testFilenameSuffix /* locale */, mPrefs);
         // Add random words to the user history dictionary.
         addToDict(dict, words);
+        if (checksContents) {
+            try {
+                Thread.sleep(TimeUnit.MILLISECONDS.convert(5L, TimeUnit.SECONDS));
+            } catch (InterruptedException e) {
+            }
+            for (int i = 0; i < 10 && i < numberOfWords; ++i) {
+                final String word = words.get(i);
+                // This may fail as long as we use tryLock on inserting the bigram words
+                assertTrue(dict.isInDictionaryForTests(word));
+            }
+        }
         // write to file.
         dict.close();
     }
@@ -103,7 +118,8 @@
         final Random random = new Random(123456);
 
         try {
-            addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random);
+            addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random,
+                    true /* checksContents */);
         } finally {
             try {
                 Log.d(TAG, "waiting for writing ...");
@@ -148,7 +164,8 @@
                 final int index = i % numberOfLanguages;
                 // Switch languages to testFilenameSuffixes[index].
                 addAndWriteRandomWords(testFilenameSuffixes[index],
-                        numberOfWordsInsertedForEachLanguageSwitch, random);
+                        numberOfWordsInsertedForEachLanguageSwitch, random,
+                        false /* checksContents */);
             }
 
             final long end = System.currentTimeMillis();