15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_reader.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/spellchecker/spelling_service_client.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/spellcheck_result.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/base/testing_profile.h"
19a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "content/public/test/test_browser_thread_bundle.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/load_flags.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/test_url_fetcher_factory.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A mock URL fetcher used in the TestingSpellingServiceClient class. This class
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// verifies JSON-RPC requests when the SpellingServiceClient class sends them to
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the Spelling service. This class also verifies the SpellingServiceClient
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// class does not either send cookies to the Spelling service or accept cookies
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from it.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TestSpellingURLFetcher : public net::TestURLFetcher {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TestSpellingURLFetcher(int id,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const GURL& url,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         net::URLFetcherDelegate* d,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         int version,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const std::string& text,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const std::string& language,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         int status,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const std::string& response)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : net::TestURLFetcher(0, url, d),
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        version_(base::StringPrintf("v%d", version)),
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        language_(language.empty() ? std::string("en") : language),
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        text_(text) {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    set_response_code(status);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetResponseString(response);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~TestSpellingURLFetcher() {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void SetUploadData(const std::string& upload_content_type,
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const std::string& upload_content) OVERRIDE {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Verify the given content type is JSON. (The Spelling service returns an
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // internal server error when this content type is not JSON.)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ("application/json", upload_content_type);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Parse the JSON to be sent to the service, and verify its parameters.
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::DictionaryValue> value(static_cast<base::DictionaryValue*>(
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::JSONReader::Read(upload_content,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               base::JSON_ALLOW_TRAILING_COMMAS)));
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(!!value.get());
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string method;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(value->GetString("method", &method));
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ("spelling.check", method);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string version;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(value->GetString("apiVersion", &version));
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(version_, version);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string text;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(value->GetString("params.text", &text));
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(text_, text);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string language;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(value->GetString("params.language", &language));
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(language_, language);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(GetExpectedCountry(language, &country_));
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string country;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(value->GetString("params.originCountry", &country));
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(country_, country);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::TestURLFetcher::SetUploadData(upload_content_type, upload_content);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Start() OVERRIDE {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Verify that this client does not either send cookies to the Spelling
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // service or accept cookies from it.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES,
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              GetLoadFlags());
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool GetExpectedCountry(const std::string& language, std::string* country) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const struct {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const char* language;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const char* country;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } kCountries[] = {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {"af", "ZAF"},
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {"en", "USA"},
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    };
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kCountries); ++i) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!language.compare(kCountries[i].language)) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        country->assign(kCountries[i].country);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string version_;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string language_;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string country_;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string text_;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A class derived from the SpellingServiceClient class used by the
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SpellingServiceClientTest class. This class overrides CreateURLFetcher so
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// this test can use TestSpellingURLFetcher. This class also lets tests access
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// the ParseResponse method.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TestingSpellingServiceClient : public SpellingServiceClient {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TestingSpellingServiceClient()
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : request_type_(0),
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        response_status_(0),
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        success_(false),
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fetcher_(NULL) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~TestingSpellingServiceClient() {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetHTTPRequest(int type,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const std::string& text,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const std::string& language) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request_type_ = type;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request_text_ = text;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request_language_ = language;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetHTTPResponse(int status, const char* data) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    response_status_ = status;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    response_data_.assign(data);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetExpectedTextCheckResult(bool success, const char* text) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success_ = success;
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    corrected_text_.assign(base::UTF8ToUTF16(text));
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CallOnURLFetchComplete() {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(!!fetcher_);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fetcher_->delegate()->OnURLFetchComplete(fetcher_);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fetcher_ = NULL;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void VerifyResponse(bool success,
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                      const base::string16& request_text,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const std::vector<SpellCheckResult>& results) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(success_, success);
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 text(base::UTF8ToUTF16(request_text_));
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(text, request_text);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::vector<SpellCheckResult>::const_iterator it = results.begin();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         it != results.end(); ++it) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      text.replace(it->location, it->length, it->replacement);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(corrected_text_, text);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool ParseResponseSuccess(const std::string& data) {
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::vector<SpellCheckResult> results;
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return ParseResponse(data, &results);
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual net::URLFetcher* CreateURLFetcher(const GURL& url) OVERRIDE {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ("https://www.googleapis.com/rpc", url.spec());
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fetcher_ = new TestSpellingURLFetcher(0, url, this,
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          request_type_, request_text_,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          request_language_,
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          response_status_, response_data_);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return fetcher_;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int request_type_;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string request_text_;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string request_language_;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int response_status_;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string response_data_;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success_;
186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 corrected_text_;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TestSpellingURLFetcher* fetcher_;  // weak
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A test class used for testing the SpellingServiceClient class. This class
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// implements a callback function used by the SpellingServiceClient class to
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// monitor the class calls the callback with expected results.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SpellingServiceClientTest : public testing::Test {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnTextCheckComplete(int tag,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           bool success,
197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           const base::string16& text,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const std::vector<SpellCheckResult>& results) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_.VerifyResponse(success, text, results);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
203a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  content::TestBrowserThreadBundle thread_bundle_;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TestingSpellingServiceClient client_;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TestingProfile profile_;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Verifies that SpellingServiceClient::RequestTextCheck() creates a JSON
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// request sent to the Spelling service as we expect. This test also verifies
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that it parses a JSON response from the service and calls the callback
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// function. To avoid sending JSON-RPC requests to the service, this test uses a
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// custom TestURLFecher class (TestSpellingURLFetcher) which calls
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SpellingServiceClient::OnURLFetchComplete() with the parameters set by this
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// test. This test also uses a custom callback function that replaces all
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// misspelled words with ones suggested by the service so this test can compare
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the corrected text with the expected results. (If there are not any
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// misspelled words, |corrected_text| should be equal to |request_text|.)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SpellingServiceClientTest, RequestTextCheck) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const struct {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* request_text;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SpellingServiceClient::ServiceType request_type;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int response_status;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* response_data;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool success;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* corrected_text;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* language;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } kTests[] = {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "",
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SpellingServiceClient::SUGGEST,
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      500,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "",
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      false,
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "",
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "af",
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }, {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "chromebook",
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SpellingServiceClient::SUGGEST,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      200,
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "{}",
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      true,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "chromebook",
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "af",
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }, {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "chrombook",
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SpellingServiceClient::SUGGEST,
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      200,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "{\n"
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "  \"result\": {\n"
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "    \"spellingCheckResponse\": {\n"
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "      \"misspellings\": [{\n"
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "        \"charStart\": 0,\n"
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "        \"charLength\": 9,\n"
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "        \"suggestions\": [{ \"suggestion\": \"chromebook\" }],\n"
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "        \"canAutoCorrect\": false\n"
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "      }]\n"
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "    }\n"
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "  }\n"
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "}",
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      true,
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "chromebook",
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "af",
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }, {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "",
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SpellingServiceClient::SPELLCHECK,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      500,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "",
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      false,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "",
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "en",
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }, {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "I have been to USA.",
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SpellingServiceClient::SPELLCHECK,
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      200,
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "{}",
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      true,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "I have been to USA.",
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "en",
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }, {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "I have bean to USA.",
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SpellingServiceClient::SPELLCHECK,
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      200,
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "{\n"
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "  \"result\": {\n"
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "    \"spellingCheckResponse\": {\n"
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "      \"misspellings\": [{\n"
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "        \"charStart\": 7,\n"
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "        \"charLength\": 4,\n"
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "        \"suggestions\": [{ \"suggestion\": \"been\" }],\n"
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "        \"canAutoCorrect\": false\n"
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "      }]\n"
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "    }\n"
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "  }\n"
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "}",
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      true,
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "I have been to USA.",
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "en",
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrefService* pref = profile_.GetPrefs();
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pref->SetBoolean(prefs::kEnableContinuousSpellcheck, true);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_.SetHTTPRequest(kTests[i].request_type, kTests[i].request_text,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           kTests[i].language);
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_.SetHTTPResponse(kTests[i].response_status, kTests[i].response_data);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_.SetExpectedTextCheckResult(kTests[i].success,
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       kTests[i].corrected_text);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pref->SetString(prefs::kSpellCheckDictionary, kTests[i].language);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_.RequestTextCheck(
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &profile_,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kTests[i].request_type,
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::ASCIIToUTF16(kTests[i].request_text),
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&SpellingServiceClientTest::OnTextCheckComplete,
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Unretained(this), 0));
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_.CallOnURLFetchComplete();
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Verify that SpellingServiceClient::IsAvailable() returns true only when it
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// can send suggest requests or spellcheck requests.
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(SpellingServiceClientTest, AvailableServices) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SpellingServiceClient::ServiceType kSuggest =
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SpellingServiceClient::SUGGEST;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SpellingServiceClient::ServiceType kSpellcheck =
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SpellingServiceClient::SPELLCHECK;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When a user disables spellchecking or prevent using the Spelling service,
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this function should return false both for suggestions and for spellcheck.
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrefService* pref = profile_.GetPrefs();
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pref->SetBoolean(prefs::kEnableContinuousSpellcheck, false);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref->SetBoolean(prefs::kSpellCheckUseSpellingService, false);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(client_.IsAvailable(&profile_, kSuggest));
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(client_.IsAvailable(&profile_, kSpellcheck));
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pref->SetBoolean(prefs::kEnableContinuousSpellcheck, true);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For locales supported by the SpellCheck service, this function returns
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // false for suggestions and true for spellcheck. (The comment in
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SpellingServiceClient::IsAvailable() describes why this function returns
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // false for suggestions.) If there is no language set, then we
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // do not allow any remote.
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pref->SetString(prefs::kSpellCheckDictionary, std::string());
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(client_.IsAvailable(&profile_, kSuggest));
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(client_.IsAvailable(&profile_, kSpellcheck));
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char* kSupported[] = {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "en-AU", "en-CA", "en-GB", "en-US",
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If spellcheck is allowed, then suggest is not since spellcheck is a
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // superset of suggest.
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSupported); ++i) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pref->SetString(prefs::kSpellCheckDictionary, kSupported[i]);
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_FALSE(client_.IsAvailable(&profile_, kSuggest));
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(client_.IsAvailable(&profile_, kSpellcheck));
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This function returns true for suggestions for all and false for
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // spellcheck for unsupported locales.
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char* kUnsupported[] = {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "af-ZA", "bg-BG", "ca-ES", "cs-CZ", "da-DK", "de-DE", "el-GR", "es-ES",
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "et-EE", "fo-FO", "fr-FR", "he-IL", "hi-IN", "hr-HR", "hu-HU", "id-ID",
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "it-IT", "lt-LT", "lv-LV", "nb-NO", "nl-NL", "pl-PL", "pt-BR", "pt-PT",
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "ro-RO", "ru-RU", "sk-SK", "sl-SI", "sh", "sr", "sv-SE", "tr-TR",
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "uk-UA", "vi-VN",
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kUnsupported); ++i) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pref->SetString(prefs::kSpellCheckDictionary, kUnsupported[i]);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(client_.IsAvailable(&profile_, kSuggest));
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_FALSE(client_.IsAvailable(&profile_, kSpellcheck));
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
382868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
383868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Verify that an error in JSON response from spelling service will result in
384868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// ParseResponse returning false.
385868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(SpellingServiceClientTest, ResponseErrorTest) {
386868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_TRUE(client_.ParseResponseSuccess("{\"result\": {}}"));
387868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_FALSE(client_.ParseResponseSuccess("{\"error\": {}}"));
388868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
389