| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/android/contextualsearch/contextual_search_delegate.h" | 5 #include "chrome/browser/android/contextualsearch/contextual_search_delegate.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> |
| 9 #include <memory> | 10 #include <memory> |
| 11 #include <string> |
| 10 | 12 |
| 11 #include "base/base64.h" | 13 #include "base/base64.h" |
| 14 #include "base/command_line.h" |
| 12 #include "base/macros.h" | 15 #include "base/macros.h" |
| 13 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
| 14 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
| 15 #include "base/strings/utf_string_conversions.h" | 18 #include "base/strings/utf_string_conversions.h" |
| 16 #include "base/values.h" | 19 #include "base/values.h" |
| 17 #include "chrome/browser/android/contextualsearch/contextual_search_context.h" | 20 #include "chrome/browser/android/contextualsearch/contextual_search_context.h" |
| 18 #include "chrome/browser/android/contextualsearch/resolved_search_term.h" | 21 #include "chrome/browser/android/contextualsearch/resolved_search_term.h" |
| 19 #include "chrome/browser/android/proto/client_discourse_context.pb.h" | 22 #include "chrome/browser/android/proto/client_discourse_context.pb.h" |
| 23 #include "chrome/common/chrome_switches.h" |
| 20 #include "components/search_engines/template_url_service.h" | 24 #include "components/search_engines/template_url_service.h" |
| 21 #include "net/base/escape.h" | 25 #include "net/base/escape.h" |
| 22 #include "net/url_request/test_url_fetcher_factory.h" | 26 #include "net/url_request/test_url_fetcher_factory.h" |
| 23 #include "net/url_request/url_request_test_util.h" | 27 #include "net/url_request/url_request_test_util.h" |
| 24 #include "testing/gtest/include/gtest/gtest.h" | 28 #include "testing/gtest/include/gtest/gtest.h" |
| 25 | 29 |
| 26 using base::ListValue; | 30 using base::ListValue; |
| 27 | 31 |
| 28 namespace { | 32 namespace { |
| 29 | 33 |
| 30 const char kSomeSpecificBasePage[] = "http://some.specific.host.name.com/"; | 34 const char kSomeSpecificBasePage[] = "http://some.specific.host.name.com/"; |
| 31 const char kDiscourseContextHeaderName[] = "X-Additional-Discourse-Context"; | 35 const char kDiscourseContextHeaderName[] = "X-Additional-Discourse-Context"; |
| 32 | 36 |
| 33 } // namespace | 37 } // namespace |
| 34 | 38 |
| 35 class ContextualSearchDelegateTest : public testing::Test { | 39 class ContextualSearchDelegateTest : public testing::Test { |
| 36 public: | 40 public: |
| 37 ContextualSearchDelegateTest() {} | 41 ContextualSearchDelegateTest() {} |
| 38 ~ContextualSearchDelegateTest() override {} | 42 ~ContextualSearchDelegateTest() override {} |
| 39 | 43 |
| 40 protected: | 44 protected: |
| 41 void SetUp() override { | 45 void SetUp() override { |
| 46 base::CommandLine::ForCurrentProcess()->AppendSwitch( |
| 47 switches::kEnableContextualSearchNowOnTapBarIntegration); |
| 42 request_context_ = | 48 request_context_ = |
| 43 new net::TestURLRequestContextGetter(io_message_loop_.task_runner()); | 49 new net::TestURLRequestContextGetter(io_message_loop_.task_runner()); |
| 44 template_url_service_.reset(CreateTemplateURLService()); | 50 template_url_service_.reset(CreateTemplateURLService()); |
| 45 delegate_.reset(new ContextualSearchDelegate( | 51 delegate_.reset(new ContextualSearchDelegate( |
| 46 request_context_.get(), template_url_service_.get(), | 52 request_context_.get(), template_url_service_.get(), |
| 47 base::Bind( | 53 base::Bind( |
| 48 &ContextualSearchDelegateTest::recordSearchTermResolutionResponse, | 54 &ContextualSearchDelegateTest::recordSearchTermResolutionResponse, |
| 49 base::Unretained(this)), | 55 base::Unretained(this)), |
| 50 base::Bind(&ContextualSearchDelegateTest::recordSurroundingText, | 56 base::Bind(&ContextualSearchDelegateTest::recordSurroundingText, |
| 51 base::Unretained(this)), | 57 base::Unretained(this)), |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 test_context_->start_offset = start_offset; | 100 test_context_->start_offset = start_offset; |
| 95 test_context_->end_offset = end_offset; | 101 test_context_->end_offset = end_offset; |
| 96 test_context_->surrounding_text = surrounding_text; | 102 test_context_->surrounding_text = surrounding_text; |
| 97 delegate_->ContinueSearchTermResolutionRequest(); | 103 delegate_->ContinueSearchTermResolutionRequest(); |
| 98 fetcher_ = test_factory_.GetFetcherByID( | 104 fetcher_ = test_factory_.GetFetcherByID( |
| 99 ContextualSearchDelegate::kContextualSearchURLFetcherID); | 105 ContextualSearchDelegate::kContextualSearchURLFetcherID); |
| 100 ASSERT_TRUE(fetcher_); | 106 ASSERT_TRUE(fetcher_); |
| 101 ASSERT_TRUE(fetcher()); | 107 ASSERT_TRUE(fetcher()); |
| 102 } | 108 } |
| 103 | 109 |
| 110 // Allows using the vertical bar "|" as a quote character, which makes |
| 111 // test cases more readable versus the escaped double quote that is otherwise |
| 112 // needed for JSON literals. |
| 113 std::string escapeBarQuoted(std::string bar_quoted) { |
| 114 std::replace(bar_quoted.begin(), bar_quoted.end(), '|', '\"'); |
| 115 return bar_quoted; |
| 116 } |
| 117 |
| 118 void CreateDefaultSearchWithContextualCardsData( |
| 119 const std::string contextual_cards_data) { |
| 120 CreateDefaultSearchContextAndRequestSearchTerm(); |
| 121 fetcher()->set_response_code(200); |
| 122 std::string response = |
| 123 escapeBarQuoted("{|search_term|:|obama|" + contextual_cards_data + "}"); |
| 124 fetcher()->SetResponseString(response); |
| 125 fetcher()->delegate()->OnURLFetchComplete(fetcher()); |
| 126 |
| 127 EXPECT_FALSE(is_invalid()); |
| 128 EXPECT_EQ(200, response_code()); |
| 129 EXPECT_EQ("obama", search_term()); |
| 130 } |
| 131 |
| 132 void CreateDefaultSearchWithContextualCardsValue( |
| 133 const std::string contextual_cards_value) { |
| 134 CreateDefaultSearchWithContextualCardsData(", |contextual_cards|:" + |
| 135 contextual_cards_value); |
| 136 } |
| 137 |
| 104 void SetResponseStringAndFetch(const std::string& selected_text, | 138 void SetResponseStringAndFetch(const std::string& selected_text, |
| 105 const std::string& mentions_start, | 139 const std::string& mentions_start, |
| 106 const std::string& mentions_end) { | 140 const std::string& mentions_end) { |
| 107 fetcher()->set_response_code(200); | 141 fetcher()->set_response_code(200); |
| 108 fetcher()->SetResponseString( | 142 fetcher()->SetResponseString( |
| 109 ")]}'\n" | 143 ")]}'\n" |
| 110 "{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\"," | 144 "{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\"," |
| 111 "\"info_text\":\"44th U.S. President\"," | 145 "\"info_text\":\"44th U.S. President\"," |
| 112 "\"display_text\":\"Barack Obama\"," | 146 "\"display_text\":\"Barack Obama\"," |
| 113 "\"mentions\":[" + mentions_start + ","+ mentions_end + "]," | 147 "\"mentions\":[" + mentions_start + ","+ mentions_end + "]," |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 return result; | 199 return result; |
| 166 } | 200 } |
| 167 | 201 |
| 168 net::TestURLFetcher* fetcher() { return fetcher_; } | 202 net::TestURLFetcher* fetcher() { return fetcher_; } |
| 169 bool is_invalid() { return is_invalid_; } | 203 bool is_invalid() { return is_invalid_; } |
| 170 int response_code() { return response_code_; } | 204 int response_code() { return response_code_; } |
| 171 std::string search_term() { return search_term_; } | 205 std::string search_term() { return search_term_; } |
| 172 std::string display_text() { return display_text_; } | 206 std::string display_text() { return display_text_; } |
| 173 std::string alternate_term() { return alternate_term_; } | 207 std::string alternate_term() { return alternate_term_; } |
| 174 std::string mid() { return mid_; } | 208 std::string mid() { return mid_; } |
| 209 std::string caption() { return caption_; } |
| 210 std::string thumbnail_url() { return thumbnail_url_; } |
| 175 bool do_prevent_preload() { return prevent_preload_; } | 211 bool do_prevent_preload() { return prevent_preload_; } |
| 176 std::string after_text() { return after_text_; } | 212 std::string after_text() { return after_text_; } |
| 177 int start_adjust() { return start_adjust_; } | 213 int start_adjust() { return start_adjust_; } |
| 178 int end_adjust() { return end_adjust_; } | 214 int end_adjust() { return end_adjust_; } |
| 179 std::string context_language() { return context_language_; } | 215 std::string context_language() { return context_language_; } |
| 180 | 216 |
| 181 // The delegate under test. | 217 // The delegate under test. |
| 182 std::unique_ptr<ContextualSearchDelegate> delegate_; | 218 std::unique_ptr<ContextualSearchDelegate> delegate_; |
| 183 | 219 |
| 184 private: | 220 private: |
| 185 void recordSearchTermResolutionResponse( | 221 void recordSearchTermResolutionResponse( |
| 186 const ResolvedSearchTerm& resolved_search_term) { | 222 const ResolvedSearchTerm& resolved_search_term) { |
| 187 is_invalid_ = resolved_search_term.is_invalid; | 223 is_invalid_ = resolved_search_term.is_invalid; |
| 188 response_code_ = resolved_search_term.response_code; | 224 response_code_ = resolved_search_term.response_code; |
| 189 search_term_ = resolved_search_term.search_term; | 225 search_term_ = resolved_search_term.search_term; |
| 190 display_text_ = resolved_search_term.display_text; | 226 display_text_ = resolved_search_term.display_text; |
| 191 alternate_term_ = resolved_search_term.alternate_term; | 227 alternate_term_ = resolved_search_term.alternate_term; |
| 192 mid_ = resolved_search_term.mid; | 228 mid_ = resolved_search_term.mid; |
| 229 thumbnail_url_ = resolved_search_term.thumbnail_url; |
| 230 caption_ = resolved_search_term.caption; |
| 193 prevent_preload_ = resolved_search_term.prevent_preload; | 231 prevent_preload_ = resolved_search_term.prevent_preload; |
| 194 start_adjust_ = resolved_search_term.selection_start_adjust; | 232 start_adjust_ = resolved_search_term.selection_start_adjust; |
| 195 end_adjust_ = resolved_search_term.selection_end_adjust; | 233 end_adjust_ = resolved_search_term.selection_end_adjust; |
| 196 context_language_ = resolved_search_term.context_language; | 234 context_language_ = resolved_search_term.context_language; |
| 197 } | 235 } |
| 198 | 236 |
| 199 void recordSurroundingText(const std::string& after_text) { | 237 void recordSurroundingText(const std::string& after_text) { |
| 200 after_text_ = after_text; | 238 after_text_ = after_text; |
| 201 } | 239 } |
| 202 | 240 |
| 203 void recordIcingSelectionAvailable(const std::string& encoding, | 241 void recordIcingSelectionAvailable(const std::string& encoding, |
| 204 const base::string16& surrounding_text, | 242 const base::string16& surrounding_text, |
| 205 size_t start_offset, | 243 size_t start_offset, |
| 206 size_t end_offset) { | 244 size_t end_offset) { |
| 207 // unused. | 245 // unused. |
| 208 } | 246 } |
| 209 | 247 |
| 210 bool is_invalid_; | 248 bool is_invalid_; |
| 211 int response_code_; | 249 int response_code_; |
| 212 std::string search_term_; | 250 std::string search_term_; |
| 213 std::string display_text_; | 251 std::string display_text_; |
| 214 std::string alternate_term_; | 252 std::string alternate_term_; |
| 215 std::string mid_; | 253 std::string mid_; |
| 254 std::string thumbnail_url_; |
| 255 std::string caption_; |
| 216 bool prevent_preload_; | 256 bool prevent_preload_; |
| 217 int start_adjust_; | 257 int start_adjust_; |
| 218 int end_adjust_; | 258 int end_adjust_; |
| 219 std::string after_text_; | 259 std::string after_text_; |
| 220 std::string context_language_; | 260 std::string context_language_; |
| 221 | 261 |
| 222 base::MessageLoopForIO io_message_loop_; | 262 base::MessageLoopForIO io_message_loop_; |
| 223 net::TestURLFetcherFactory test_factory_; | 263 net::TestURLFetcherFactory test_factory_; |
| 224 net::TestURLFetcher* fetcher_; | 264 net::TestURLFetcher* fetcher_; |
| 225 std::unique_ptr<TemplateURLService> template_url_service_; | 265 std::unique_ptr<TemplateURLService> template_url_service_; |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 536 EXPECT_EQ("obama", display_text()); | 576 EXPECT_EQ("obama", display_text()); |
| 537 EXPECT_EQ("/m/02mjmr", mid()); | 577 EXPECT_EQ("/m/02mjmr", mid()); |
| 538 EXPECT_TRUE(do_prevent_preload()); | 578 EXPECT_TRUE(do_prevent_preload()); |
| 539 EXPECT_EQ("de", context_language()); | 579 EXPECT_EQ("de", context_language()); |
| 540 } | 580 } |
| 541 | 581 |
| 542 TEST_F(ContextualSearchDelegateTest, HeaderContainsBasePageUrl) { | 582 TEST_F(ContextualSearchDelegateTest, HeaderContainsBasePageUrl) { |
| 543 CreateDefaultSearchContextAndRequestSearchTerm(); | 583 CreateDefaultSearchContextAndRequestSearchTerm(); |
| 544 EXPECT_EQ(kSomeSpecificBasePage, getBasePageUrlFromRequest()); | 584 EXPECT_EQ(kSomeSpecificBasePage, getBasePageUrlFromRequest()); |
| 545 } | 585 } |
| 586 |
| 587 // Tests a response with a single card from Contextual Cards. |
| 588 TEST_F(ContextualSearchDelegateTest, |
| 589 ContextualCardsResponseSingleCardBarQuotedTest) { |
| 590 CreateDefaultSearchWithContextualCardsValue( |
| 591 "{|cards|:[{|singleCard|:{|subtitle|: |president|," |
| 592 "|thumbnail|:{|uri|:|https://t0.gstatic.com/images?q=tbn:ANd9|}}}]}"); |
| 593 EXPECT_EQ("president", caption()); |
| 594 EXPECT_EQ("https://t0.gstatic.com/images?q=tbn:ANd9", thumbnail_url()); |
| 595 } |
| 596 |
| 597 // Missing all Contextual Cards data. |
| 598 TEST_F(ContextualSearchDelegateTest, ContextualCardsResponseWithNoData) { |
| 599 CreateDefaultSearchWithContextualCardsData(""); |
| 600 EXPECT_EQ("", caption()); |
| 601 EXPECT_EQ("", thumbnail_url()); |
| 602 } |
| 603 |
| 604 // Missing subtitle (for caption). |
| 605 TEST_F(ContextualSearchDelegateTest, |
| 606 ContextualCardsResponseWithMissingCaption) { |
| 607 CreateDefaultSearchWithContextualCardsValue( |
| 608 "{|cards|:[{|singleCard|:{|stubtitlemisspelled|: |president|," |
| 609 "|thumbnail|:{|uri|:|https://t0.gstatic.com/images?q=tbn:ANd9|}}}]}"); |
| 610 EXPECT_EQ("", caption()); |
| 611 EXPECT_EQ("https://t0.gstatic.com/images?q=tbn:ANd9", thumbnail_url()); |
| 612 } |
| 613 |
| 614 // Missing the Thumbnail URI. |
| 615 TEST_F(ContextualSearchDelegateTest, |
| 616 ContextualCardsResponseWithMissingThumbnailUri) { |
| 617 CreateDefaultSearchWithContextualCardsValue( |
| 618 "{|cards|:[{|singleCard|:{|subtitle|: |president|," |
| 619 "|thumbnail|:{}}}]}"); |
| 620 EXPECT_EQ("president", caption()); |
| 621 EXPECT_EQ("", thumbnail_url()); |
| 622 } |
| 623 |
| 624 // Missing the whole Thumbnail. |
| 625 TEST_F(ContextualSearchDelegateTest, |
| 626 ContextualCardsResponseWithMissingThumbnail) { |
| 627 CreateDefaultSearchWithContextualCardsValue( |
| 628 "{|cards|:[{|singleCard|:{|subtitle|: |president|," |
| 629 "|ignored key|:|ignored value|}}]}"); |
| 630 EXPECT_EQ("president", caption()); |
| 631 EXPECT_EQ("", thumbnail_url()); |
| 632 } |
| 633 |
| 634 // Empty cards list. |
| 635 TEST_F(ContextualSearchDelegateTest, |
| 636 ContextualCardsResponseWithMissingSingleCard) { |
| 637 CreateDefaultSearchWithContextualCardsValue("{|cards|:[]}"); |
| 638 EXPECT_EQ("", caption()); |
| 639 EXPECT_EQ("", thumbnail_url()); |
| 640 } |
| 641 |
| 642 // Tests carouselCard followed by singleCard. |
| 643 TEST_F(ContextualSearchDelegateTest, |
| 644 ContextualCardsResponseWithSingleAndCarouselCards) { |
| 645 CreateDefaultSearchWithContextualCardsValue( |
| 646 "{|cards|:[{|carouselCard|:{}},{|singleCard|:{|subtitle|: |president|," |
| 647 "|thumbnail|:{|uri|:|https://t0.gstatic.com/images?q=tbn:ANd9|}}}]}"); |
| 648 EXPECT_EQ("president", caption()); |
| 649 EXPECT_EQ("https://t0.gstatic.com/images?q=tbn:ANd9", thumbnail_url()); |
| 650 } |
| 651 |
| 652 // Missing cards. |
| 653 TEST_F(ContextualSearchDelegateTest, ContextualCardsResponseWithMissingCards) { |
| 654 CreateDefaultSearchWithContextualCardsValue("{}"); |
| 655 EXPECT_EQ("", caption()); |
| 656 EXPECT_EQ("", thumbnail_url()); |
| 657 } |
| 658 |
| 659 // Multiple cards (latter should be ignored). |
| 660 TEST_F(ContextualSearchDelegateTest, ContextualCardsResponseWithMultipleCards) { |
| 661 CreateDefaultSearchWithContextualCardsValue( |
| 662 "{|cards|:[{|singleCard|:{|subtitle|: |president|," |
| 663 "|thumbnail|:{|uri|:|https://t0.gstatic.com/images?q=tbn:ANd9|}}}," |
| 664 "{|singleCard|:{|subtitle|:|wrong subtitle|," |
| 665 "|thumbnail|:{|uri|:|https://t0.gstatic.com/wrongThumbnail|}}}]}"); |
| 666 EXPECT_EQ("president", caption()); |
| 667 EXPECT_EQ("https://t0.gstatic.com/images?q=tbn:ANd9", thumbnail_url()); |
| 668 } |
| OLD | NEW |