1a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard/*
2a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard * Copyright (C) 2013 The Android Open Source Project
3a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard *
4a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard * Licensed under the Apache License, Version 2.0 (the "License");
5a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard * you may not use this file except in compliance with the License.
6a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard * You may obtain a copy of the License at
7a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard *
8a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard *      http://www.apache.org/licenses/LICENSE-2.0
9a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard *
10a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard * Unless required by applicable law or agreed to in writing, software
11a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard * distributed under the License is distributed on an "AS IS" BASIS,
12a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard * See the License for the specific language governing permissions and
14a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard * limitations under the License.
15a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard */
16a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard
17a411595b169c1f136d09d114a458def1f99f91d9Jean Chalardpackage com.android.inputmethod.latin.makedict;
18a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard
19f14cf3e64caea68419969deb71793b367b1bbce2Keisuke Kuroyanagiimport com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions;
20a411595b169c1f136d09d114a458def1f99f91d9Jean Chalardimport com.android.inputmethod.latin.makedict.FusionDictionary;
21576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanadaimport com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
22af30cbf0ee8370763edf22822ea34a282e882084Jean Chalardimport com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
235f5feeba13f6f1a907d90365d8037a361d0ff5daKeisuke Kuroyanagiimport com.android.inputmethod.latin.makedict.WordProperty;
24a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard
25a411595b169c1f136d09d114a458def1f99f91d9Jean Chalardimport junit.framework.TestCase;
26a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard
27a411595b169c1f136d09d114a458def1f99f91d9Jean Chalardimport java.util.ArrayList;
28a411595b169c1f136d09d114a458def1f99f91d9Jean Chalardimport java.util.HashMap;
29a411595b169c1f136d09d114a458def1f99f91d9Jean Chalardimport java.util.Random;
30a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard
31a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard/**
3294460eba11019ec4658c42b4bcc0379d70f41770Yuichiro Hanada * Unit tests for FusionDictionary.
33a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard */
34a411595b169c1f136d09d114a458def1f99f91d9Jean Chalardpublic class FusionDictionaryTest extends TestCase {
35a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka    private static final ArrayList<String> sWords = new ArrayList<>();
36a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    private static final int MAX_UNIGRAMS = 1000;
37a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard
38a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    private void prepare(final long seed) {
39a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        System.out.println("Seed is " + seed);
40a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        final Random random = new Random(seed);
41a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        sWords.clear();
42a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        generateWords(MAX_UNIGRAMS, random);
43a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    }
44a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard
45a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    /**
46a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard     * Generates a random word.
47a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard     */
48a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    private String generateWord(final Random random) {
49a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        StringBuilder builder = new StringBuilder("a");
50a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        int count = random.nextInt() % 30;
51a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        while (count > 0) {
52a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard            final long r = Math.abs(random.nextInt());
53a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard            if (r < 0) continue;
54a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard            // Don't insert 0~20, but insert any other code point.
55a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard            // Code points are in the range 0~0x10FFFF.
56a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard            if (builder.length() < 7)
57a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard                builder.appendCodePoint((int)(20 +r % (0x10FFFF - 20)));
58a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard            --count;
59a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        }
60a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        if (builder.length() == 1) return generateWord(random);
61a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        return builder.toString();
62a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    }
63a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard
64a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    private void generateWords(final int number, final Random random) {
65a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        while (sWords.size() < number) {
66a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard            sWords.add(generateWord(random));
67a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        }
68a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    }
69a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard
705f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    private static void checkDictionary(final FusionDictionary dict, final ArrayList<String> words,
715f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            final int limit) {
72a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        assertNotNull(dict);
735f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        int count = limit;
74a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        for (final String word : words) {
755f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            if (--count < 0) return;
76576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada            final PtNode ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray, word);
77576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada            assertNotNull(ptNode);
78a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        }
79a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    }
80a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard
815f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    private static String dumpWord(final String word) {
82a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        final StringBuilder sb = new StringBuilder("");
83a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        for (int i = 0; i < word.length(); i = word.offsetByCodePoints(i, 1)) {
84a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard            sb.append(word.codePointAt(i));
85a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard            sb.append(" ");
86a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        }
87a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        return sb.toString();
88a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    }
89a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard
905f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    private static void dumpDict(final FusionDictionary dict) {
915f5feeba13f6f1a907d90365d8037a361d0ff5daKeisuke Kuroyanagi        for (WordProperty wordProperty : dict) {
925f5feeba13f6f1a907d90365d8037a361d0ff5daKeisuke Kuroyanagi            System.out.println("Word " + dumpWord(wordProperty.mWord));
93a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        }
94a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    }
95a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard
96a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    // Test the flattened array contains the expected number of nodes, and
97a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    // that it does not contain any duplicates.
98a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    public void testFusion() {
99af30cbf0ee8370763edf22822ea34a282e882084Jean Chalard        final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
1007b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard                new DictionaryOptions(new HashMap<String, String>()));
101a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        final long time = System.currentTimeMillis();
102a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        prepare(time);
103a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        for (int i = 0; i < sWords.size(); ++i) {
104a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard            System.out.println("Adding in pos " + i + " : " + dumpWord(sWords.get(i)));
10505172bf1a5693c2e108e91436b98ecd35d2dadadAdrian Velicu            dict.add(sWords.get(i), new ProbabilityInfo(180), null, false,
10605172bf1a5693c2e108e91436b98ecd35d2dadadAdrian Velicu                    false /* isPossiblyOffensive */);
107a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard            dumpDict(dict);
108a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard            checkDictionary(dict, sWords, i);
109a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard        }
110a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard    }
111a411595b169c1f136d09d114a458def1f99f91d9Jean Chalard}
112