Update broken references to image assets
[chromium-blink-merge.git] / chrome / browser / spellchecker / spelling_service_client_unittest.cc
blob92f2ecafeba08dae4f4c9da493e38dcf906a58d5
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
3 // found in the LICENSE file.
5 #include <string>
6 #include <vector>
8 #include "base/bind.h"
9 #include "base/json/json_reader.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "chrome/browser/spellchecker/spelling_service_client.h"
16 #include "chrome/common/pref_names.h"
17 #include "chrome/common/spellcheck_result.h"
18 #include "chrome/test/base/testing_profile.h"
19 #include "content/public/test/test_browser_thread_bundle.h"
20 #include "net/base/load_flags.h"
21 #include "net/url_request/test_url_fetcher_factory.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 namespace {
26 // A mock URL fetcher used in the TestingSpellingServiceClient class. This class
27 // verifies JSON-RPC requests when the SpellingServiceClient class sends them to
28 // the Spelling service. This class also verifies the SpellingServiceClient
29 // class does not either send cookies to the Spelling service or accept cookies
30 // from it.
31 class TestSpellingURLFetcher : public net::TestURLFetcher {
32 public:
33 TestSpellingURLFetcher(int id,
34 const GURL& url,
35 net::URLFetcherDelegate* d,
36 int version,
37 const std::string& sanitized_text,
38 const std::string& language,
39 int status,
40 const std::string& response)
41 : net::TestURLFetcher(0, url, d),
42 version_(base::StringPrintf("v%d", version)),
43 language_(language.empty() ? std::string("en") : language),
44 sanitized_text_(sanitized_text) {
45 set_response_code(status);
46 SetResponseString(response);
48 ~TestSpellingURLFetcher() override {}
50 void SetUploadData(const std::string& upload_content_type,
51 const std::string& upload_content) override {
52 // Verify the given content type is JSON. (The Spelling service returns an
53 // internal server error when this content type is not JSON.)
54 EXPECT_EQ("application/json", upload_content_type);
56 // Parse the JSON to be sent to the service, and verify its parameters.
57 scoped_ptr<base::DictionaryValue> value(
58 static_cast<base::DictionaryValue*>(base::JSONReader::DeprecatedRead(
59 upload_content, base::JSON_ALLOW_TRAILING_COMMAS)));
60 ASSERT_TRUE(value.get());
61 std::string method;
62 EXPECT_TRUE(value->GetString("method", &method));
63 EXPECT_EQ("spelling.check", method);
64 std::string version;
65 EXPECT_TRUE(value->GetString("apiVersion", &version));
66 EXPECT_EQ(version_, version);
67 std::string sanitized_text;
68 EXPECT_TRUE(value->GetString("params.text", &sanitized_text));
69 EXPECT_EQ(sanitized_text_, sanitized_text);
70 std::string language;
71 EXPECT_TRUE(value->GetString("params.language", &language));
72 EXPECT_EQ(language_, language);
73 ASSERT_TRUE(GetExpectedCountry(language, &country_));
74 std::string country;
75 EXPECT_TRUE(value->GetString("params.originCountry", &country));
76 EXPECT_EQ(country_, country);
78 net::TestURLFetcher::SetUploadData(upload_content_type, upload_content);
81 void Start() override {
82 // Verify that this client does not either send cookies to the Spelling
83 // service or accept cookies from it.
84 EXPECT_EQ(net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES,
85 GetLoadFlags());
88 private:
89 bool GetExpectedCountry(const std::string& language, std::string* country) {
90 static const struct {
91 const char* language;
92 const char* country;
93 } kCountries[] = {
94 {"af", "ZAF"},
95 {"en", "USA"},
97 for (size_t i = 0; i < arraysize(kCountries); ++i) {
98 if (!language.compare(kCountries[i].language)) {
99 country->assign(kCountries[i].country);
100 return true;
103 return false;
106 std::string version_;
107 std::string language_;
108 std::string country_;
109 std::string sanitized_text_;
112 // A class derived from the SpellingServiceClient class used by the
113 // SpellingServiceClientTest class. This class overrides CreateURLFetcher so
114 // this test can use TestSpellingURLFetcher. This class also lets tests access
115 // the ParseResponse method.
116 class TestingSpellingServiceClient : public SpellingServiceClient {
117 public:
118 TestingSpellingServiceClient()
119 : request_type_(0),
120 response_status_(0),
121 success_(false),
122 fetcher_(NULL) {
124 ~TestingSpellingServiceClient() override {}
126 void SetHTTPRequest(int type,
127 const std::string& sanitized_text,
128 const std::string& language) {
129 request_type_ = type;
130 sanitized_request_text_ = sanitized_text;
131 request_language_ = language;
134 void SetHTTPResponse(int status, const char* data) {
135 response_status_ = status;
136 response_data_.assign(data);
139 void SetExpectedTextCheckResult(bool success, const char* text) {
140 success_ = success;
141 corrected_text_.assign(base::UTF8ToUTF16(text));
144 void CallOnURLFetchComplete() {
145 ASSERT_TRUE(fetcher_);
146 fetcher_->delegate()->OnURLFetchComplete(fetcher_);
147 fetcher_ = NULL;
150 void VerifyResponse(bool success,
151 const base::string16& request_text,
152 const std::vector<SpellCheckResult>& results) {
153 EXPECT_EQ(success_, success);
154 base::string16 text(base::UTF8ToUTF16(sanitized_request_text_));
155 for (std::vector<SpellCheckResult>::const_iterator it = results.begin();
156 it != results.end(); ++it) {
157 text.replace(it->location, it->length, it->replacement);
159 EXPECT_EQ(corrected_text_, text);
162 bool ParseResponseSuccess(const std::string& data) {
163 std::vector<SpellCheckResult> results;
164 return ParseResponse(data, &results);
167 private:
168 scoped_ptr<net::URLFetcher> CreateURLFetcher(const GURL& url) override {
169 EXPECT_EQ("https://www.googleapis.com/rpc", url.spec());
170 fetcher_ = new TestSpellingURLFetcher(
171 0, url, this, request_type_, sanitized_request_text_, request_language_,
172 response_status_, response_data_);
173 return scoped_ptr<net::URLFetcher>(fetcher_);
176 int request_type_;
177 std::string sanitized_request_text_;
178 std::string request_language_;
179 int response_status_;
180 std::string response_data_;
181 bool success_;
182 base::string16 corrected_text_;
183 TestSpellingURLFetcher* fetcher_; // weak
186 // A test class used for testing the SpellingServiceClient class. This class
187 // implements a callback function used by the SpellingServiceClient class to
188 // monitor the class calls the callback with expected results.
189 class SpellingServiceClientTest : public testing::Test {
190 public:
191 void OnTextCheckComplete(int tag,
192 bool success,
193 const base::string16& text,
194 const std::vector<SpellCheckResult>& results) {
195 client_.VerifyResponse(success, text, results);
198 protected:
199 content::TestBrowserThreadBundle thread_bundle_;
200 TestingSpellingServiceClient client_;
201 TestingProfile profile_;
204 } // namespace
206 // Verifies that SpellingServiceClient::RequestTextCheck() creates a JSON
207 // request sent to the Spelling service as we expect. This test also verifies
208 // that it parses a JSON response from the service and calls the callback
209 // function. To avoid sending JSON-RPC requests to the service, this test uses a
210 // custom TestURLFecher class (TestSpellingURLFetcher) which calls
211 // SpellingServiceClient::OnURLFetchComplete() with the parameters set by this
212 // test. This test also uses a custom callback function that replaces all
213 // misspelled words with ones suggested by the service so this test can compare
214 // the corrected text with the expected results. (If there are not any
215 // misspelled words, |corrected_text| should be equal to |request_text|.)
216 TEST_F(SpellingServiceClientTest, RequestTextCheck) {
217 static const struct {
218 const wchar_t* request_text;
219 const char* sanitized_request_text;
220 SpellingServiceClient::ServiceType request_type;
221 int response_status;
222 const char* response_data;
223 bool success;
224 const char* corrected_text;
225 const char* language;
226 } kTests[] = {
228 L"",
230 SpellingServiceClient::SUGGEST,
231 500,
233 false,
235 "af",
236 }, {
237 L"chromebook",
238 "chromebook",
239 SpellingServiceClient::SUGGEST,
240 200,
241 "{}",
242 true,
243 "chromebook",
244 "af",
245 }, {
246 L"chrombook",
247 "chrombook",
248 SpellingServiceClient::SUGGEST,
249 200,
250 "{\n"
251 " \"result\": {\n"
252 " \"spellingCheckResponse\": {\n"
253 " \"misspellings\": [{\n"
254 " \"charStart\": 0,\n"
255 " \"charLength\": 9,\n"
256 " \"suggestions\": [{ \"suggestion\": \"chromebook\" }],\n"
257 " \"canAutoCorrect\": false\n"
258 " }]\n"
259 " }\n"
260 " }\n"
261 "}",
262 true,
263 "chromebook",
264 "af",
265 }, {
266 L"",
268 SpellingServiceClient::SPELLCHECK,
269 500,
271 false,
273 "en",
274 }, {
275 L"I have been to USA.",
276 "I have been to USA.",
277 SpellingServiceClient::SPELLCHECK,
278 200,
279 "{}",
280 true,
281 "I have been to USA.",
282 "en",
283 }, {
284 L"I have bean to USA.",
285 "I have bean to USA.",
286 SpellingServiceClient::SPELLCHECK,
287 200,
288 "{\n"
289 " \"result\": {\n"
290 " \"spellingCheckResponse\": {\n"
291 " \"misspellings\": [{\n"
292 " \"charStart\": 7,\n"
293 " \"charLength\": 4,\n"
294 " \"suggestions\": [{ \"suggestion\": \"been\" }],\n"
295 " \"canAutoCorrect\": false\n"
296 " }]\n"
297 " }\n"
298 " }\n"
299 "}",
300 true,
301 "I have been to USA.",
302 "en",
303 }, {
304 L"I\x2019mattheIn'n'Out.",
305 "I'mattheIn'n'Out.",
306 SpellingServiceClient::SPELLCHECK,
307 200,
308 "{\n"
309 " \"result\": {\n"
310 " \"spellingCheckResponse\": {\n"
311 " \"misspellings\": [{\n"
312 " \"charStart\": 0,\n"
313 " \"charLength\": 16,\n"
314 " \"suggestions\":"
315 " [{ \"suggestion\": \"I'm at the In'N'Out\" }],\n"
316 " \"canAutoCorrect\": false\n"
317 " }]\n"
318 " }\n"
319 " }\n"
320 "}",
321 true,
322 "I'm at the In'N'Out.",
323 "en",
327 PrefService* pref = profile_.GetPrefs();
328 pref->SetBoolean(prefs::kEnableContinuousSpellcheck, true);
329 pref->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
331 for (size_t i = 0; i < arraysize(kTests); ++i) {
332 client_.SetHTTPRequest(kTests[i].request_type,
333 kTests[i].sanitized_request_text,
334 kTests[i].language);
335 client_.SetHTTPResponse(kTests[i].response_status, kTests[i].response_data);
336 client_.SetExpectedTextCheckResult(kTests[i].success,
337 kTests[i].corrected_text);
338 base::ListValue dictionary;
339 dictionary.AppendString(kTests[i].language);
340 pref->Set(prefs::kSpellCheckDictionaries, dictionary);
342 client_.RequestTextCheck(
343 &profile_,
344 kTests[i].request_type,
345 base::WideToUTF16(kTests[i].request_text),
346 base::Bind(&SpellingServiceClientTest::OnTextCheckComplete,
347 base::Unretained(this), 0));
348 client_.CallOnURLFetchComplete();
352 // Verify that SpellingServiceClient::IsAvailable() returns true only when it
353 // can send suggest requests or spellcheck requests.
354 TEST_F(SpellingServiceClientTest, AvailableServices) {
355 const SpellingServiceClient::ServiceType kSuggest =
356 SpellingServiceClient::SUGGEST;
357 const SpellingServiceClient::ServiceType kSpellcheck =
358 SpellingServiceClient::SPELLCHECK;
360 // When a user disables spellchecking or prevent using the Spelling service,
361 // this function should return false both for suggestions and for spellcheck.
362 PrefService* pref = profile_.GetPrefs();
363 pref->SetBoolean(prefs::kEnableContinuousSpellcheck, false);
364 pref->SetBoolean(prefs::kSpellCheckUseSpellingService, false);
365 EXPECT_FALSE(client_.IsAvailable(&profile_, kSuggest));
366 EXPECT_FALSE(client_.IsAvailable(&profile_, kSpellcheck));
368 pref->SetBoolean(prefs::kEnableContinuousSpellcheck, true);
369 pref->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
371 // For locales supported by the SpellCheck service, this function returns
372 // false for suggestions and true for spellcheck. (The comment in
373 // SpellingServiceClient::IsAvailable() describes why this function returns
374 // false for suggestions.) If there is no language set, then we
375 // do not allow any remote.
376 pref->Set(prefs::kSpellCheckDictionaries, base::ListValue());
378 EXPECT_FALSE(client_.IsAvailable(&profile_, kSuggest));
379 EXPECT_FALSE(client_.IsAvailable(&profile_, kSpellcheck));
381 static const char* kSupported[] = {
382 "en-AU", "en-CA", "en-GB", "en-US", "da-DK", "es-ES",
384 // If spellcheck is allowed, then suggest is not since spellcheck is a
385 // superset of suggest.
386 for (size_t i = 0; i < arraysize(kSupported); ++i) {
387 base::ListValue dictionary;
388 dictionary.AppendString(kSupported[i]);
389 pref->Set(prefs::kSpellCheckDictionaries, dictionary);
391 EXPECT_FALSE(client_.IsAvailable(&profile_, kSuggest));
392 EXPECT_TRUE(client_.IsAvailable(&profile_, kSpellcheck));
395 // This function returns true for suggestions for all and false for
396 // spellcheck for unsupported locales.
397 static const char* kUnsupported[] = {
398 "af-ZA", "bg-BG", "ca-ES", "cs-CZ", "de-DE", "el-GR", "et-EE", "fo-FO",
399 "fr-FR", "he-IL", "hi-IN", "hr-HR", "hu-HU", "id-ID", "it-IT", "lt-LT",
400 "lv-LV", "nb-NO", "nl-NL", "pl-PL", "pt-BR", "pt-PT", "ro-RO", "ru-RU",
401 "sk-SK", "sl-SI", "sh", "sr", "sv-SE", "tr-TR", "uk-UA", "vi-VN",
403 for (size_t i = 0; i < arraysize(kUnsupported); ++i) {
404 SCOPED_TRACE(std::string("Expected language ") + kUnsupported[i]);
405 base::ListValue dictionary;
406 dictionary.AppendString(kUnsupported[i]);
407 pref->Set(prefs::kSpellCheckDictionaries, dictionary);
409 EXPECT_TRUE(client_.IsAvailable(&profile_, kSuggest));
410 EXPECT_FALSE(client_.IsAvailable(&profile_, kSpellcheck));
414 // Verify that an error in JSON response from spelling service will result in
415 // ParseResponse returning false.
416 TEST_F(SpellingServiceClientTest, ResponseErrorTest) {
417 EXPECT_TRUE(client_.ParseResponseSuccess("{\"result\": {}}"));
418 EXPECT_FALSE(client_.ParseResponseSuccess("{\"error\": {}}"));