diff options
author | shinyak@chromium.org <shinyak@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-19 18:58:23 +0000 |
---|---|---|
committer | shinyak@chromium.org <shinyak@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-19 18:58:23 +0000 |
commit | acb38b0ab5acfa3327e57f2d2bed9d7626d0f2d0 (patch) | |
tree | 951b7f74260680369e9ec33d099de13488a4840b /chrome/renderer | |
parent | e4a1771c8d6de3e6eb60aa8ac159ad8e99403e06 (diff) | |
download | chromium_src-acb38b0ab5acfa3327e57f2d2bed9d7626d0f2d0.zip chromium_src-acb38b0ab5acfa3327e57f2d2bed9d7626d0f2d0.tar.gz chromium_src-acb38b0ab5acfa3327e57f2d2bed9d7626d0f2d0.tar.bz2 |
This patch implements asynchronous spellchecker on Windows and Linux.
Though Mac already has its own spellchecker, Linux and Windows don't have one. So we have implemented asynchronous spellchecker posting a task.
BUG=6424, 111593
TEST=SpellCheckTest.*
Review URL: http://codereview.chromium.org/9169082
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@133029 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r-- | chrome/renderer/spellchecker/spellcheck.cc | 156 | ||||
-rw-r--r-- | chrome/renderer/spellchecker/spellcheck.h | 62 | ||||
-rw-r--r-- | chrome/renderer/spellchecker/spellcheck_provider.cc | 44 | ||||
-rw-r--r-- | chrome/renderer/spellchecker/spellcheck_provider.h | 2 | ||||
-rw-r--r-- | chrome/renderer/spellchecker/spellcheck_unittest.cc | 160 |
5 files changed, 382 insertions, 42 deletions
diff --git a/chrome/renderer/spellchecker/spellcheck.cc b/chrome/renderer/spellchecker/spellcheck.cc index e8ccc1a..e16927a 100644 --- a/chrome/renderer/spellchecker/spellcheck.cc +++ b/chrome/renderer/spellchecker/spellcheck.cc @@ -4,8 +4,10 @@ #include "chrome/renderer/spellchecker/spellcheck.h" +#include "base/bind.h" #include "base/file_util.h" #include "base/metrics/histogram.h" +#include "base/message_loop_proxy.h" #include "base/time.h" #include "base/utf_string_conversions.h" #include "chrome/common/render_messages.h" @@ -14,15 +16,84 @@ #include "chrome/common/spellcheck_result.h" #include "content/public/renderer/render_thread.h" #include "third_party/hunspell/src/hunspell/hunspell.hxx" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingCompletion.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingResult.h" using base::TimeTicks; using content::RenderThread; +using WebKit::WebVector; +using WebKit::WebTextCheckingResult; +using WebKit::WebTextCheckingType; + +namespace spellcheck { +void ToWebResultList( + int offset, + const std::vector<SpellCheckResult>& results, + WebVector<WebTextCheckingResult>* web_results) { + WebVector<WebTextCheckingResult> list(results.size()); + for (size_t i = 0; i < results.size(); ++i) { + list[i] = WebTextCheckingResult( + static_cast<WebTextCheckingType>(results[i].type), + results[i].location + offset, + results[i].length, + results[i].replacement); + } + + list.swap(*web_results); +} + +WebVector<WebTextCheckingResult> ToWebResultList( + int offset, + const std::vector<SpellCheckResult>& results) { + WebVector<WebTextCheckingResult> web_results; + ToWebResultList(offset, results, &web_results); + return web_results; +} +} // namespace spellcheck + +class SpellCheck::SpellCheckRequestParam + : public base::RefCountedThreadSafe<SpellCheck::SpellCheckRequestParam> { + public: + SpellCheckRequestParam(const string16& text, + int offset, + WebKit::WebTextCheckingCompletion* completion) + : text_(text), + offset_(offset), + completion_(completion) { + DCHECK(completion); + } + + string16 text() { + return text_; + } + + int offset() { + return offset_; + } + + WebKit::WebTextCheckingCompletion* completion() { + return completion_; + } + + private: + // Text to be checked in this task. + string16 text_; + + // The text offset from the beginning. + int offset_; + + // The interface to send the misspelled ranges to WebKit. + WebKit::WebTextCheckingCompletion* completion_; + + DISALLOW_COPY_AND_ASSIGN(SpellCheckRequestParam); +}; SpellCheck::SpellCheck() : file_(base::kInvalidPlatformFileValue), auto_spell_correct_turned_on_(false), is_using_platform_spelling_engine_(false), - initialized_(false) { + initialized_(false), + dictionary_requested_(false) { // Wait till we check the first word before doing any initializing. } @@ -49,6 +120,8 @@ void SpellCheck::OnInit(IPC::PlatformFileForTransit bdict_file, Init(IPC::PlatformFileForTransitToPlatformFile(bdict_file), custom_words, language); auto_spell_correct_turned_on_ = auto_spell_correct; + + PostDelayedSpellCheckTask(); } void SpellCheck::OnWordAdded(const std::string& word) { @@ -147,7 +220,6 @@ bool SpellCheck::SpellCheckWord( bool SpellCheck::SpellCheckParagraph( const string16& text, - int tag, std::vector<SpellCheckResult>* results) { #if !defined(OS_MACOSX) // Mac has its own spell checker, so this method will not be used. @@ -238,6 +310,41 @@ string16 SpellCheck::GetAutoCorrectionWord(const string16& word, int tag) { return autocorrect_word; } +void SpellCheck::RequestTextChecking( + const string16& text, + int offset, + WebKit::WebTextCheckingCompletion* completion) { +#if !defined(OS_MACOSX) + // Commented out on Mac, because SpellCheckRequest::PerformSpellCheck is not + // implemented on Mac. Mac uses its own spellchecker, so this method + // will not be used. + + DCHECK(!is_using_platform_spelling_engine_); + + // Clean up the previous request before starting a new request. + if (pending_request_param_.get()) { + pending_request_param_->completion()->didFinishCheckingText( + WebKit::WebVector<WebKit::WebTextCheckingResult>()); + pending_request_param_ = NULL; + } + + if (InitializeIfNeeded()) { + // We will check this text after we finish loading the hunspell dictionary. + // Save parameters so that we can use them when we receive an init message + // from the browser process. + pending_request_param_ = new SpellCheckRequestParam( + text, offset, completion); + return; + } + + requested_params_.push(new SpellCheckRequestParam(text, offset, completion)); + base::MessageLoopProxy::current()->PostTask(FROM_HERE, + base::Bind(&SpellCheck::PerformSpellCheck, AsWeakPtr())); +#else + NOTREACHED(); +#endif +} + void SpellCheck::InitializeHunspell() { if (hunspell_.get()) return; @@ -272,9 +379,11 @@ bool SpellCheck::InitializeIfNeeded() { if (is_using_platform_spelling_engine_) return false; - if (!initialized_) { - RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary); - initialized_ = true; + if (!initialized_ && !dictionary_requested_) { + // RenderThread will not exist in test. + if (RenderThread::Get()) + RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary); + dictionary_requested_ = true; return true; } @@ -282,7 +391,7 @@ bool SpellCheck::InitializeIfNeeded() { if (file_ != base::kInvalidPlatformFileValue) InitializeHunspell(); - return false; + return !initialized_; } // When called, relays the request to check the spelling to the proper @@ -314,6 +423,41 @@ bool SpellCheck::CheckSpelling(const string16& word_to_check, int tag) { return word_correct; } +void SpellCheck::PostDelayedSpellCheckTask() { + if (!pending_request_param_) + return; + + if (file_ == base::kInvalidPlatformFileValue) { + pending_request_param_->completion()->didFinishCheckingText( + WebKit::WebVector<WebKit::WebTextCheckingResult>()); + } else { + requested_params_.push(pending_request_param_); + base::MessageLoopProxy::current()->PostTask(FROM_HERE, + base::Bind(&SpellCheck::PerformSpellCheck, AsWeakPtr())); + } + + pending_request_param_ = NULL; +} + +void SpellCheck::PerformSpellCheck() { +#if !defined(OS_MACOSX) + DCHECK(!requested_params_.empty()); + scoped_refptr<SpellCheckRequestParam> param = requested_params_.front(); + DCHECK(param); + requested_params_.pop(); + + std::vector<SpellCheckResult> results; + SpellCheckParagraph(param->text(), &results); + param->completion()->didFinishCheckingText( + spellcheck::ToWebResultList(param->offset(), results)); +#else + // SpellCheck::SpellCheckParagraph is not implemented on Mac, + // so we return without spellchecking. Note that Mac uses its own + // spellchecker, this function won't be used. + NOTREACHED(); +#endif +} + void SpellCheck::FillSuggestionList( const string16& wrong_word, std::vector<string16>* optional_suggestions) { diff --git a/chrome/renderer/spellchecker/spellcheck.h b/chrome/renderer/spellchecker/spellcheck.h index 8567163..5cf0ef4 100644 --- a/chrome/renderer/spellchecker/spellcheck.h +++ b/chrome/renderer/spellchecker/spellcheck.h @@ -7,16 +7,20 @@ #pragma once #include <string> +#include <queue> #include <vector> #include "base/gtest_prod_util.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/platform_file.h" #include "base/string16.h" #include "base/time.h" #include "chrome/renderer/spellchecker/spellcheck_worditerator.h" #include "content/public/renderer/render_process_observer.h" #include "ipc/ipc_platform_file.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" #include "unicode/uscript.h" class Hunspell; @@ -26,9 +30,28 @@ namespace file_util { class MemoryMappedFile; } +namespace WebKit { +class WebTextCheckingCompletion; +struct WebTextCheckingResult; +} + +namespace spellcheck { +// Converts vector<SpellCheckResult> to WebVector<WebTextCheckingResult> +// for WebKit. +void ToWebResultList( + int offset, + const std::vector<SpellCheckResult>& results, + WebKit::WebVector<WebKit::WebTextCheckingResult>* web_results); + +WebKit::WebVector<WebKit::WebTextCheckingResult> ToWebResultList( + int offset, + const std::vector<SpellCheckResult>& results); +} + // TODO(morrita): Needs reorg with SpellCheckProvider. // See http://crbug.com/73699. -class SpellCheck : public content::RenderProcessObserver { +class SpellCheck : public content::RenderProcessObserver, + public base::SupportsWeakPtr<SpellCheck> { public: SpellCheck(); virtual ~SpellCheck(); @@ -57,10 +80,7 @@ class SpellCheck : public content::RenderProcessObserver { // SpellCheck a paragrpah. // Returns true if |text| is correctly spelled, false otherwise. // If the spellchecker failed to initialize, always returns true. - // The |tag| parameter should either be a unique identifier for the document, - // or 0. bool SpellCheckParagraph(const string16& text, - int tag, std::vector<SpellCheckResult>* results); // Find a possible correctly spelled word for a misspelled word. Computes an @@ -71,6 +91,12 @@ class SpellCheck : public content::RenderProcessObserver { // behind its command line flag. string16 GetAutoCorrectionWord(const string16& word, int tag); + // Requests to spellcheck the specified text in the background. This function + // posts a background task and calls SpellCheckParagraph() in the task. + void RequestTextChecking(const string16& text, + int offset, + WebKit::WebTextCheckingCompletion* completion); + // Returns true if the spellchecker delegate checking to a system-provided // checker on the browser process. bool is_using_platform_spelling_engine() const { @@ -79,6 +105,10 @@ class SpellCheck : public content::RenderProcessObserver { private: FRIEND_TEST_ALL_PREFIXES(SpellCheckTest, GetAutoCorrectionWord_EN_US); + FRIEND_TEST_ALL_PREFIXES(SpellCheckTest, + RequestSpellCheckMultipleTimesWithoutInitialization); + + class SpellCheckRequestParam; // RenderProcessObserver implementation: virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE; @@ -107,6 +137,12 @@ class SpellCheck : public content::RenderProcessObserver { // backend, either hunspell or a platform-specific backend. bool CheckSpelling(const string16& word_to_check, int tag); + // Posts delayed spellcheck task and clear it if any. + void PostDelayedSpellCheckTask(); + + // Performs spell checking from the request queue. + void PerformSpellCheck(); + // When called, relays the request to fill the list with suggestions to // the proper backend, either hunspell or a platform-specific backend. void FillSuggestionList(const string16& wrong_word, @@ -147,12 +183,26 @@ class SpellCheck : public content::RenderProcessObserver { // and False if hunspell is being used. bool is_using_platform_spelling_engine_; - // This flags whether we have ever been initialized, or have asked the browser - // for a dictionary. The value indicates whether we should request a + // This flags is true if we have been intialized. + // The value indicates whether we should request a // dictionary from the browser when the render view asks us to check the // spelling of a word. bool initialized_; + // This flags is true if we have requested dictionary. + bool dictionary_requested_; + + // The parameters of a pending background-spellchecking request. When WebKit + // sends a background-spellchecking request before initializing hunspell, + // we save its parameters and start spellchecking after we finish initializing + // hunspell. (When WebKit sends two or more requests, we cancel the previous + // requests so we do not have to use vectors.) + scoped_refptr<SpellCheckRequestParam> pending_request_param_; + + // The set of params already requested. When finishing the request, the params + // should be removed from the set. + std::queue<scoped_refptr<SpellCheckRequestParam> > requested_params_; + DISALLOW_COPY_AND_ASSIGN(SpellCheck); }; diff --git a/chrome/renderer/spellchecker/spellcheck_provider.cc b/chrome/renderer/spellchecker/spellcheck_provider.cc index 89b7cfc..b3fd4a9 100644 --- a/chrome/renderer/spellchecker/spellcheck_provider.cc +++ b/chrome/renderer/spellchecker/spellcheck_provider.cc @@ -18,6 +18,7 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" +using spellcheck::ToWebResultList; using WebKit::WebFrame; using WebKit::WebString; using WebKit::WebTextCheckingCompletion; @@ -42,34 +43,6 @@ COMPILE_ASSERT(int(WebKit::WebTextCheckingTypeCorrection) == COMPILE_ASSERT(int(WebKit::WebTextCheckingTypeShowCorrectionPanel) == int(SpellCheckResult::SHOWCORRECTIONPANEL), mismatching_enums); -namespace { - -void ToWebResultList( - int offset, - const std::vector<SpellCheckResult>& results, - WebVector<WebTextCheckingResult>* web_results) { - WebVector<WebTextCheckingResult> list(results.size()); - for (size_t i = 0; i < results.size(); ++i) { - list[i] = WebTextCheckingResult( - static_cast<WebTextCheckingType>(results[i].type), - results[i].location + offset, - results[i].length, - results[i].replacement); - } - - list.swap(*web_results); -} - -WebVector<WebTextCheckingResult> ToWebResultList( - int offset, - const std::vector<SpellCheckResult>& results) { - WebVector<WebTextCheckingResult> web_results; - ToWebResultList(offset, results, &web_results); - return web_results; -} - -} // namespace - SpellCheckProvider::SpellCheckProvider( content::RenderView* render_view, chrome::ChromeContentRendererClient* renderer_client) @@ -118,6 +91,7 @@ void SpellCheckProvider::RequestTextChecking( completion->didFinishCheckingText(std::vector<WebTextCheckingResult>()); return; } + last_line_ = line; Send(new SpellCheckHostMsg_CallSpellingService( routing_id(), @@ -210,7 +184,6 @@ void SpellCheckProvider::checkTextOfParagraph( std::vector<SpellCheckResult> tmp_results; chrome_content_renderer_client_->spellcheck()->SpellCheckParagraph( string16(text), - document_tag_, &tmp_results); ToWebResultList(0, tmp_results, results); #endif @@ -257,12 +230,25 @@ void SpellCheckProvider::updateSpellingUIWithMisspelledWord( void SpellCheckProvider::OnRespondSpellingService( int identifier, int offset, + bool succeeded, + const string16& text, const std::vector<SpellCheckResult>& results) { WebTextCheckingCompletion* completion = text_check_completions_.Lookup(identifier); if (!completion) return; text_check_completions_.Remove(identifier); + + // If |succeeded| is false, we use local spellcheck as a fallback. + if (!succeeded) { + // |chrome_content_renderer_client| may be NULL in unit tests. + if (chrome_content_renderer_client_) { + chrome_content_renderer_client_->spellcheck()->RequestTextChecking( + text, offset, completion); + return; + } + } + completion->didFinishCheckingText(ToWebResultList(offset, results)); } diff --git a/chrome/renderer/spellchecker/spellcheck_provider.h b/chrome/renderer/spellchecker/spellcheck_provider.h index 72ac84e..8419c90 100644 --- a/chrome/renderer/spellchecker/spellcheck_provider.h +++ b/chrome/renderer/spellchecker/spellcheck_provider.h @@ -81,6 +81,8 @@ class SpellCheckProvider : public content::RenderViewObserver, void OnRespondSpellingService( int identifier, int offset, + bool succeeded, + const string16& text, const std::vector<SpellCheckResult>& results); // Returns whether |text| has word characters after |index|, i.e. whether a diff --git a/chrome/renderer/spellchecker/spellcheck_unittest.cc b/chrome/renderer/spellchecker/spellcheck_unittest.cc index eeb0a4d..4e2cea6 100644 --- a/chrome/renderer/spellchecker/spellcheck_unittest.cc +++ b/chrome/renderer/spellchecker/spellcheck_unittest.cc @@ -15,6 +15,8 @@ #include "chrome/common/spellcheck_common.h" #include "chrome/common/spellcheck_result.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingCompletion.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCheckingResult.h" namespace { @@ -39,7 +41,14 @@ class SpellCheckTest : public testing::Test { void ReinitializeSpellCheck(const std::string& language) { spell_check_.reset(new SpellCheck()); + InitializeSpellCheck(language); + } + + void UninitializeSpellCheck() { + spell_check_.reset(new SpellCheck()); + } + void InitializeSpellCheck(const std::string& language) { FilePath hunspell_directory = GetHunspellDirectory(); EXPECT_FALSE(hunspell_directory.empty()); base::PlatformFile file = base::CreatePlatformFile( @@ -61,7 +70,6 @@ class SpellCheckTest : public testing::Test { const std::vector<SpellCheckResult>& expected) { std::vector<SpellCheckResult> results; spell_check()->SpellCheckParagraph(input, - 0, &results); EXPECT_EQ(results.size(), expected.size()); @@ -76,6 +84,24 @@ class SpellCheckTest : public testing::Test { private: scoped_ptr<SpellCheck> spell_check_; + MessageLoop loop; +}; + +// A fake completion object for verification. +class MockTextCheckingCompletion : public WebKit::WebTextCheckingCompletion { + public: + MockTextCheckingCompletion() + : completion_count_(0) { + } + + virtual void didFinishCheckingText( + const WebKit::WebVector<WebKit::WebTextCheckingResult>& results) { + completion_count_++; + last_results_ = results; + } + + size_t completion_count_; + WebKit::WebVector<WebKit::WebTextCheckingResult> last_results_; }; // Operates unit tests for the webkit_glue::SpellCheckWord() function @@ -808,4 +834,136 @@ TEST_F(SpellCheckTest, SpellCheckParagraphLongSentenceMultipleMisspellings) { TestSpellCheckParagraph(text, expected); } + +// We also skip RequestSpellCheck tests on Mac, because a system spellchecker +// is used on Mac instead of SpellCheck::RequestTextChecking. + +// Make sure RequestTextChecking does not crash if input is empty. +TEST_F(SpellCheckTest, RequestSpellCheckWithEmptyString) { + MockTextCheckingCompletion completion; + + const string16 text = ASCIIToUTF16(""); + spell_check()->RequestTextChecking(text, 0, &completion); + + MessageLoop::current()->RunAllPending(); + + EXPECT_EQ(completion.completion_count_, 1U); +} + +// A simple test case having no misspellings. +TEST_F(SpellCheckTest, RequestSpellCheckWithoutMisspelling) { + MockTextCheckingCompletion completion; + + const string16 text = ASCIIToUTF16("hello"); + spell_check()->RequestTextChecking(text, 0, &completion); + + MessageLoop::current()->RunAllPending(); + + EXPECT_EQ(completion.completion_count_, 1U); +} + +// A simple test case having one misspelling. +TEST_F(SpellCheckTest, RequestSpellCheckWithSingleMisspelling) { + MockTextCheckingCompletion completion; + + const string16 text = ASCIIToUTF16("apple, zz"); + spell_check()->RequestTextChecking(text, 0, &completion); + + MessageLoop::current()->RunAllPending(); + + EXPECT_EQ(completion.completion_count_, 1U); + EXPECT_EQ(completion.last_results_.size(), 1U); + EXPECT_EQ(completion.last_results_[0].location, 7); + EXPECT_EQ(completion.last_results_[0].length, 2); +} + +// A simple test case having a few misspellings. +TEST_F(SpellCheckTest, RequestSpellCheckWithMisspellings) { + MockTextCheckingCompletion completion; + + const string16 text = ASCIIToUTF16("apple, zz, orange, zz"); + spell_check()->RequestTextChecking(text, 0, &completion); + + MessageLoop::current()->RunAllPending(); + + EXPECT_EQ(completion.completion_count_, 1U); + EXPECT_EQ(completion.last_results_.size(), 2U); + EXPECT_EQ(completion.last_results_[0].location, 7); + EXPECT_EQ(completion.last_results_[0].length, 2); + EXPECT_EQ(completion.last_results_[1].location, 19); + EXPECT_EQ(completion.last_results_[1].length, 2); +} + +// A test case that multiple requests comes at once. Make sure all +// requests are processed. +TEST_F(SpellCheckTest, RequestSpellCheckWithMultipleRequests) { + MockTextCheckingCompletion completion[3]; + + const string16 text[3] = { + ASCIIToUTF16("what, zz"), + ASCIIToUTF16("apple, zz"), + ASCIIToUTF16("orange, zz") + }; + + for (int i = 0; i < 3; ++i) + spell_check()->RequestTextChecking(text[i], 0, &completion[i]); + + MessageLoop::current()->RunAllPending(); + + for (int i = 0; i < 3; ++i) { + EXPECT_EQ(completion[i].completion_count_, 1U); + EXPECT_EQ(completion[i].last_results_.size(), 1U); + EXPECT_EQ(completion[i].last_results_[0].location, 6 + i); + EXPECT_EQ(completion[i].last_results_[0].length, 2); + } +} + +// A test case that spellchecking is requested before initializing. +// In this case, we postpone to post a request. +TEST_F(SpellCheckTest, RequestSpellCheckWithoutInitialization) { + UninitializeSpellCheck(); + + MockTextCheckingCompletion completion; + const string16 text = ASCIIToUTF16("zz"); + + spell_check()->RequestTextChecking(text, 0, &completion); + + // The task will not be posted yet. + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(completion.completion_count_, 0U); +} + +// Requests several spellchecking before initializing. Except the last one, +// posting requests is cancelled and text is rendered as correct one. +TEST_F(SpellCheckTest, RequestSpellCheckMultipleTimesWithoutInitialization) { + UninitializeSpellCheck(); + + MockTextCheckingCompletion completion[3]; + const string16 text[3] = { + ASCIIToUTF16("what, zz"), + ASCIIToUTF16("apple, zz"), + ASCIIToUTF16("orange, zz") + }; + + // Calls RequestTextchecking a few times. + for (int i = 0; i < 3; ++i) + spell_check()->RequestTextChecking(text[i], 0, &completion[i]); + + // The last task will be posted after initialization, however the other + // requests should be pressed without spellchecking. + MessageLoop::current()->RunAllPending(); + for (int i = 0; i < 2; ++i) + EXPECT_EQ(completion[i].completion_count_, 1U); + EXPECT_EQ(completion[2].completion_count_, 0U); + + // Checks the last request is processed after initialization. + InitializeSpellCheck("en-US"); + + // Calls PostDelayedSpellCheckTask instead of OnInit here for simplicity. + spell_check()->PostDelayedSpellCheckTask(); + MessageLoop::current()->RunAllPending(); + for (int i = 0; i < 3; ++i) + EXPECT_EQ(completion[i].completion_count_, 1U); +} + #endif |