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 |
20 namespace { | 22 namespace { |
21 | 23 |
22 base::FilePath GetHunspellDirectory() { | 24 base::FilePath GetHunspellDirectory() { |
23 base::FilePath hunspell_directory; | 25 base::FilePath hunspell_directory; |
24 if (!PathService::Get(base::DIR_SOURCE_ROOT, &hunspell_directory)) | 26 if (!PathService::Get(base::DIR_SOURCE_ROOT, &hunspell_directory)) |
25 return base::FilePath(); | 27 return base::FilePath(); |
26 | 28 |
27 hunspell_directory = hunspell_directory.AppendASCII("third_party"); | 29 hunspell_directory = hunspell_directory.AppendASCII("third_party"); |
28 hunspell_directory = hunspell_directory.AppendASCII("hunspell_dictionaries"); | 30 hunspell_directory = hunspell_directory.AppendASCII("hunspell_dictionaries"); |
29 return hunspell_directory; | 31 return hunspell_directory; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 | 75 |
74 ~SpellCheckTest() override {} | 76 ~SpellCheckTest() override {} |
75 | 77 |
76 SpellCheck* spell_check() { return spell_check_.get(); } | 78 SpellCheck* spell_check() { return spell_check_.get(); } |
77 | 79 |
78 bool CheckSpelling(const std::string& word, int tag) { | 80 bool CheckSpelling(const std::string& word, int tag) { |
79 return spell_check_->spellcheck_.platform_spelling_engine_->CheckSpelling( | 81 return spell_check_->spellcheck_.platform_spelling_engine_->CheckSpelling( |
80 base::ASCIIToUTF16(word), tag); | 82 base::ASCIIToUTF16(word), tag); |
81 } | 83 } |
82 | 84 |
| 85 bool IsValidContraction(const base::string16& word, int tag) { |
| 86 return spell_check_->spellcheck_.IsValidContraction(word, tag); |
| 87 } |
| 88 |
83 #if !defined(OS_MACOSX) | 89 #if !defined(OS_MACOSX) |
84 protected: | 90 protected: |
85 void TestSpellCheckParagraph( | 91 void TestSpellCheckParagraph( |
86 const base::string16& input, | 92 const base::string16& input, |
87 const std::vector<SpellCheckResult>& expected) { | 93 const std::vector<SpellCheckResult>& expected) { |
88 blink::WebVector<blink::WebTextCheckingResult> results; | 94 blink::WebVector<blink::WebTextCheckingResult> results; |
89 spell_check()->SpellCheckParagraph(input, | 95 spell_check()->SpellCheckParagraph(input, |
90 &results); | 96 &results); |
91 | 97 |
92 EXPECT_EQ(results.size(), expected.size()); | 98 EXPECT_EQ(results.size(), expected.size()); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 // Two valid Greek words (meaning "hello") consisting of seven Greek | 200 // Two valid Greek words (meaning "hello") consisting of seven Greek |
195 // letters | 201 // letters |
196 {L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", true}, | 202 {L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", true}, |
197 // A valid Russian word (meaning "hello") consisting of twelve Cyrillic | 203 // A valid Russian word (meaning "hello") consisting of twelve Cyrillic |
198 // letters | 204 // letters |
199 {L"\x0437\x0434\x0440\x0430\x0432\x0441" | 205 {L"\x0437\x0434\x0440\x0430\x0432\x0441" |
200 L"\x0442\x0432\x0443\x0439\x0442\x0435", true}, | 206 L"\x0442\x0432\x0443\x0439\x0442\x0435", true}, |
201 // A valid English contraction | 207 // A valid English contraction |
202 {L"isn't", true}, | 208 {L"isn't", true}, |
203 // A valid English contraction with a typographical apostrophe. | 209 // A valid English contraction with a typographical apostrophe. |
204 {L"isn\x2019t", true}, | 210 {L"isn" TYPOGRAPHICAL_APOSTROPHE L"t", true}, |
205 // A valid English word enclosed with underscores. | 211 // A valid English word enclosed with underscores. |
206 {L"_hello_", true}, | 212 {L"_hello_", true}, |
207 | 213 |
208 // A valid English word with a preceding whitespace | 214 // A valid English word with a preceding whitespace |
209 {L" " L"hello", true}, | 215 {L" " L"hello", true}, |
210 // A valid English word with a preceding no-break space | 216 // A valid English word with a preceding no-break space |
211 {L"\xA0" L"hello", true}, | 217 {L"\xA0" L"hello", true}, |
212 // A valid English word with a preceding ideographic space | 218 // A valid English word with a preceding ideographic space |
213 {L"\x3000" L"hello", true}, | 219 {L"\x3000" L"hello", true}, |
214 // A valid English word with a preceding Chinese word | 220 // A valid English word with a preceding Chinese word |
(...skipping 918 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1133 base::string16 text = base::ASCIIToUTF16("zz"); | 1139 base::string16 text = base::ASCIIToUTF16("zz"); |
1134 std::vector<SpellCheckResult> spellcheck_results; | 1140 std::vector<SpellCheckResult> spellcheck_results; |
1135 spellcheck_results.push_back(SpellCheckResult( | 1141 spellcheck_results.push_back(SpellCheckResult( |
1136 SpellCheckResult::SPELLING, 0, 2, base::string16())); | 1142 SpellCheckResult::SPELLING, 0, 2, base::string16())); |
1137 blink::WebVector<blink::WebTextCheckingResult> textcheck_results; | 1143 blink::WebVector<blink::WebTextCheckingResult> textcheck_results; |
1138 spell_check()->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER, | 1144 spell_check()->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER, |
1139 0, | 1145 0, |
1140 text, | 1146 text, |
1141 spellcheck_results, | 1147 spellcheck_results, |
1142 &textcheck_results); | 1148 &textcheck_results); |
1143 EXPECT_EQ(spellcheck_results.size(), textcheck_results.size()); | 1149 ASSERT_EQ(spellcheck_results.size(), textcheck_results.size()); |
1144 EXPECT_EQ(blink::WebTextDecorationTypeSpelling, | 1150 EXPECT_EQ(blink::WebTextDecorationTypeSpelling, |
1145 textcheck_results[0].decoration); | 1151 textcheck_results[0].decoration); |
1146 EXPECT_EQ(spellcheck_results[0].location, textcheck_results[0].location); | 1152 EXPECT_EQ(spellcheck_results[0].location, textcheck_results[0].location); |
1147 EXPECT_EQ(spellcheck_results[0].length, textcheck_results[0].length); | 1153 EXPECT_EQ(spellcheck_results[0].length, textcheck_results[0].length); |
1148 } | 1154 } |
1149 | 1155 |
1150 // Verify that the SpellCheck class replaces the spelling marker added to a | 1156 // Verify that the SpellCheck class replaces the spelling marker added to a |
1151 // contextually-misspelled word "bean" with a grammar marker. | 1157 // contextually-misspelled word "bean" with a grammar marker. |
1152 { | 1158 { |
1153 base::string16 text = base::ASCIIToUTF16("I have bean to USA."); | 1159 base::string16 text = base::ASCIIToUTF16("I have bean to USA."); |
1154 std::vector<SpellCheckResult> spellcheck_results; | 1160 std::vector<SpellCheckResult> spellcheck_results; |
1155 spellcheck_results.push_back(SpellCheckResult( | 1161 spellcheck_results.push_back(SpellCheckResult( |
1156 SpellCheckResult::SPELLING, 7, 4, base::string16())); | 1162 SpellCheckResult::SPELLING, 7, 4, base::string16())); |
1157 blink::WebVector<blink::WebTextCheckingResult> textcheck_results; | 1163 blink::WebVector<blink::WebTextCheckingResult> textcheck_results; |
1158 spell_check()->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER, | 1164 spell_check()->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER, |
1159 0, | 1165 0, |
1160 text, | 1166 text, |
1161 spellcheck_results, | 1167 spellcheck_results, |
1162 &textcheck_results); | 1168 &textcheck_results); |
1163 EXPECT_EQ(spellcheck_results.size(), textcheck_results.size()); | 1169 ASSERT_EQ(spellcheck_results.size(), textcheck_results.size()); |
1164 EXPECT_EQ(blink::WebTextDecorationTypeGrammar, | 1170 EXPECT_EQ(blink::WebTextDecorationTypeGrammar, |
1165 textcheck_results[0].decoration); | 1171 textcheck_results[0].decoration); |
1166 EXPECT_EQ(spellcheck_results[0].location, textcheck_results[0].location); | 1172 EXPECT_EQ(spellcheck_results[0].location, textcheck_results[0].location); |
1167 EXPECT_EQ(spellcheck_results[0].length, textcheck_results[0].length); | 1173 EXPECT_EQ(spellcheck_results[0].length, textcheck_results[0].length); |
1168 } | 1174 } |
| 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 } |
1169 } | 1241 } |
1170 | 1242 |
1171 #endif | 1243 #endif |
1172 | 1244 |
1173 // Checks some words that should be present in all English dictionaries. | 1245 // Checks some words that should be present in all English dictionaries. |
1174 TEST_F(SpellCheckTest, EnglishWords) { | 1246 TEST_F(SpellCheckTest, EnglishWords) { |
1175 static const struct { | 1247 static const struct { |
1176 const char* input; | 1248 const char* input; |
1177 bool should_pass; | 1249 bool should_pass; |
1178 } kTestCases[] = { | 1250 } kTestCases[] = { |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1366 strlen(kTestCases[i].misspelled), | 1438 strlen(kTestCases[i].misspelled), |
1367 0, | 1439 0, |
1368 &misspelling_start, | 1440 &misspelling_start, |
1369 &misspelling_length, | 1441 &misspelling_length, |
1370 &suggestions)); | 1442 &suggestions)); |
1371 EXPECT_GE(suggestions.size(), static_cast<size_t>(1)); | 1443 EXPECT_GE(suggestions.size(), static_cast<size_t>(1)); |
1372 if (suggestions.size() > 0) | 1444 if (suggestions.size() > 0) |
1373 EXPECT_EQ(suggestions[0], base::ASCIIToUTF16(kTestCases[i].suggestion)); | 1445 EXPECT_EQ(suggestions[0], base::ASCIIToUTF16(kTestCases[i].suggestion)); |
1374 } | 1446 } |
1375 } | 1447 } |
| 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 |