OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/renderer/spellchecker/spellcheck.h" | 5 #include "chrome/renderer/spellchecker/spellcheck.h" |
6 | 6 |
7 #include "base/files/file_path.h" | 7 #include "base/files/file_path.h" |
8 #include "base/files/file_util.h" | 8 #include "base/files/file_util.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "base/path_service.h" | 10 #include "base/path_service.h" |
11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
12 #include "chrome/common/spellcheck_common.h" | 12 #include "chrome/common/spellcheck_common.h" |
13 #include "chrome/common/spellcheck_result.h" | 13 #include "chrome/common/spellcheck_result.h" |
14 #include "chrome/renderer/spellchecker/hunspell_engine.h" | 14 #include "chrome/renderer/spellchecker/hunspell_engine.h" |
15 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
16 #include "third_party/WebKit/public/platform/WebVector.h" | 16 #include "third_party/WebKit/public/platform/WebVector.h" |
17 #include "third_party/WebKit/public/web/WebTextCheckingCompletion.h" | 17 #include "third_party/WebKit/public/web/WebTextCheckingCompletion.h" |
18 #include "third_party/WebKit/public/web/WebTextCheckingResult.h" | 18 #include "third_party/WebKit/public/web/WebTextCheckingResult.h" |
19 | 19 |
20 #define TYPOGRAPHICAL_APOSTROPHE L"\x2019" | |
21 | |
22 namespace { | 20 namespace { |
23 | 21 |
24 base::FilePath GetHunspellDirectory() { | 22 base::FilePath GetHunspellDirectory() { |
25 base::FilePath hunspell_directory; | 23 base::FilePath hunspell_directory; |
26 if (!PathService::Get(base::DIR_SOURCE_ROOT, &hunspell_directory)) | 24 if (!PathService::Get(base::DIR_SOURCE_ROOT, &hunspell_directory)) |
27 return base::FilePath(); | 25 return base::FilePath(); |
28 | 26 |
29 hunspell_directory = hunspell_directory.AppendASCII("third_party"); | 27 hunspell_directory = hunspell_directory.AppendASCII("third_party"); |
30 hunspell_directory = hunspell_directory.AppendASCII("hunspell_dictionaries"); | 28 hunspell_directory = hunspell_directory.AppendASCII("hunspell_dictionaries"); |
31 return hunspell_directory; | 29 return hunspell_directory; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 | 73 |
76 ~SpellCheckTest() override {} | 74 ~SpellCheckTest() override {} |
77 | 75 |
78 SpellCheck* spell_check() { return spell_check_.get(); } | 76 SpellCheck* spell_check() { return spell_check_.get(); } |
79 | 77 |
80 bool CheckSpelling(const std::string& word, int tag) { | 78 bool CheckSpelling(const std::string& word, int tag) { |
81 return spell_check_->spellcheck_.platform_spelling_engine_->CheckSpelling( | 79 return spell_check_->spellcheck_.platform_spelling_engine_->CheckSpelling( |
82 base::ASCIIToUTF16(word), tag); | 80 base::ASCIIToUTF16(word), tag); |
83 } | 81 } |
84 | 82 |
85 bool IsValidContraction(const base::string16& word, int tag) { | |
86 return spell_check_->spellcheck_.IsValidContraction(word, tag); | |
87 } | |
88 | |
89 #if !defined(OS_MACOSX) | 83 #if !defined(OS_MACOSX) |
90 protected: | 84 protected: |
91 void TestSpellCheckParagraph( | 85 void TestSpellCheckParagraph( |
92 const base::string16& input, | 86 const base::string16& input, |
93 const std::vector<SpellCheckResult>& expected) { | 87 const std::vector<SpellCheckResult>& expected) { |
94 blink::WebVector<blink::WebTextCheckingResult> results; | 88 blink::WebVector<blink::WebTextCheckingResult> results; |
95 spell_check()->SpellCheckParagraph(input, | 89 spell_check()->SpellCheckParagraph(input, |
96 &results); | 90 &results); |
97 | 91 |
98 EXPECT_EQ(results.size(), expected.size()); | 92 EXPECT_EQ(results.size(), expected.size()); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 // Two valid Greek words (meaning "hello") consisting of seven Greek | 194 // Two valid Greek words (meaning "hello") consisting of seven Greek |
201 // letters | 195 // letters |
202 {L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", true}, | 196 {L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", true}, |
203 // A valid Russian word (meaning "hello") consisting of twelve Cyrillic | 197 // A valid Russian word (meaning "hello") consisting of twelve Cyrillic |
204 // letters | 198 // letters |
205 {L"\x0437\x0434\x0440\x0430\x0432\x0441" | 199 {L"\x0437\x0434\x0440\x0430\x0432\x0441" |
206 L"\x0442\x0432\x0443\x0439\x0442\x0435", true}, | 200 L"\x0442\x0432\x0443\x0439\x0442\x0435", true}, |
207 // A valid English contraction | 201 // A valid English contraction |
208 {L"isn't", true}, | 202 {L"isn't", true}, |
209 // A valid English contraction with a typographical apostrophe. | 203 // A valid English contraction with a typographical apostrophe. |
210 {L"isn" TYPOGRAPHICAL_APOSTROPHE L"t", true}, | 204 {L"isn\x2019t", true}, |
211 // A valid English word enclosed with underscores. | 205 // A valid English word enclosed with underscores. |
212 {L"_hello_", true}, | 206 {L"_hello_", true}, |
213 | 207 |
214 // A valid English word with a preceding whitespace | 208 // A valid English word with a preceding whitespace |
215 {L" " L"hello", true}, | 209 {L" " L"hello", true}, |
216 // A valid English word with a preceding no-break space | 210 // A valid English word with a preceding no-break space |
217 {L"\xA0" L"hello", true}, | 211 {L"\xA0" L"hello", true}, |
218 // A valid English word with a preceding ideographic space | 212 // A valid English word with a preceding ideographic space |
219 {L"\x3000" L"hello", true}, | 213 {L"\x3000" L"hello", true}, |
220 // A valid English word with a preceding Chinese word | 214 // A valid English word with a preceding Chinese word |
(...skipping 918 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1139 base::string16 text = base::ASCIIToUTF16("zz"); | 1133 base::string16 text = base::ASCIIToUTF16("zz"); |
1140 std::vector<SpellCheckResult> spellcheck_results; | 1134 std::vector<SpellCheckResult> spellcheck_results; |
1141 spellcheck_results.push_back(SpellCheckResult( | 1135 spellcheck_results.push_back(SpellCheckResult( |
1142 SpellCheckResult::SPELLING, 0, 2, base::string16())); | 1136 SpellCheckResult::SPELLING, 0, 2, base::string16())); |
1143 blink::WebVector<blink::WebTextCheckingResult> textcheck_results; | 1137 blink::WebVector<blink::WebTextCheckingResult> textcheck_results; |
1144 spell_check()->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER, | 1138 spell_check()->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER, |
1145 0, | 1139 0, |
1146 text, | 1140 text, |
1147 spellcheck_results, | 1141 spellcheck_results, |
1148 &textcheck_results); | 1142 &textcheck_results); |
1149 ASSERT_EQ(spellcheck_results.size(), textcheck_results.size()); | 1143 EXPECT_EQ(spellcheck_results.size(), textcheck_results.size()); |
1150 EXPECT_EQ(blink::WebTextDecorationTypeSpelling, | 1144 EXPECT_EQ(blink::WebTextDecorationTypeSpelling, |
1151 textcheck_results[0].decoration); | 1145 textcheck_results[0].decoration); |
1152 EXPECT_EQ(spellcheck_results[0].location, textcheck_results[0].location); | 1146 EXPECT_EQ(spellcheck_results[0].location, textcheck_results[0].location); |
1153 EXPECT_EQ(spellcheck_results[0].length, textcheck_results[0].length); | 1147 EXPECT_EQ(spellcheck_results[0].length, textcheck_results[0].length); |
1154 } | 1148 } |
1155 | 1149 |
1156 // Verify that the SpellCheck class replaces the spelling marker added to a | 1150 // Verify that the SpellCheck class replaces the spelling marker added to a |
1157 // contextually-misspelled word "bean" with a grammar marker. | 1151 // contextually-misspelled word "bean" with a grammar marker. |
1158 { | 1152 { |
1159 base::string16 text = base::ASCIIToUTF16("I have bean to USA."); | 1153 base::string16 text = base::ASCIIToUTF16("I have bean to USA."); |
1160 std::vector<SpellCheckResult> spellcheck_results; | 1154 std::vector<SpellCheckResult> spellcheck_results; |
1161 spellcheck_results.push_back(SpellCheckResult( | 1155 spellcheck_results.push_back(SpellCheckResult( |
1162 SpellCheckResult::SPELLING, 7, 4, base::string16())); | 1156 SpellCheckResult::SPELLING, 7, 4, base::string16())); |
1163 blink::WebVector<blink::WebTextCheckingResult> textcheck_results; | 1157 blink::WebVector<blink::WebTextCheckingResult> textcheck_results; |
1164 spell_check()->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER, | 1158 spell_check()->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER, |
1165 0, | 1159 0, |
1166 text, | 1160 text, |
1167 spellcheck_results, | 1161 spellcheck_results, |
1168 &textcheck_results); | 1162 &textcheck_results); |
1169 ASSERT_EQ(spellcheck_results.size(), textcheck_results.size()); | 1163 EXPECT_EQ(spellcheck_results.size(), textcheck_results.size()); |
1170 EXPECT_EQ(blink::WebTextDecorationTypeGrammar, | 1164 EXPECT_EQ(blink::WebTextDecorationTypeGrammar, |
1171 textcheck_results[0].decoration); | 1165 textcheck_results[0].decoration); |
1172 EXPECT_EQ(spellcheck_results[0].location, textcheck_results[0].location); | 1166 EXPECT_EQ(spellcheck_results[0].location, textcheck_results[0].location); |
1173 EXPECT_EQ(spellcheck_results[0].length, textcheck_results[0].length); | 1167 EXPECT_EQ(spellcheck_results[0].length, textcheck_results[0].length); |
1174 } | 1168 } |
1175 | |
1176 // Verify that the SpellCheck preserves the original apostrophe type in the | |
1177 // checked text, regardless of the type of apostrophe the browser returns. | |
1178 { | |
1179 base::string16 text = base::WideToUTF16( | |
1180 L"Ik've havn" TYPOGRAPHICAL_APOSTROPHE L"t ni'n" | |
1181 TYPOGRAPHICAL_APOSTROPHE L"out-s I've I" TYPOGRAPHICAL_APOSTROPHE | |
1182 L"ve"); | |
1183 std::vector<SpellCheckResult> spellcheck_results; | |
1184 | |
1185 // All typewriter apostrophe results. | |
1186 spellcheck_results.push_back(SpellCheckResult( | |
1187 SpellCheckResult::SPELLING, 0, 5, base::UTF8ToUTF16("I've"))); | |
1188 spellcheck_results.push_back(SpellCheckResult( | |
1189 SpellCheckResult::SPELLING, 6, 6, base::UTF8ToUTF16("haven't"))); | |
1190 spellcheck_results.push_back(SpellCheckResult( | |
1191 SpellCheckResult::SPELLING, 13, 10, base::UTF8ToUTF16("in'n'out's"))); | |
1192 | |
1193 // Replacements that differ only by apostrophe type should be ignored. | |
1194 spellcheck_results.push_back(SpellCheckResult( | |
1195 SpellCheckResult::SPELLING, 24, 4, base::UTF8ToUTF16("I've"))); | |
1196 spellcheck_results.push_back(SpellCheckResult( | |
1197 SpellCheckResult::SPELLING, 29, 4, base::UTF8ToUTF16("I've"))); | |
1198 | |
1199 // All typographical apostrophe results. | |
1200 spellcheck_results.push_back(SpellCheckResult( | |
1201 SpellCheckResult::SPELLING, 0, 5, | |
1202 base::WideToUTF16(L"I" TYPOGRAPHICAL_APOSTROPHE L"ve"))); | |
1203 spellcheck_results.push_back(SpellCheckResult( | |
1204 SpellCheckResult::SPELLING, 6, 6, | |
1205 base::WideToUTF16(L"haven" TYPOGRAPHICAL_APOSTROPHE L"t"))); | |
1206 spellcheck_results.push_back(SpellCheckResult( | |
1207 SpellCheckResult::SPELLING, 13, 10, base::WideToUTF16( | |
1208 L"in" TYPOGRAPHICAL_APOSTROPHE L"n" TYPOGRAPHICAL_APOSTROPHE L"out" | |
1209 TYPOGRAPHICAL_APOSTROPHE L"s"))); | |
1210 | |
1211 // Replacements that differ only by apostrophe type should be ignored. | |
1212 spellcheck_results.push_back(SpellCheckResult( | |
1213 SpellCheckResult::SPELLING, 24, 4, | |
1214 base::WideToUTF16(L"I" TYPOGRAPHICAL_APOSTROPHE L"ve"))); | |
1215 spellcheck_results.push_back(SpellCheckResult( | |
1216 SpellCheckResult::SPELLING, 29, 4, | |
1217 base::WideToUTF16(L"I" TYPOGRAPHICAL_APOSTROPHE L"ve"))); | |
1218 | |
1219 blink::WebVector<blink::WebTextCheckingResult> textcheck_results; | |
1220 spell_check()->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER, 0, | |
1221 text, spellcheck_results, | |
1222 &textcheck_results); | |
1223 | |
1224 static const wchar_t* kExpectedReplacements[] = { | |
1225 L"I've", | |
1226 L"haven" TYPOGRAPHICAL_APOSTROPHE L"t", | |
1227 L"in'n" TYPOGRAPHICAL_APOSTROPHE L"out's", | |
1228 L"I've", | |
1229 L"haven" TYPOGRAPHICAL_APOSTROPHE L"t", | |
1230 L"in'n" TYPOGRAPHICAL_APOSTROPHE L"out" TYPOGRAPHICAL_APOSTROPHE L"s", | |
1231 }; | |
1232 | |
1233 ASSERT_EQ(arraysize(kExpectedReplacements), textcheck_results.size()); | |
1234 for (size_t i = 0; i < arraysize(kExpectedReplacements); ++i) { | |
1235 EXPECT_EQ(base::WideToUTF16(kExpectedReplacements[i]), | |
1236 textcheck_results[i].replacement) | |
1237 << "i=" << i << "\nactual: \"" | |
1238 << base::string16(textcheck_results[i].replacement) << "\""; | |
1239 } | |
1240 } | |
1241 } | 1169 } |
1242 | 1170 |
1243 #endif | 1171 #endif |
1244 | 1172 |
1245 // Checks some words that should be present in all English dictionaries. | 1173 // Checks some words that should be present in all English dictionaries. |
1246 TEST_F(SpellCheckTest, EnglishWords) { | 1174 TEST_F(SpellCheckTest, EnglishWords) { |
1247 static const struct { | 1175 static const struct { |
1248 const char* input; | 1176 const char* input; |
1249 bool should_pass; | 1177 bool should_pass; |
1250 } kTestCases[] = { | 1178 } kTestCases[] = { |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1438 strlen(kTestCases[i].misspelled), | 1366 strlen(kTestCases[i].misspelled), |
1439 0, | 1367 0, |
1440 &misspelling_start, | 1368 &misspelling_start, |
1441 &misspelling_length, | 1369 &misspelling_length, |
1442 &suggestions)); | 1370 &suggestions)); |
1443 EXPECT_GE(suggestions.size(), static_cast<size_t>(1)); | 1371 EXPECT_GE(suggestions.size(), static_cast<size_t>(1)); |
1444 if (suggestions.size() > 0) | 1372 if (suggestions.size() > 0) |
1445 EXPECT_EQ(suggestions[0], base::ASCIIToUTF16(kTestCases[i].suggestion)); | 1373 EXPECT_EQ(suggestions[0], base::ASCIIToUTF16(kTestCases[i].suggestion)); |
1446 } | 1374 } |
1447 } | 1375 } |
1448 | |
1449 // Words with apostrophes should be valid contractions. | |
1450 TEST_F(SpellCheckTest, IsValidContraction) { | |
1451 static const char* kLanguages[] = { | |
1452 "en-AU", | |
1453 "en-CA", | |
1454 "en-GB", | |
1455 "en-US", | |
1456 }; | |
1457 | |
1458 static const wchar_t* kWords[] = { | |
1459 L"in'n'out", | |
1460 L"in" TYPOGRAPHICAL_APOSTROPHE L"n" TYPOGRAPHICAL_APOSTROPHE L"out", | |
1461 }; | |
1462 | |
1463 for (size_t i = 0; i < arraysize(kLanguages); ++i) { | |
1464 ReinitializeSpellCheck(kLanguages[i]); | |
1465 for (size_t j = 0; j < arraysize(kWords); ++j) | |
1466 EXPECT_TRUE(IsValidContraction(base::WideToUTF16(kWords[j]), 0)); | |
1467 } | |
1468 } | |
OLD | NEW |