Index: chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc |
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f375d217a5e5bfd9c9b25fb6466c6e7203acccb6 |
--- /dev/null |
+++ b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc |
@@ -0,0 +1,329 @@ |
+// Copyright 2013 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 "chrome/browser/ui/app_list/search/app_search_provider.h" |
+ |
+#include <stddef.h> |
+ |
+#include <memory> |
+#include <string> |
+#include <utility> |
+ |
+#include "base/macros.h" |
+#include "base/metrics/field_trial.h" |
+#include "base/metrics/field_trial_params.h" |
+#include "base/strings/utf_string_conversions.h" |
+#include "base/test/scoped_feature_list.h" |
+#include "chrome/browser/ui/app_list/app_list_test_util.h" |
+#include "chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.h" |
+#include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h" |
+#include "chrome/test/base/testing_profile.h" |
+#include "content/test/mock_navigation_handle.h" |
+#include "net/http/http_response_headers.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "ui/app_list/app_list_features.h" |
+#include "ui/app_list/app_list_model.h" |
+#include "ui/app_list/search_result.h" |
+ |
+using ::testing::_; |
+using ::testing::Return; |
+using ::testing::ReturnRef; |
+ |
+namespace app_list { |
+namespace test { |
+ |
+namespace { |
+ |
+views::View* const kView = reinterpret_cast<views::View*>(123456); |
xiyuan
2017/06/22 16:43:21
Can we create a real views::View owned by AnswerCa
vadimt
2017/06/22 19:48:03
Done.
|
+constexpr char kCatCardId[] = "http://meow.org/meow"; |
+constexpr char kCatCardTitle[] = "Cat is a furry beast."; |
+ |
+class MockAnswerCardContents : public AnswerCardContents { |
+ public: |
+ MockAnswerCardContents() {} |
+ |
+ // AnswerCardContents overrides: |
+ MOCK_METHOD1(LoadURL, void(const GURL& url)); |
+ MOCK_CONST_METHOD0(IsLoading, bool()); |
+ MOCK_METHOD0(GetView, views::View*()); |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(MockAnswerCardContents); |
+}; |
+ |
+gfx::Size GetMaxValidCardSize() { |
+ return gfx::Size(features::AnswerCardMaxWidth(), |
+ features::AnswerCardMaxHeight()); |
+} |
+ |
+} // namespace |
+ |
+class AnswerCardSearchProviderTest : public AppListTestBase { |
+ public: |
+ AnswerCardSearchProviderTest() : field_trial_list_(nullptr) {} |
+ |
+ void SetMockHeaders(std::string has_result, |
+ std::string open_url, |
+ std::string title) { |
+ headers_->RemoveHeader("SearchAnswer-HasResult"); |
+ headers_->RemoveHeader("SearchAnswer-OpenResultUrl"); |
+ headers_->RemoveHeader("SearchAnswer-Title"); |
+ |
+ if (!has_result.empty()) |
+ headers_->AddHeader("SearchAnswer-HasResult: " + has_result); |
+ if (!open_url.empty()) |
+ headers_->AddHeader("SearchAnswer-OpenResultUrl: " + open_url); |
+ if (!title.empty()) |
+ headers_->AddHeader("SearchAnswer-Title: " + title); |
+ } |
+ |
+ void TestHeadersParsing(std::string has_result, |
+ std::string open_url, |
+ std::string title, |
+ std::size_t expected_result_count) { |
+ SetMockHeaders(has_result, open_url, title); |
+ |
+ EXPECT_CALL(*contents(), LoadURL(GURL("http://beasts.org/search?q=cat"))); |
+ provider()->Start(false, base::UTF8ToUTF16("cat")); |
+ |
+ GURL url("http://beasts.org/search?q=cat"); |
+ EXPECT_CALL(*navigation_handle_.get(), GetURL()).WillOnce(ReturnRef(url)); |
+ provider()->DidFinishNavigation(navigation_handle_.get()); |
+ |
+ provider()->DidStopLoading(); |
+ provider()->UpdatePreferredSize(GetMaxValidCardSize()); |
+ |
+ EXPECT_EQ(expected_result_count, results().size()); |
xiyuan
2017/06/22 16:43:21
We might need a
testing::Mock::VerifyAndClearE
vadimt
2017/06/22 19:48:03
Done.
|
+ } |
+ |
+ AppListModel* model() const { return model_.get(); } |
+ |
+ const SearchProvider::Results& results() { return provider()->results(); } |
+ |
+ MockAnswerCardContents* contents() const { return contents_; } |
+ |
+ AnswerCardSearchProvider* provider() const { return provider_.get(); } |
+ |
+ content::MockNavigationHandle* navigation_handle() const { |
+ return navigation_handle_.get(); |
+ } |
+ |
+ // AppListTestBase overrides: |
+ void SetUp() override { |
+ AppListTestBase::SetUp(); |
+ |
+ model_ = base::MakeUnique<app_list::AppListModel>(); |
+ model_->SetSearchEngineIsGoogle(true); |
+ |
+ controller_ = base::MakeUnique<::test::TestAppListControllerDelegate>(); |
+ |
+ // Set up card server URL. |
+ std::map<std::string, std::string> params; |
+ params["ServerUrl"] = "http://beasts.org/search"; |
+ base::AssociateFieldTrialParams("TestTrial", "TestGroup", params); |
+ scoped_refptr<base::FieldTrial> trial = |
+ base::FieldTrialList::CreateFieldTrial("TestTrial", "TestGroup"); |
+ std::unique_ptr<base::FeatureList> feature_list = |
+ base::MakeUnique<base::FeatureList>(); |
+ feature_list->RegisterFieldTrialOverride( |
+ features::kEnableAnswerCard.name, |
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get()); |
+ scoped_feature_list_.InitWithFeatureList(std::move(feature_list)); |
+ |
+ contents_ = new MockAnswerCardContents; |
+ std::unique_ptr<AnswerCardContents> contents(contents_); |
xiyuan
2017/06/22 16:43:22
Would presubmit script complains about using std::
vadimt
2017/06/22 19:48:03
No, presubmit is fine.
|
+ // Provider will own the MockAnswerCardContents instance. |
+ provider_ = base::MakeUnique<AnswerCardSearchProvider>( |
+ profile_.get(), model_.get(), nullptr, std::move(contents)); |
+ |
+ headers_ = new net::HttpResponseHeaders(""); |
+ SetMockHeaders("true", kCatCardId, kCatCardTitle); |
+ |
+ navigation_handle_ = base::MakeUnique<content::MockNavigationHandle>(); |
+ ON_CALL(*navigation_handle_.get(), HasCommitted()) |
+ .WillByDefault(Return(true)); |
+ ON_CALL(*navigation_handle_.get(), IsErrorPage()) |
+ .WillByDefault(Return(false)); |
+ ON_CALL(*navigation_handle_.get(), IsInMainFrame()) |
+ .WillByDefault(Return(true)); |
+ ON_CALL(*navigation_handle_.get(), GetResponseHeaders()) |
+ .WillByDefault(Return(headers_.get())); |
+ |
+ ON_CALL(*contents_, GetView()).WillByDefault(Return(kView)); |
+ } |
+ |
+ private: |
+ std::unique_ptr<app_list::AppListModel> model_; |
+ std::unique_ptr<AnswerCardSearchProvider> provider_; |
+ std::unique_ptr<::test::TestAppListControllerDelegate> controller_; |
+ MockAnswerCardContents* contents_ = nullptr; // Unowned. |
+ base::FieldTrialList field_trial_list_; |
+ base::test::ScopedFeatureList scoped_feature_list_; |
+ scoped_refptr<net::HttpResponseHeaders> headers_; |
+ std::unique_ptr<content::MockNavigationHandle> navigation_handle_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(AnswerCardSearchProviderTest); |
+}; |
+ |
+// Basic event sequence. |
+TEST_F(AnswerCardSearchProviderTest, Basic) { |
+ EXPECT_CALL(*contents(), LoadURL(GURL("http://beasts.org/search?q=cat"))); |
+ provider()->Start(false, base::UTF8ToUTF16("cat")); |
+ GURL url("http://beasts.org/search?q=cat"); |
+ EXPECT_CALL(*navigation_handle(), GetURL()).WillOnce(ReturnRef(url)); |
+ provider()->DidFinishNavigation(navigation_handle()); |
+ provider()->DidStopLoading(); |
+ provider()->UpdatePreferredSize(GetMaxValidCardSize()); |
+ |
+ EXPECT_EQ(1UL, results().size()); |
+ SearchResult* result = results()[0].get(); |
+ EXPECT_EQ(SearchResult::DISPLAY_CARD, result->display_type()); |
+ EXPECT_EQ(kCatCardId, result->id()); |
+ EXPECT_EQ(1, result->relevance()); |
+ EXPECT_EQ(kView, result->view()); |
+ EXPECT_EQ(base::UTF8ToUTF16(kCatCardTitle), result->title()); |
+} |
+ |
+// Voice queries are ignored. |
+TEST_F(AnswerCardSearchProviderTest, VoiceQuery) { |
+ EXPECT_CALL(*contents(), LoadURL(_)).Times(0); |
+ provider()->Start(true, base::UTF8ToUTF16("cat")); |
+} |
+ |
+// Queries to non-Google search engines are ignored. |
+TEST_F(AnswerCardSearchProviderTest, NotGoogle) { |
+ model()->SetSearchEngineIsGoogle(false); |
+ EXPECT_CALL(*contents(), LoadURL(_)).Times(0); |
+ provider()->Start(false, base::UTF8ToUTF16("cat")); |
+} |
+ |
+// Zero-query is ignored. |
+TEST_F(AnswerCardSearchProviderTest, EmptyQuery) { |
+ EXPECT_CALL(*contents(), LoadURL(_)).Times(0); |
+ provider()->Start(false, base::UTF8ToUTF16("")); |
+} |
+ |
+// Two queries, the second produces a card of exactly same size, so |
+// UpdatePreferredSize() doesn't come. The second query should still produce a |
+// result. |
+TEST_F(AnswerCardSearchProviderTest, TwoResultsSameSize) { |
+ EXPECT_CALL(*contents(), LoadURL(GURL("http://beasts.org/search?q=cat"))); |
+ provider()->Start(false, base::UTF8ToUTF16("cat")); |
+ GURL url("http://beasts.org/search?q=cat"); |
+ EXPECT_CALL(*navigation_handle(), GetURL()).WillOnce(ReturnRef(url)); |
+ provider()->DidFinishNavigation(navigation_handle()); |
+ provider()->DidStopLoading(); |
+ provider()->UpdatePreferredSize(GetMaxValidCardSize()); |
+ |
+ EXPECT_EQ(1UL, results().size()); |
+ SearchResult* result = results()[0].get(); |
+ EXPECT_EQ(SearchResult::DISPLAY_CARD, result->display_type()); |
+ EXPECT_EQ(kCatCardId, result->id()); |
+ EXPECT_EQ(1, result->relevance()); |
+ EXPECT_EQ(kView, result->view()); |
+ EXPECT_EQ(base::UTF8ToUTF16(kCatCardTitle), result->title()); |
+ |
+ EXPECT_CALL(*contents(), LoadURL(GURL("http://beasts.org/search?q=dog"))); |
+ provider()->Start(false, base::UTF8ToUTF16("dog")); |
+ EXPECT_EQ(0UL, results().size()); |
+ |
+ url = GURL("http://beasts.org/search?q=dog"); |
+ EXPECT_CALL(*navigation_handle(), GetURL()).WillOnce(ReturnRef(url)); |
+ SetMockHeaders("true", "http://woof.org/woof", "Dog is a friendly beast."); |
+ provider()->DidFinishNavigation(navigation_handle()); |
+ provider()->DidStopLoading(); |
+ // No UpdatePreferredSize(). |
+ |
+ EXPECT_EQ(1UL, results().size()); |
+ result = results()[0].get(); |
+ EXPECT_EQ(SearchResult::DISPLAY_CARD, result->display_type()); |
+ EXPECT_EQ("http://woof.org/woof", result->id()); |
+ EXPECT_EQ(1, result->relevance()); |
+ EXPECT_EQ(kView, result->view()); |
+ EXPECT_EQ(base::UTF8ToUTF16("Dog is a friendly beast."), result->title()); |
+} |
+ |
+// User enters a query character by character, so that each next query generates |
+// a web request while the previous one is still in progress. Only the last |
+// query should produce a result. |
+TEST_F(AnswerCardSearchProviderTest, InterruptedRequest) { |
+ EXPECT_CALL(*contents(), LoadURL(GURL("http://beasts.org/search?q=c"))); |
+ provider()->Start(false, base::UTF8ToUTF16("c")); |
+ EXPECT_EQ(0UL, results().size()); |
+ |
+ EXPECT_CALL(*contents(), LoadURL(GURL("http://beasts.org/search?q=ca"))); |
+ provider()->Start(false, base::UTF8ToUTF16("ca")); |
+ EXPECT_EQ(0UL, results().size()); |
+ |
+ EXPECT_CALL(*contents(), LoadURL(GURL("http://beasts.org/search?q=cat"))); |
+ provider()->Start(false, base::UTF8ToUTF16("cat")); |
+ EXPECT_EQ(0UL, results().size()); |
+ |
+ SetMockHeaders("true", "http://c-meow", "Title c"); |
+ GURL url = GURL("http://beasts.org/search?q=c"); |
+ EXPECT_CALL(*navigation_handle(), GetURL()).WillOnce(ReturnRef(url)); |
+ provider()->DidFinishNavigation(navigation_handle()); |
+ provider()->DidStopLoading(); |
+ EXPECT_EQ(0UL, results().size()); |
+ |
+ SetMockHeaders("true", "http://ca-meow", "Title ca"); |
+ url = GURL("http://beasts.org/search?q=ca"); |
+ EXPECT_CALL(*navigation_handle(), GetURL()).WillOnce(ReturnRef(url)); |
+ provider()->DidFinishNavigation(navigation_handle()); |
+ provider()->DidStopLoading(); |
+ provider()->UpdatePreferredSize(gfx::Size(1, 1)); |
+ EXPECT_EQ(0UL, results().size()); |
+ |
+ SetMockHeaders("true", kCatCardId, kCatCardTitle); |
+ url = GURL("http://beasts.org/search?q=cat"); |
+ EXPECT_CALL(*navigation_handle(), GetURL()).WillOnce(ReturnRef(url)); |
+ provider()->DidFinishNavigation(navigation_handle()); |
+ provider()->DidStopLoading(); |
+ provider()->UpdatePreferredSize(GetMaxValidCardSize()); |
+ EXPECT_EQ(1UL, results().size()); |
+ |
+ SearchResult* result = results()[0].get(); |
+ EXPECT_EQ(SearchResult::DISPLAY_CARD, result->display_type()); |
+ EXPECT_EQ(kCatCardId, result->id()); |
+ EXPECT_EQ(base::UTF8ToUTF16(kCatCardTitle), result->title()); |
+} |
+ |
+// Due to, for example, JS activity in the card, it can change its size after |
+// loading. We should hide the result while its size if larger than the allowed |
+// maximum. |
+TEST_F(AnswerCardSearchProviderTest, ChangingSize) { |
+ EXPECT_CALL(*contents(), LoadURL(GURL("http://beasts.org/search?q=cat"))); |
+ provider()->Start(false, base::UTF8ToUTF16("cat")); |
+ GURL url("http://beasts.org/search?q=cat"); |
+ EXPECT_CALL(*navigation_handle(), GetURL()).WillOnce(ReturnRef(url)); |
+ provider()->DidFinishNavigation(navigation_handle()); |
+ provider()->UpdatePreferredSize(gfx::Size(features::AnswerCardMaxWidth() + 1, |
+ features::AnswerCardMaxHeight())); |
+ provider()->DidStopLoading(); |
+ EXPECT_EQ(0UL, results().size()); |
+ |
+ provider()->UpdatePreferredSize(GetMaxValidCardSize()); |
+ EXPECT_EQ(1UL, results().size()); |
+ |
+ provider()->UpdatePreferredSize(gfx::Size( |
+ features::AnswerCardMaxWidth(), features::AnswerCardMaxHeight() + 1)); |
+ EXPECT_EQ(0UL, results().size()); |
+ |
+ provider()->UpdatePreferredSize(GetMaxValidCardSize()); |
+ EXPECT_EQ(1UL, results().size()); |
+} |
+ |
+// The result is generated only when all headers exist, and indicate presence of |
+// the result. |
+TEST_F(AnswerCardSearchProviderTest, Headers) { |
+ TestHeadersParsing("true", kCatCardId, kCatCardTitle, 1UL); |
+ TestHeadersParsing("false", kCatCardId, kCatCardTitle, 0UL); |
+ TestHeadersParsing("", kCatCardId, kCatCardTitle, 0UL); |
+ TestHeadersParsing("true", "", kCatCardTitle, 0UL); |
+ TestHeadersParsing("true", kCatCardId, "", 0UL); |
+ TestHeadersParsing("true", kCatCardId, kCatCardTitle, 1UL); |
+} |
+ |
+} // namespace test |
+} // namespace app_list |