blob: 1af1ad9dcf7a7eb4c9a97deb67099c8b838b4720 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/test_runner/mock_spell_check.h"
#include <stddef.h>
#include <algorithm>
#include "base/logging.h"
#include "base/macros.h"
#include "components/test_runner/test_common.h"
namespace test_runner {
namespace {
void Append(blink::WebVector<blink::WebString>* data,
const blink::WebString& item) {
blink::WebVector<blink::WebString> result(data->size() + 1);
for (size_t i = 0; i < data->size(); ++i)
result[i] = (*data)[i];
result[data->size()] = item;
data->swap(result);
}
} // namespace
MockSpellCheck::MockSpellCheck() : initialized_(false) {
}
MockSpellCheck::~MockSpellCheck() {
}
bool MockSpellCheck::SpellCheckWord(const blink::WebString& text,
int* misspelled_offset,
int* misspelled_length) {
DCHECK(misspelled_offset);
DCHECK(misspelled_length);
// Initialize this spellchecker.
InitializeIfNeeded();
// Reset the result values as our spellchecker does.
*misspelled_offset = 0;
*misspelled_length = 0;
// Convert to a base::string16 because we store base::string16 instances in
// misspelled_words_ and blink::WebString has no find().
base::string16 string_text = text.utf16();
int skipped_length = 0;
while (!string_text.empty()) {
// Extract the first possible English word from the given string.
// The given string may include non-ASCII characters or numbers. So, we
// should filter out such characters before start looking up our
// misspelled-word table.
// (This is a simple version of our SpellCheckWordIterator class.)
// If the given string doesn't include any ASCII characters, we can treat
// the string as valid one.
base::string16::iterator first_char =
std::find_if(string_text.begin(), string_text.end(), IsASCIIAlpha);
if (first_char == string_text.end())
return true;
int word_offset = std::distance(string_text.begin(), first_char);
int max_word_length = static_cast<int>(string_text.length()) - word_offset;
int word_length;
base::string16 word;
// Look up our misspelled-word table to check if the extracted word is a
// known misspelled word, and return the offset and the length of the
// extracted word if this word is a known misspelled word.
// (See the comment in MockSpellCheck::InitializeIfNeeded() why we use a
// misspelled-word table.)
for (size_t i = 0; i < misspelled_words_.size(); ++i) {
word_length =
static_cast<int>(misspelled_words_.at(i).length()) > max_word_length
? max_word_length
: static_cast<int>(misspelled_words_.at(i).length());
word = string_text.substr(word_offset, word_length);
if (word == misspelled_words_.at(i) &&
(static_cast<int>(string_text.length()) ==
word_offset + word_length ||
IsNotASCIIAlpha(string_text[word_offset + word_length]))) {
*misspelled_offset = word_offset + skipped_length;
*misspelled_length = word_length;
break;
}
}
if (*misspelled_length > 0)
break;
base::string16::iterator last_char = std::find_if(
string_text.begin() + word_offset, string_text.end(), IsNotASCIIAlpha);
if (last_char == string_text.end())
word_length = static_cast<int>(string_text.length()) - word_offset;
else
word_length = std::distance(first_char, last_char);
DCHECK_LT(0, word_offset + word_length);
string_text = string_text.substr(word_offset + word_length);
skipped_length += word_offset + word_length;
}
return false;
}
bool MockSpellCheck::HasInCache(const blink::WebString& word) {
return word == "Spell wellcome. Is it broken?" ||
word == "Spell wellcome.\x007F";
}
bool MockSpellCheck::IsMultiWordMisspelling(
const blink::WebString& text,
std::vector<blink::WebTextCheckingResult>* results) {
if (text == "Helllo wordl.") {
results->push_back(blink::WebTextCheckingResult(
blink::WebTextDecorationTypeSpelling, 0, 6, blink::WebString("Hello")));
results->push_back(blink::WebTextCheckingResult(
blink::WebTextDecorationTypeSpelling, 7, 5, blink::WebString("world")));
return true;
}
return false;
}
void MockSpellCheck::FillSuggestionList(
const blink::WebString& word,
blink::WebVector<blink::WebString>* suggestions) {
if (word == "wellcome")
Append(suggestions, blink::WebString::fromUTF8("welcome"));
else if (word == "upper case")
Append(suggestions, blink::WebString::fromUTF8("uppercase"));
else if (word == "Helllo")
Append(suggestions, blink::WebString::fromUTF8("Hello"));
else if (word == "wordl")
Append(suggestions, blink::WebString::fromUTF8("world"));
}
bool MockSpellCheck::InitializeIfNeeded() {
// Exit if we have already initialized this object.
if (initialized_)
return false;
// Create a table that consists of misspelled words used in WebKit layout
// tests.
// Since WebKit layout tests don't have so many misspelled words as
// well-spelled words, it is easier to compare the given word with misspelled
// ones than to compare with well-spelled ones.
static const char* misspelled_words[] = {
// These words are known misspelled words in webkit tests.
// If there are other misspelled words in webkit tests, please add them in
// this array.
"foo", "Foo", "baz", "fo", "LibertyF",
"chello", "xxxtestxxx", "XXxxx", "Textx", "blockquoted",
"asd", "Lorem", "Nunc", "Curabitur", "eu",
"adlj", "adaasj", "sdklj", "jlkds", "jsaada",
"jlda", "zz", "contentEditable",
// The following words are used by unit tests.
"ifmmp", "qwertyuiopasd", "qwertyuiopasdf", "upper case", "wellcome"};
misspelled_words_.clear();
for (size_t i = 0; i < arraysize(misspelled_words); ++i)
misspelled_words_.push_back(
base::string16(misspelled_words[i],
misspelled_words[i] + strlen(misspelled_words[i])));
// Mark as initialized to prevent this object from being initialized twice
// or more.
initialized_ = true;
// Since this MockSpellCheck class doesn't download dictionaries, this
// function always returns false.
return false;
}
} // namespace test_runner