1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //     * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //     * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 #include "dictionary/user_dictionary_util.h"
31 
32 #include "base/util.h"
33 #include "testing/base/public/googletest.h"
34 #include "testing/base/public/gunit.h"
35 #include "testing/base/public/testing_util.h"
36 
37 namespace mozc {
38 
39 using user_dictionary::UserDictionary;
40 using user_dictionary::UserDictionaryCommandStatus;
41 
TestNormalizeReading(const string & golden,const string & input)42 static void TestNormalizeReading(const string &golden, const string &input) {
43   string output;
44   UserDictionaryUtil::NormalizeReading(input, &output);
45   EXPECT_EQ(golden, output);
46 }
47 
TEST(UserDictionaryUtilTest,TestIsValidReading)48 TEST(UserDictionaryUtilTest, TestIsValidReading) {
49   EXPECT_TRUE(UserDictionaryUtil::IsValidReading("ABYZabyz0189"));
50   EXPECT_TRUE(UserDictionaryUtil::IsValidReading("〜「」"));
51   EXPECT_TRUE(UserDictionaryUtil::IsValidReading("あいうわをんゔ"));
52   EXPECT_TRUE(UserDictionaryUtil::IsValidReading("アイウワヲンヴ"));
53   EXPECT_FALSE(UserDictionaryUtil::IsValidReading("水雲"));
54 
55   // COMBINING KATAKANA-HIRAGANA VOICED/SEMI-VOICED SOUND MARK (u3099, u309A)
56   EXPECT_FALSE(UserDictionaryUtil::IsValidReading("゙゚"));
57 
58   // KATAKANA-HIRAGANA VOICED/SEMI-VOICED SOUND MARK (u309B, u309C)
59   EXPECT_TRUE(UserDictionaryUtil::IsValidReading("゛゜"));
60 }
61 
TEST(UserDictionaryUtilTest,TestNormalizeReading)62 TEST(UserDictionaryUtilTest, TestNormalizeReading) {
63   TestNormalizeReading("あいうゔゎ", "アイウヴヮ");
64   TestNormalizeReading("あいうゃ", "アイウャ");
65   TestNormalizeReading("ABab01@&=|", "ABab01@&=|");
66 }
67 
68 namespace {
69 struct UserDictionaryEntryData {
70   const char *key;
71   const char *value;
72   const UserDictionary::PosType pos;
73   const char *comment;
74 };
75 
ConvertUserDictionaryEntry(const UserDictionaryEntryData & input,UserDictionary::Entry * output)76 void ConvertUserDictionaryEntry(
77     const UserDictionaryEntryData &input, UserDictionary::Entry *output) {
78   output->set_key(input.key);
79   output->set_value(input.value);
80   output->set_pos(input.pos);
81   output->set_comment(input.comment);
82 }
83 }  // namespace
84 
TEST(UserDictionaryUtilTest,TestSanitizeEntry)85 TEST(UserDictionaryUtilTest, TestSanitizeEntry) {
86   const UserDictionaryEntryData golden_data = {
87     "abc", "abc", UserDictionary::NOUN, "abc",
88   };
89 
90   UserDictionary::Entry golden, input;
91   ConvertUserDictionaryEntry(golden_data, &golden);
92 
93   {
94     UserDictionaryEntryData input_data = {
95       "abc", "abc", UserDictionary::NOUN, "abc" };
96     ConvertUserDictionaryEntry(input_data, &input);
97     EXPECT_FALSE(UserDictionaryUtil::SanitizeEntry(&input));
98     EXPECT_EQ(golden.DebugString(), input.DebugString());
99   }
100 
101   {
102     UserDictionaryEntryData input_data = {
103       "ab\tc", "abc", UserDictionary::NOUN, "abc" };
104     ConvertUserDictionaryEntry(input_data, &input);
105     EXPECT_TRUE(UserDictionaryUtil::SanitizeEntry(&input));
106     EXPECT_EQ(golden.DebugString(), input.DebugString());
107   }
108 
109   {
110     UserDictionaryEntryData input_data = {
111       "abc", "ab\tc", UserDictionary::NOUN, "ab\tc" };
112     ConvertUserDictionaryEntry(input_data, &input);
113     EXPECT_TRUE(UserDictionaryUtil::SanitizeEntry(&input));
114     EXPECT_EQ(golden.DebugString(), input.DebugString());
115   }
116 
117   {
118     UserDictionaryEntryData input_data = {
119       "ab\tc", "ab\tc", UserDictionary::NOUN, "ab\tc" };
120     ConvertUserDictionaryEntry(input_data, &input);
121     EXPECT_TRUE(UserDictionaryUtil::SanitizeEntry(&input));
122     EXPECT_EQ(golden.DebugString(), input.DebugString());
123   }
124 }
125 
TEST(UserDictionaryUtilTest,TestSanitize)126 TEST(UserDictionaryUtilTest, TestSanitize) {
127   string str(10, '\t');
128   EXPECT_TRUE(UserDictionaryUtil::Sanitize(&str, 5));
129   EXPECT_EQ("", str);
130 
131   str = "ab\tc";
132   EXPECT_TRUE(UserDictionaryUtil::Sanitize(&str, 10));
133   EXPECT_EQ("abc", str);
134 
135   str = "かしゆか";
136   EXPECT_TRUE(UserDictionaryUtil::Sanitize(&str, 3));
137   EXPECT_EQ("か", str);
138 
139   str = "かしゆか";
140   EXPECT_TRUE(UserDictionaryUtil::Sanitize(&str, 4));
141   EXPECT_EQ("か", str);
142 
143   str = "かしゆか";
144   EXPECT_TRUE(UserDictionaryUtil::Sanitize(&str, 5));
145   EXPECT_EQ("か", str);
146 
147   str = "かしゆか";
148   EXPECT_TRUE(UserDictionaryUtil::Sanitize(&str, 6));
149   EXPECT_EQ("かし", str);
150 
151   str = "かしゆか";
152   EXPECT_FALSE(UserDictionaryUtil::Sanitize(&str, 100));
153   EXPECT_EQ("かしゆか", str);
154 }
155 
TEST(UserDictionaryUtilTest,ValidateEntry)156 TEST(UserDictionaryUtilTest, ValidateEntry) {
157   // Create a valid entry.
158   UserDictionary::Entry base_entry;
159   base_entry.set_key("よみ");
160   base_entry.set_value("単語");
161   base_entry.set_pos(UserDictionary::NOUN);
162   base_entry.set_comment("コメント");
163 
164   UserDictionary::Entry entry;
165   entry.CopyFrom(base_entry);
166   EXPECT_EQ(UserDictionaryCommandStatus::USER_DICTIONARY_COMMAND_SUCCESS,
167             UserDictionaryUtil::ValidateEntry(entry));
168 
169   entry.CopyFrom(base_entry);
170   entry.clear_key();
171   EXPECT_EQ(UserDictionaryCommandStatus::READING_EMPTY,
172             UserDictionaryUtil::ValidateEntry(entry));
173 
174   entry.CopyFrom(base_entry);
175   entry.set_key(string(500, 'a'));
176   EXPECT_EQ(UserDictionaryCommandStatus::READING_TOO_LONG,
177             UserDictionaryUtil::ValidateEntry(entry));
178 
179   entry.CopyFrom(base_entry);
180   entry.set_key("a\nb");
181   EXPECT_EQ(UserDictionaryCommandStatus::READING_CONTAINS_INVALID_CHARACTER,
182             UserDictionaryUtil::ValidateEntry(entry));
183 
184   entry.CopyFrom(base_entry);
185   entry.clear_value();
186   EXPECT_EQ(UserDictionaryCommandStatus::WORD_EMPTY,
187             UserDictionaryUtil::ValidateEntry(entry));
188 
189   entry.CopyFrom(base_entry);
190   entry.set_value(string(500, 'a'));
191   EXPECT_EQ(UserDictionaryCommandStatus::WORD_TOO_LONG,
192             UserDictionaryUtil::ValidateEntry(entry));
193 
194   entry.CopyFrom(base_entry);
195   entry.set_value("a\nb");
196   EXPECT_EQ(UserDictionaryCommandStatus::WORD_CONTAINS_INVALID_CHARACTER,
197             UserDictionaryUtil::ValidateEntry(entry));
198 
199   entry.CopyFrom(base_entry);
200   entry.clear_comment();
201   EXPECT_EQ(UserDictionaryCommandStatus::USER_DICTIONARY_COMMAND_SUCCESS,
202             UserDictionaryUtil::ValidateEntry(entry));
203 
204   entry.CopyFrom(base_entry);
205   entry.set_comment(string(500, 'a'));
206   EXPECT_EQ(UserDictionaryCommandStatus::COMMENT_TOO_LONG,
207             UserDictionaryUtil::ValidateEntry(entry));
208 
209   entry.CopyFrom(base_entry);
210   entry.set_comment("a\nb");
211   EXPECT_EQ(UserDictionaryCommandStatus::COMMENT_CONTAINS_INVALID_CHARACTER,
212             UserDictionaryUtil::ValidateEntry(entry));
213 
214   entry.CopyFrom(base_entry);
215   entry.clear_pos();
216   EXPECT_EQ(UserDictionaryCommandStatus::INVALID_POS_TYPE,
217             UserDictionaryUtil::ValidateEntry(entry));
218 }
219 
TEST(UserDictionaryUtilTest,ValidateDictionaryName)220 TEST(UserDictionaryUtilTest, ValidateDictionaryName) {
221   EXPECT_EQ(UserDictionaryCommandStatus::DICTIONARY_NAME_EMPTY,
222             UserDictionaryUtil::ValidateDictionaryName(
223                 user_dictionary::UserDictionaryStorage::default_instance(),
224                 ""));
225 
226   EXPECT_EQ(UserDictionaryCommandStatus::DICTIONARY_NAME_TOO_LONG,
227             UserDictionaryUtil::ValidateDictionaryName(
228                 user_dictionary::UserDictionaryStorage::default_instance(),
229                 string(500, 'a')));
230 
231   EXPECT_EQ(UserDictionaryCommandStatus
232                 ::DICTIONARY_NAME_CONTAINS_INVALID_CHARACTER,
233             UserDictionaryUtil::ValidateDictionaryName(
234                 user_dictionary::UserDictionaryStorage::default_instance(),
235                 "a\nbc"));
236 
237   user_dictionary::UserDictionaryStorage storage;
238   storage.add_dictionaries()->set_name("abc");
239   EXPECT_EQ(UserDictionaryCommandStatus::DICTIONARY_NAME_DUPLICATED,
240             UserDictionaryUtil::ValidateDictionaryName(
241                 storage, "abc"));
242 }
243 
TEST(UserDictionaryUtilTest,IsStorageFull)244 TEST(UserDictionaryUtilTest, IsStorageFull) {
245   user_dictionary::UserDictionaryStorage storage;
246   for (int i = 0; i < UserDictionaryUtil::max_dictionary_size(); ++i) {
247     EXPECT_FALSE(UserDictionaryUtil::IsStorageFull(storage));
248     storage.add_dictionaries();
249   }
250 
251   EXPECT_TRUE(UserDictionaryUtil::IsStorageFull(storage));
252 }
253 
TEST(UserDictionaryUtilTest,IsDictionaryFull)254 TEST(UserDictionaryUtilTest, IsDictionaryFull) {
255   UserDictionary dictionary;
256   for (int i = 0; i < UserDictionaryUtil::max_entry_size(); ++i) {
257     EXPECT_FALSE(UserDictionaryUtil::IsDictionaryFull(dictionary));
258     dictionary.add_entries();
259   }
260 
261   EXPECT_TRUE(UserDictionaryUtil::IsDictionaryFull(dictionary));
262 }
263 
TEST(UserDictionaryUtilTest,GetUserDictionaryById)264 TEST(UserDictionaryUtilTest, GetUserDictionaryById) {
265   user_dictionary::UserDictionaryStorage storage;
266   storage.add_dictionaries()->set_id(1);
267   storage.add_dictionaries()->set_id(2);
268 
269   EXPECT_TRUE(UserDictionaryUtil::GetUserDictionaryById(storage, 1) ==
270               &storage.dictionaries(0));
271   EXPECT_TRUE(UserDictionaryUtil::GetUserDictionaryById(storage, 2) ==
272               &storage.dictionaries(1));
273   EXPECT_TRUE(UserDictionaryUtil::GetUserDictionaryById(storage, -1) == NULL);
274 }
275 
TEST(UserDictionaryUtilTest,GetMutableUserDictionaryById)276 TEST(UserDictionaryUtilTest, GetMutableUserDictionaryById) {
277   user_dictionary::UserDictionaryStorage storage;
278   storage.add_dictionaries()->set_id(1);
279   storage.add_dictionaries()->set_id(2);
280 
281   EXPECT_TRUE(UserDictionaryUtil::GetMutableUserDictionaryById(&storage, 1) ==
282               storage.mutable_dictionaries(0));
283   EXPECT_TRUE(UserDictionaryUtil::GetMutableUserDictionaryById(&storage, 2) ==
284               storage.mutable_dictionaries(1));
285   EXPECT_TRUE(
286       UserDictionaryUtil::GetMutableUserDictionaryById(&storage, -1) == NULL);
287 }
288 
TEST(UserDictionaryUtilTest,GetUserDictionaryIndexById)289 TEST(UserDictionaryUtilTest, GetUserDictionaryIndexById) {
290   user_dictionary::UserDictionaryStorage storage;
291   storage.add_dictionaries()->set_id(1);
292   storage.add_dictionaries()->set_id(2);
293 
294   EXPECT_EQ(0, UserDictionaryUtil::GetUserDictionaryIndexById(storage, 1));
295   EXPECT_EQ(1, UserDictionaryUtil::GetUserDictionaryIndexById(storage, 2));
296 
297   // Return -1 for a failing case.
298   EXPECT_EQ(-1, UserDictionaryUtil::GetUserDictionaryIndexById(storage, -1));
299 }
300 
TEST(UserDictionaryUtilTest,CreateDictionary)301 TEST(UserDictionaryUtilTest, CreateDictionary) {
302   user_dictionary::UserDictionaryStorage storage;
303   uint64 dictionary_id;
304 
305   // Check dictionary validity.
306   EXPECT_EQ(UserDictionaryCommandStatus::DICTIONARY_NAME_EMPTY,
307             UserDictionaryUtil::CreateDictionary(
308                 &storage, "", &dictionary_id));
309 
310   // Check the limit of the number of dictionaries.
311   storage.Clear();
312   for (int i = 0; i < UserDictionaryUtil::max_dictionary_size(); ++i) {
313     storage.add_dictionaries();
314   }
315 
316   EXPECT_EQ(UserDictionaryCommandStatus::DICTIONARY_SIZE_LIMIT_EXCEEDED,
317             UserDictionaryUtil::CreateDictionary(
318                 &storage, "new dictionary", &dictionary_id));
319 
320   storage.Clear();
321   EXPECT_EQ(UserDictionaryCommandStatus::UNKNOWN_ERROR,
322             UserDictionaryUtil::CreateDictionary(
323                 &storage, "new dictionary", NULL));
324 
325   ASSERT_EQ(UserDictionaryCommandStatus::USER_DICTIONARY_COMMAND_SUCCESS,
326             UserDictionaryUtil::CreateDictionary(
327                 &storage, "new dictionary", &dictionary_id));
328 
329   EXPECT_PROTO_PEQ("dictionaries <\n"
330                    "  name: \"new dictionary\"\n"
331                    ">\n",
332                    storage);
333   EXPECT_EQ(dictionary_id, storage.dictionaries(0).id());
334 }
335 
TEST(UserDictionaryUtilTest,DeleteDictionary)336 TEST(UserDictionaryUtilTest, DeleteDictionary) {
337   user_dictionary::UserDictionaryStorage storage;
338   storage.add_dictionaries()->set_id(1);
339   storage.add_dictionaries()->set_id(2);
340 
341   // Simplest deleting case.
342   int original_index;
343   ASSERT_TRUE(UserDictionaryUtil::DeleteDictionary(
344       &storage, 1, &original_index, NULL));
345   EXPECT_EQ(0, original_index);
346   ASSERT_EQ(1, storage.dictionaries_size());
347   EXPECT_EQ(2, storage.dictionaries(0).id());
348 
349   // Deletion for unknown dictionary should fail.
350   storage.Clear();
351   storage.add_dictionaries()->set_id(1);
352   storage.add_dictionaries()->set_id(2);
353   EXPECT_FALSE(UserDictionaryUtil::DeleteDictionary(
354       &storage, 100, NULL, NULL));
355 
356   // Keep deleted dictionary.
357   storage.Clear();
358   storage.add_dictionaries()->set_id(1);
359   storage.add_dictionaries()->set_id(2);
360   UserDictionary *expected_deleted_dictionary =
361       storage.mutable_dictionaries(0);
362   UserDictionary *deleted_dictionary;
363   EXPECT_TRUE(UserDictionaryUtil::DeleteDictionary(
364       &storage, 1, NULL, &deleted_dictionary));
365   ASSERT_EQ(1, storage.dictionaries_size());
366   EXPECT_EQ(2, storage.dictionaries(0).id());
367   EXPECT_TRUE(expected_deleted_dictionary == deleted_dictionary);
368 
369   // Delete to avoid memoary leaking.
370   delete expected_deleted_dictionary;
371 }
372 
373 }  // namespace mozc
374