Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(383)

Side by Side Diff: chrome/renderer/spellcheck_unittest.cc

Issue 8176: Move the spellcheck unittest into browser next to the file (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 12 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/spellcheck_unittest.cc ('k') | chrome/test/unit/unittests.vcproj » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "webkit/glue/webkit_glue.h"
6
7 #include "base/file_util.h"
8 #include "base/message_loop.h"
9 #include "base/path_service.h"
10 #include "chrome/browser/spellchecker.h"
11 #include "chrome/common/chrome_paths.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace {
15 class SpellCheckTest : public testing::Test {
16 private:
17 MessageLoop message_loop_;
18 };
19
20 const std::wstring kTempCustomDictionaryFile(L"temp_custom_dictionary.txt");
21
22 } // namespace
23
24 // Represents a special initialization function used only for the unit tests
25 // in this file.
26 extern void InitHunspellWithFiles(FILE* file_aff_hunspell,
27 FILE* file_dic_hunspell);
28
29 // Operates unit tests for the webkit_glue::SpellCheckWord() function
30 // with the US English dictionary.
31 // The unit tests in this function consist of:
32 // * Tests for the function with empty strings;
33 // * Tests for the function with a valid English word;
34 // * Tests for the function with a valid non-English word;
35 // * Tests for the function with a valid English word with a preceding
36 // space character;
37 // * Tests for the function with a valid English word with a preceding
38 // non-English word;
39 // * Tests for the function with a valid English word with a following
40 // space character;
41 // * Tests for the function with a valid English word with a following
42 // non-English word;
43 // * Tests for the function with two valid English words concatenated
44 // with space characters or non-English words;
45 // * Tests for the function with an invalid English word;
46 // * Tests for the function with an invalid English word with a preceding
47 // space character;
48 // * Tests for the function with an invalid English word with a preceding
49 // non-English word;
50 // * Tests for the function with2 an invalid English word with a following
51 // space character;
52 // * Tests for the function with an invalid English word with a following
53 // non-English word, and;
54 // * Tests for the function with two invalid English words concatenated
55 // with space characters or non-English words.
56 // A test with a "[ROBUSTNESS]" mark shows it is a robustness test and it uses
57 // grammartically incorrect string.
58 // TODO(hbono): Please feel free to add more tests.
59 TEST_F(SpellCheckTest, SpellCheckStrings_EN_US) {
60 static const struct {
61 // A string to be tested.
62 const wchar_t* input;
63 // An expected result for this test case.
64 // * true: the input string does not have any invalid words.
65 // * false: the input string has one or more invalid words.
66 bool expected_result;
67 // The position and the length of the first invalid word.
68 int misspelling_start;
69 int misspelling_length;
70 } kTestCases[] = {
71 // Empty strings.
72 {NULL, true, 0, 0},
73 {L"", true, 0, 0},
74 {L" ", true, 0, 0},
75 {L"\xA0", true, 0, 0},
76 {L"\x3000", true, 0, 0},
77
78 // A valid English word "hello".
79 {L"hello", true, 0, 0},
80 // A valid Chinese word (meaning "hello") consisiting of two CJKV
81 // ideographs
82 {L"\x4F60\x597D", true, 0, 0},
83 // A valid Korean word (meaning "hello") consisting of five hangul
84 // syllables
85 {L"\xC548\xB155\xD558\xC138\xC694", true, 0, 0},
86 // A valid Japanese word (meaning "hello") consisting of five Hiragana
87 // letters
88 {L"\x3053\x3093\x306B\x3061\x306F", true, 0, 0},
89 // A valid Hindi word (meaning ?) consisting of six Devanagari letters
90 // (This word is copied from "http://b/issue?id=857583".)
91 {L"\x0930\x093E\x091C\x0927\x093E\x0928", true, 0, 0},
92 // A valid English word "affix" using a Latin ligature 'ffi'
93 {L"a\xFB03x", true, 0, 0},
94 // A valid English word "hello" (fullwidth version)
95 {L"\xFF28\xFF45\xFF4C\xFF4C\xFF4F", true, 0, 0},
96 // Two valid Greek words (meaning "hello") consisting of seven Greek
97 // letters
98 {L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", true, 0, 0},
99 // A valid Russian word (meainng "hello") consisting of twelve Cyrillic
100 // letters
101 {L"\x0437\x0434\x0440\x0430\x0432\x0441"
102 L"\x0442\x0432\x0443\x0439\x0442\x0435", true, 0, 0},
103 // A valid English contraction
104 {L"isn't", true, 0, 0},
105 // A valid English word enclosed with underscores.
106 {L"_hello_", true, 0, 0},
107
108 // A valid English word with a preceding whitespace
109 {L" " L"hello", true, 0, 0},
110 // A valid English word with a preceding no-break space
111 {L"\xA0" L"hello", true, 0, 0},
112 // A valid English word with a preceding ideographic space
113 {L"\x3000" L"hello", true, 0, 0},
114 // A valid English word with a preceding Chinese word
115 {L"\x4F60\x597D" L"hello", true, 0, 0},
116 // [ROBUSTNESS] A valid English word with a preceding Korean word
117 {L"\xC548\xB155\xD558\xC138\xC694" L"hello", true, 0, 0},
118 // A valid English word with a preceding Japanese word
119 {L"\x3053\x3093\x306B\x3061\x306F" L"hello", true, 0, 0},
120 // [ROBUSTNESS] A valid English word with a preceding Hindi word
121 {L"\x0930\x093E\x091C\x0927\x093E\x0928" L"hello", true, 0, 0},
122 // [ROBUSTNESS] A valid English word with two preceding Greek words
123 {L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5"
124 L"hello", true, 0, 0},
125 // [ROBUSTNESS] A valid English word with a preceding Russian word
126 {L"\x0437\x0434\x0440\x0430\x0432\x0441"
127 L"\x0442\x0432\x0443\x0439\x0442\x0435" L"hello", true, 0, 0},
128
129 // A valid English word with a following whitespace
130 {L"hello" L" ", true, 0, 0},
131 // A valid English word with a following no-break space
132 {L"hello" L"\xA0", true, 0, 0},
133 // A valid English word with a following ideographic space
134 {L"hello" L"\x3000", true, 0, 0},
135 // A valid English word with a following Chinese word
136 {L"hello" L"\x4F60\x597D", true, 0, 0},
137 // [ROBUSTNESS] A valid English word with a following Korean word
138 {L"hello" L"\xC548\xB155\xD558\xC138\xC694", true, 0, 0},
139 // A valid English word with a following Japanese word
140 {L"hello" L"\x3053\x3093\x306B\x3061\x306F", true, 0, 0},
141 // [ROBUSTNESS] A valid English word with a following Hindi word
142 {L"hello" L"\x0930\x093E\x091C\x0927\x093E\x0928", true, 0, 0},
143 // [ROBUSTNESS] A valid English word with two following Greek words
144 {L"hello"
145 L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", true, 0, 0},
146 // [ROBUSTNESS] A valid English word with a following Russian word
147 {L"hello" L"\x0437\x0434\x0440\x0430\x0432\x0441"
148 L"\x0442\x0432\x0443\x0439\x0442\x0435", true, 0, 0},
149
150 // Two valid English words concatenated with a whitespace
151 {L"hello" L" " L"hello", true, 0, 0},
152 // Two valid English words concatenated with a no-break space
153 {L"hello" L"\xA0" L"hello", true, 0, 0},
154 // Two valid English words concatenated with an ideographic space
155 {L"hello" L"\x3000" L"hello", true, 0, 0},
156 // Two valid English words concatenated with a Chinese word
157 {L"hello" L"\x4F60\x597D" L"hello", true, 0, 0},
158 // [ROBUSTNESS] Two valid English words concatenated with a Korean word
159 {L"hello" L"\xC548\xB155\xD558\xC138\xC694" L"hello", true, 0, 0},
160 // Two valid English words concatenated with a Japanese word
161 {L"hello" L"\x3053\x3093\x306B\x3061\x306F" L"hello", true, 0, 0},
162 // [ROBUSTNESS] Two valid English words concatenated with a Hindi word
163 {L"hello" L"\x0930\x093E\x091C\x0927\x093E\x0928" L"hello" , true, 0, 0},
164 // [ROBUSTNESS] Two valid English words concatenated with two Greek words
165 {L"hello" L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5"
166 L"hello", true, 0, 0},
167 // [ROBUSTNESS] Two valid English words concatenated with a Russian word
168 {L"hello" L"\x0437\x0434\x0440\x0430\x0432\x0441"
169 L"\x0442\x0432\x0443\x0439\x0442\x0435" L"hello", true, 0, 0},
170 // [ROBUSTNESS] Two valid English words concatenated with a contraction
171 // character.
172 {L"hello:hello", true, 0, 0},
173
174 // An invalid English word
175 {L"ifmmp", false, 0, 5},
176 // An invalid English word "bffly" containing a Latin ligature 'ffl'
177 {L"b\xFB04y", false, 0, 3},
178 // An invalid English word "ifmmp" (fullwidth version)
179 {L"\xFF29\xFF46\xFF4D\xFF4D\xFF50", false, 0, 5},
180 // An invalid English contraction
181 {L"jtm'u", false, 0, 5},
182 // An invalid English word enclosed with underscores.
183 {L"_ifmmp_", false, 1, 5},
184
185 // An invalid English word with a preceding whitespace
186 {L" " L"ifmmp", false, 1, 5},
187 // An invalid English word with a preceding no-break space
188 {L"\xA0" L"ifmmp", false, 1, 5},
189 // An invalid English word with a preceding ideographic space
190 {L"\x3000" L"ifmmp", false, 1, 5},
191 // An invalid English word with a preceding Chinese word
192 {L"\x4F60\x597D" L"ifmmp", false, 2, 5},
193 // [ROBUSTNESS] An invalid English word with a preceding Korean word
194 {L"\xC548\xB155\xD558\xC138\xC694" L"ifmmp", false, 5, 5},
195 // An invalid English word with a preceding Japanese word
196 {L"\x3053\x3093\x306B\x3061\x306F" L"ifmmp", false, 5, 5},
197 // [ROBUSTNESS] An invalid English word with a preceding Hindi word
198 {L"\x0930\x093E\x091C\x0927\x093E\x0928" L"ifmmp", false, 6, 5},
199 // [ROBUSTNESS] An invalid English word with two preceding Greek words
200 {L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5"
201 L"ifmmp", false, 8, 5},
202 // [ROBUSTNESS] An invalid English word with a preceding Russian word
203 {L"\x0437\x0434\x0440\x0430\x0432\x0441"
204 L"\x0442\x0432\x0443\x0439\x0442\x0435" L"ifmmp", false, 12, 5},
205
206 // An invalid English word with a following whitespace
207 {L"ifmmp" L" ", false, 0, 5},
208 // An invalid English word with a following no-break space
209 {L"ifmmp" L"\xA0", false, 0, 5},
210 // An invalid English word with a following ideographic space
211 {L"ifmmp" L"\x3000", false, 0, 5},
212 // An invalid English word with a following Chinese word
213 {L"ifmmp" L"\x4F60\x597D", false, 0, 5},
214 // [ROBUSTNESS] An invalid English word with a following Korean word
215 {L"ifmmp" L"\xC548\xB155\xD558\xC138\xC694", false, 0, 5},
216 // An invalid English word with a following Japanese word
217 {L"ifmmp" L"\x3053\x3093\x306B\x3061\x306F", false, 0, 5},
218 // [ROBUSTNESS] An invalid English word with a following Hindi word
219 {L"ifmmp" L"\x0930\x093E\x091C\x0927\x093E\x0928", false, 0, 5},
220 // [ROBUSTNESS] An invalid English word with two following Greek words
221 {L"ifmmp"
222 L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", false, 0, 5},
223 // [ROBUSTNESS] An invalid English word with a following Russian word
224 {L"ifmmp" L"\x0437\x0434\x0440\x0430\x0432\x0441"
225 L"\x0442\x0432\x0443\x0439\x0442\x0435", false, 0, 5},
226
227 // Two invalid English words concatenated with a whitespace
228 {L"ifmmp" L" " L"ifmmp", false, 0, 5},
229 // Two invalid English words concatenated with a no-break space
230 {L"ifmmp" L"\xA0" L"ifmmp", false, 0, 5},
231 // Two invalid English words concatenated with an ideographic space
232 {L"ifmmp" L"\x3000" L"ifmmp", false, 0, 5},
233 // Two invalid English words concatenated with a Chinese word
234 {L"ifmmp" L"\x4F60\x597D" L"ifmmp", false, 0, 5},
235 // [ROBUSTNESS] Two invalid English words concatenated with a Korean word
236 {L"ifmmp" L"\xC548\xB155\xD558\xC138\xC694" L"ifmmp", false, 0, 5},
237 // Two invalid English words concatenated with a Japanese word
238 {L"ifmmp" L"\x3053\x3093\x306B\x3061\x306F" L"ifmmp", false, 0, 5},
239 // [ROBUSTNESS] Two invalid English words concatenated with a Hindi word
240 {L"ifmmp" L"\x0930\x093E\x091C\x0927\x093E\x0928" L"ifmmp" , false, 0, 5},
241 // [ROBUSTNESS] Two invalid English words concatenated with two Greek words
242 {L"ifmmp" L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5"
243 L"ifmmp", false, 0, 5},
244 // [ROBUSTNESS] Two invalid English words concatenated with a Russian word
245 {L"ifmmp" L"\x0437\x0434\x0440\x0430\x0432\x0441"
246 L"\x0442\x0432\x0443\x0439\x0442\x0435" L"ifmmp", false, 0, 5},
247 // [ROBUSTNESS] Two invalid English words concatenated with a contraction
248 // character.
249 {L"ifmmp:ifmmp", false, 0, 11},
250 };
251
252 std::wstring hunspell_directory;
253 ASSERT_TRUE(PathService::Get(chrome::DIR_APP_DICTIONARIES,
254 &hunspell_directory));
255
256 scoped_refptr<SpellChecker> spell_checker(new SpellChecker(
257 hunspell_directory, L"en-US", NULL, L""));
258
259 for (int i = 0; i < arraysize(kTestCases); i++) {
260 size_t input_length = 0;
261 if (kTestCases[i].input != NULL) {
262 input_length = wcslen(kTestCases[i].input);
263 }
264 int misspelling_start;
265 int misspelling_length;
266 bool result = spell_checker->SpellCheckWord(kTestCases[i].input,
267 static_cast<int>(input_length),
268 &misspelling_start,
269 &misspelling_length, NULL);
270
271 EXPECT_EQ(result, kTestCases[i].expected_result);
272 EXPECT_EQ(misspelling_start, kTestCases[i].misspelling_start);
273 EXPECT_EQ(misspelling_length, kTestCases[i].misspelling_length);
274 }
275 }
276
277
278 TEST_F(SpellCheckTest, SpellCheckSuggestions_EN_US) {
279 static const struct {
280 // A string to be tested.
281 const wchar_t* input;
282 // An expected result for this test case.
283 // * true: the input string does not have any invalid words.
284 // * false: the input string has one or more invalid words.
285 bool expected_result;
286 // The position and the length of the first invalid word.
287 int misspelling_start;
288 int misspelling_length;
289
290 // A suggested word that should occur.
291 const wchar_t* suggested_word;
292 } kTestCases[] = { // A valid English word with a preceding whitespace
293 {L"ello", false, 0, 0, L"hello"},
294 {L"ello", false, 0, 0, L"cello"},
295 {L"wate", false, 0, 0, L"water"},
296 {L"wate", false, 0, 0, L"waste"},
297 {L"wate", false, 0, 0, L"sate"},
298 {L"wate", false, 0, 0, L"rate"},
299 {L"jum", false, 0, 0, L"jump"},
300 {L"jum", false, 0, 0, L"rum"},
301 {L"jum", false, 0, 0, L"sum"},
302 {L"jum", false, 0, 0, L"tum"},
303 // TODO (Sidchat): add many more examples.
304 };
305
306 std::wstring hunspell_directory;
307 ASSERT_TRUE(PathService::Get(chrome::DIR_APP_DICTIONARIES,
308 &hunspell_directory));
309
310 scoped_refptr<SpellChecker> spell_checker(new SpellChecker(
311 hunspell_directory, L"en-US", NULL, L""));
312
313 for (int i = 0; i < arraysize(kTestCases); i++) {
314 std::vector<std::wstring> suggestions;
315 size_t input_length = 0;
316 if (kTestCases[i].input != NULL) {
317 input_length = wcslen(kTestCases[i].input);
318 }
319 int misspelling_start;
320 int misspelling_length;
321 bool result = spell_checker->SpellCheckWord(kTestCases[i].input,
322 static_cast<int>(input_length),
323 &misspelling_start,
324 &misspelling_length,
325 &suggestions);
326
327 // Check for spelling.
328 EXPECT_EQ(result, kTestCases[i].expected_result);
329
330 // Check if the suggested words occur.
331 bool suggested_word_is_present = false;
332 for (int j=0; j < static_cast<int>(suggestions.size()); j++) {
333 if (suggestions.at(j).compare(kTestCases[i].suggested_word) == 0) {
334 suggested_word_is_present = true;
335 break;
336 }
337 }
338
339 EXPECT_TRUE(suggested_word_is_present);
340 }
341 }
342
343 // This test Adds words to the SpellChecker and veifies that it remembers them.
344 TEST_F(SpellCheckTest, DISABLED_SpellCheckAddToDictionary_EN_US) {
345 static const struct {
346 // A string to be added to SpellChecker.
347 const wchar_t* word_to_add;
348 } kTestCases[] = { // word to be added to SpellChecker
349 {L"Googley"},
350 {L"Googleplex"},
351 {L"Googler"},
352 };
353
354 std::wstring hunspell_directory;
355 ASSERT_TRUE(PathService::Get(chrome::DIR_APP_DICTIONARIES,
356 &hunspell_directory));
357
358 scoped_refptr<SpellChecker> spell_checker(new SpellChecker(
359 hunspell_directory, L"en-US", NULL, kTempCustomDictionaryFile));
360
361 for (int i = 0; i < arraysize(kTestCases); i++) {
362 // Add the word to spellchecker.
363 spell_checker->AddWord(std::wstring(kTestCases[i].word_to_add));
364
365 // Now check whether it is added to Spellchecker.
366 std::vector<std::wstring> suggestions;
367 size_t input_length = 0;
368 if (kTestCases[i].word_to_add != NULL) {
369 input_length = wcslen(kTestCases[i].word_to_add);
370 }
371 int misspelling_start;
372 int misspelling_length;
373 bool result = spell_checker->SpellCheckWord(kTestCases[i].word_to_add,
374 static_cast<int>(input_length),
375 &misspelling_start,
376 &misspelling_length,
377 &suggestions);
378
379 // Check for spelling.
380 EXPECT_TRUE(result);
381 }
382
383 // Now initialize another spellchecker to see that AddToWord is permanent.
384 scoped_refptr<SpellChecker> spell_checker_new(new SpellChecker(
385 hunspell_directory, L"en-US", NULL, kTempCustomDictionaryFile));
386
387 for (int i = 0; i < arraysize(kTestCases); i++) {
388 // Now check whether it is added to Spellchecker.
389 std::vector<std::wstring> suggestions;
390 size_t input_length = 0;
391 if (kTestCases[i].word_to_add != NULL) {
392 input_length = wcslen(kTestCases[i].word_to_add);
393 }
394 int misspelling_start;
395 int misspelling_length;
396 bool result = spell_checker_new->SpellCheckWord(
397 kTestCases[i].word_to_add,
398 static_cast<int>(input_length),
399 &misspelling_start,
400 &misspelling_length,
401 &suggestions);
402
403 // Check for spelling.
404 EXPECT_TRUE(result);
405 }
406
407 // Remove the temp custom dictionary file.
408 file_util::Delete(kTempCustomDictionaryFile, false);
409 }
410
411 // SpellChecker should suggest custome words for misspelled words.
412 TEST_F(SpellCheckTest, DISABLED_SpellCheckSuggestionsAddToDictionary_EN_US) {
413 static const struct {
414 // A string to be added to SpellChecker.
415 const wchar_t* word_to_add;
416 } kTestCases[] = { // word to be added to SpellChecker
417 {L"Googley"},
418 {L"Googleplex"},
419 {L"Googler"},
420 };
421
422 std::wstring hunspell_directory;
423 ASSERT_TRUE(PathService::Get(chrome::DIR_APP_DICTIONARIES,
424 &hunspell_directory));
425
426 scoped_refptr<SpellChecker> spell_checker(new SpellChecker(
427 hunspell_directory, L"en-US", NULL, kTempCustomDictionaryFile));
428
429 for (int i = 0; i < arraysize(kTestCases); i++) {
430 // Add the word to spellchecker.
431 spell_checker->AddWord(std::wstring(kTestCases[i].word_to_add));
432 }
433
434 // Now check to see whether the custom words are suggested for
435 // misspelled but similar words.
436 static const struct {
437 // A string to be tested.
438 const wchar_t* input;
439 // An expected result for this test case.
440 // * true: the input string does not have any invalid words.
441 // * false: the input string has one or more invalid words.
442 bool expected_result;
443 // The position and the length of the first invalid word.
444 int misspelling_start;
445 int misspelling_length;
446
447 // A suggested word that should occur.
448 const wchar_t* suggested_word;
449 } kTestCasesToBeTested[] = {
450 {L"oogley", false, 0, 0, L"Googley"},
451 {L"oogler", false, 0, 0, L"Googler"},
452 {L"oogleplex", false, 0, 0, L"Googleplex"},
453 };
454
455 for (int i = 0; i < arraysize(kTestCasesToBeTested); i++) {
456 std::vector<std::wstring> suggestions;
457 size_t input_length = 0;
458 if (kTestCasesToBeTested[i].input != NULL) {
459 input_length = wcslen(kTestCasesToBeTested[i].input);
460 }
461 int misspelling_start;
462 int misspelling_length;
463 bool result = spell_checker->SpellCheckWord(kTestCasesToBeTested[i].input,
464 static_cast<int>(input_length),
465 &misspelling_start,
466 &misspelling_length,
467 &suggestions);
468
469 // Check for spelling.
470 EXPECT_EQ(result, kTestCasesToBeTested[i].expected_result);
471
472 // Check if the suggested words occur.
473 bool suggested_word_is_present = false;
474 for (int j=0; j < static_cast<int>(suggestions.size()); j++) {
475 if (suggestions.at(j).compare(kTestCasesToBeTested[i].suggested_word) ==
476 0) {
477 suggested_word_is_present = true;
478 break;
479 }
480 }
481
482 EXPECT_TRUE(suggested_word_is_present);
483 }
484
485 // Remove the temp custom dictionary file.
486 file_util::Delete(kTempCustomDictionaryFile, false);
487 }
OLDNEW
« no previous file with comments | « chrome/browser/spellcheck_unittest.cc ('k') | chrome/test/unit/unittests.vcproj » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698