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