blob: b405d9860952dfb5b82c54361acfa44aab55b092 [file] [log] [blame]
// Copyright 2015 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/android/contextualsearch/contextual_search_delegate.h"
#include <stddef.h>
#include <algorithm>
#include <memory>
#include <string>
#include "base/base64.h"
#include "base/command_line.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/android/contextualsearch/contextual_search_context.h"
#include "chrome/browser/android/contextualsearch/resolved_search_term.h"
#include "chrome/browser/android/proto/client_discourse_context.pb.h"
#include "chrome/common/chrome_switches.h"
#include "components/search_engines/template_url_service.h"
#include "net/base/escape.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::ListValue;
namespace {
const char kSomeSpecificBasePage[] = "http://some.specific.host.name.com/";
const char kDiscourseContextHeaderName[] = "X-Additional-Discourse-Context";
} // namespace
class ContextualSearchDelegateTest : public testing::Test {
public:
ContextualSearchDelegateTest() {}
~ContextualSearchDelegateTest() override {}
protected:
void SetUp() override {
test_shared_url_loader_factory_ =
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_);
template_url_service_.reset(CreateTemplateURLService());
delegate_.reset(new ContextualSearchDelegate(
test_shared_url_loader_factory_, template_url_service_.get(),
base::Bind(
&ContextualSearchDelegateTest::recordSearchTermResolutionResponse,
base::Unretained(this)),
base::Bind(
&ContextualSearchDelegateTest::recordSampleSelectionAvailable,
base::Unretained(this))));
}
void TearDown() override {
is_invalid_ = true;
response_code_ = -1;
search_term_ = "invalid";
mid_ = "";
display_text_ = "unknown";
context_language_ = "";
}
TemplateURLService* CreateTemplateURLService() {
// Set a default search provider that supports Contextual Search.
TemplateURLData data;
data.SetURL("https://foobar.com/url?bar={searchTerms}");
data.contextual_search_url = "https://foobar.com/_/contextualsearch?"
"{google:contextualSearchVersion}{google:contextualSearchContextData}";
TemplateURLService* template_url_service = new TemplateURLService(NULL, 0);
TemplateURL* template_url =
template_url_service->Add(std::make_unique<TemplateURL>(data));
template_url_service->SetUserSelectedDefaultSearchProvider(template_url);
return template_url_service;
}
void CreateDefaultSearchContextAndRequestSearchTerm() {
base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
CreateSearchContextAndRequestSearchTerm("Barack Obama", surrounding, 0, 6);
}
void CreateSearchContextAndRequestSearchTerm(
const std::string& selected_text,
const base::string16& surrounding_text,
int start_offset,
int end_offset) {
test_context_ = new ContextualSearchContext(
std::string(), GURL(kSomeSpecificBasePage), "utf-8");
// ContextualSearchDelegate class takes ownership of the context.
delegate_->SetContextForTesting(test_context_->GetWeakPtr());
test_context_->SetSelectionSurroundings(start_offset, end_offset,
surrounding_text);
delegate_->ResolveSearchTermFromContext();
ASSERT_TRUE(test_url_loader_factory_.GetPendingRequest(0));
}
// Allows using the vertical bar "|" as a quote character, which makes
// test cases more readable versus the escaped double quote that is otherwise
// needed for JSON literals.
std::string escapeBarQuoted(std::string bar_quoted) {
std::replace(bar_quoted.begin(), bar_quoted.end(), '|', '\"');
return bar_quoted;
}
void CreateDefaultSearchWithAdditionalJsonData(
const std::string additional_json_data) {
CreateDefaultSearchContextAndRequestSearchTerm();
std::string response =
escapeBarQuoted("{|search_term|:|obama|" + additional_json_data + "}");
SimulateResponseReturned(response);
EXPECT_FALSE(is_invalid());
EXPECT_EQ(200, response_code());
EXPECT_EQ("obama", search_term());
}
//-------------------------------------------------------------------
// Helper methods that call private ContextualSearchDelegate methods.
// The ContextualSearchDelegate methods cannot be called directly
// from tests, but can be called here because this is a friend class.
//-------------------------------------------------------------------
void CreateTestContext() {
test_context_ = new ContextualSearchContext(
std::string(), GURL(kSomeSpecificBasePage), "utf-8");
delegate_->SetContextForTesting(test_context_->GetWeakPtr());
}
void DestroyTestContext() { delete test_context_; }
// Call the OnTextSurroundingSelectionAvailable.
// Cannot be in an actual test because OnTextSurroundingSelectionAvailable
// is private.
void CallOnTextSurroundingSelectionAvailable() {
delegate_->OnTextSurroundingSelectionAvailable(base::string16(), 1, 2);
}
void CallResolveSearchTermFromContext() {
delegate_->ResolveSearchTermFromContext();
}
void SetResponseStringAndSimulateResponse(const std::string& selected_text,
const std::string& mentions_start,
const std::string& mentions_end) {
std::string response = std::string(
")]}'\n"
"{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\","
"\"info_text\":\"44th U.S. President\","
"\"display_text\":\"Barack Obama\","
"\"mentions\":[" + mentions_start + "," + mentions_end + "],"
"\"selected_text\":\"" + selected_text + "\","
"\"resolved_term\":\"barack obama\"}");
SimulateResponseReturned(response);
}
void SimulateResponseReturned(const std::string& response) {
auto* pending_request = test_url_loader_factory_.GetPendingRequest(0);
test_url_loader_factory_.SimulateResponseForPendingRequest(
pending_request->request.url.spec(), response);
base::RunLoop().RunUntilIdle();
}
void SetSurroundingContext(const base::string16& surrounding_text,
int start_offset,
int end_offset) {
test_context_ = new ContextualSearchContext(
std::string(), GURL(kSomeSpecificBasePage), "utf-8");
test_context_->SetSelectionSurroundings(start_offset, end_offset,
surrounding_text);
// ContextualSearchDelegate class takes ownership of the context.
delegate_->SetContextForTesting(test_context_->GetWeakPtr());
}
// Gets the Client Discourse Context proto from the request header.
discourse_context::ClientDiscourseContext GetDiscourseContextFromRequest() {
discourse_context::ClientDiscourseContext cdc;
// Make sure we can get the actual raw headers from the url loader.
auto* pending_request = test_url_loader_factory_.GetPendingRequest(0);
net::HttpRequestHeaders request_headers = pending_request->request.headers;
if (request_headers.HasHeader(kDiscourseContextHeaderName)) {
std::string actual_header_value;
request_headers.GetHeader(kDiscourseContextHeaderName,
&actual_header_value);
// Unescape, since the server memoizer expects a web-safe encoding.
std::string unescaped_header = actual_header_value;
std::replace(unescaped_header.begin(), unescaped_header.end(), '-', '+');
std::replace(unescaped_header.begin(), unescaped_header.end(), '_', '/');
// Base64 decode the header.
std::string decoded_header;
if (base::Base64Decode(unescaped_header, &decoded_header)) {
cdc.ParseFromString(decoded_header);
}
}
return cdc;
}
// Gets the base-page URL from the request, or an empty string if not present.
std::string getBasePageUrlFromRequest() {
std::string result;
discourse_context::ClientDiscourseContext cdc =
GetDiscourseContextFromRequest();
if (cdc.display_size() > 0) {
const discourse_context::Display& first_display = cdc.display(0);
result = first_display.uri();
}
return result;
}
bool is_invalid() { return is_invalid_; }
int response_code() { return response_code_; }
std::string search_term() { return search_term_; }
std::string display_text() { return display_text_; }
std::string alternate_term() { return alternate_term_; }
std::string mid() { return mid_; }
std::string caption() { return caption_; }
std::string thumbnail_url() { return thumbnail_url_; }
bool do_prevent_preload() { return prevent_preload_; }
int start_adjust() { return start_adjust_; }
int end_adjust() { return end_adjust_; }
std::string context_language() { return context_language_; }
// The delegate under test.
std::unique_ptr<ContextualSearchDelegate> delegate_;
network::TestURLLoaderFactory test_url_loader_factory_;
private:
void recordSearchTermResolutionResponse(
const ResolvedSearchTerm& resolved_search_term) {
is_invalid_ = resolved_search_term.is_invalid;
response_code_ = resolved_search_term.response_code;
search_term_ = resolved_search_term.search_term;
display_text_ = resolved_search_term.display_text;
alternate_term_ = resolved_search_term.alternate_term;
mid_ = resolved_search_term.mid;
thumbnail_url_ = resolved_search_term.thumbnail_url;
caption_ = resolved_search_term.caption;
prevent_preload_ = resolved_search_term.prevent_preload;
start_adjust_ = resolved_search_term.selection_start_adjust;
end_adjust_ = resolved_search_term.selection_end_adjust;
context_language_ = resolved_search_term.context_language;
}
void recordSampleSelectionAvailable(const std::string& encoding,
const base::string16& surrounding_text,
size_t start_offset,
size_t end_offset) {
// unused.
}
bool is_invalid_;
int response_code_;
std::string search_term_;
std::string display_text_;
std::string alternate_term_;
std::string mid_;
std::string thumbnail_url_;
std::string caption_;
bool prevent_preload_;
int start_adjust_;
int end_adjust_;
std::string context_language_;
base::MessageLoopForIO io_message_loop_;
std::unique_ptr<TemplateURLService> template_url_service_;
scoped_refptr<network::SharedURLLoaderFactory>
test_shared_url_loader_factory_;
// Will be owned by the delegate.
ContextualSearchContext* test_context_;
DISALLOW_COPY_AND_ASSIGN(ContextualSearchDelegateTest);
};
TEST_F(ContextualSearchDelegateTest, NormalFetchWithXssiEscape) {
CreateDefaultSearchContextAndRequestSearchTerm();
std::string response(
")]}'\n"
"{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\","
"\"info_text\":\"44th U.S. President\","
"\"display_text\":\"Barack Obama\", \"mentions\":[0,15],"
"\"selected_text\":\"obama\", \"resolved_term\":\"barack obama\"}");
SimulateResponseReturned(response);
EXPECT_FALSE(is_invalid());
EXPECT_EQ(200, response_code());
EXPECT_EQ("obama", search_term());
EXPECT_EQ("Barack Obama", display_text());
EXPECT_EQ("/m/02mjmr", mid());
EXPECT_FALSE(do_prevent_preload());
}
TEST_F(ContextualSearchDelegateTest, NormalFetchWithoutXssiEscape) {
CreateDefaultSearchContextAndRequestSearchTerm();
std::string response(
"{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\","
"\"info_text\":\"44th U.S. President\","
"\"display_text\":\"Barack Obama\", \"mentions\":[0,15],"
"\"selected_text\":\"obama\", \"resolved_term\":\"barack obama\"}");
SimulateResponseReturned(response);
EXPECT_FALSE(is_invalid());
EXPECT_EQ(200, response_code());
EXPECT_EQ("obama", search_term());
EXPECT_EQ("Barack Obama", display_text());
EXPECT_EQ("/m/02mjmr", mid());
EXPECT_FALSE(do_prevent_preload());
}
TEST_F(ContextualSearchDelegateTest, ResponseWithNoDisplayText) {
CreateDefaultSearchContextAndRequestSearchTerm();
std::string response(
"{\"mid\":\"/m/02mjmr\",\"search_term\":\"obama\","
"\"mentions\":[0,15]}");
SimulateResponseReturned(response);
EXPECT_FALSE(is_invalid());
EXPECT_EQ(200, response_code());
EXPECT_EQ("obama", search_term());
EXPECT_EQ("obama", display_text());
EXPECT_EQ("/m/02mjmr", mid());
EXPECT_FALSE(do_prevent_preload());
}
TEST_F(ContextualSearchDelegateTest, ResponseWithPreventPreload) {
CreateDefaultSearchContextAndRequestSearchTerm();
std::string response(
"{\"mid\":\"/m/02mjmr\",\"search_term\":\"obama\","
"\"mentions\":[0,15],\"prevent_preload\":\"1\"}");
SimulateResponseReturned(response);
EXPECT_FALSE(is_invalid());
EXPECT_EQ(200, response_code());
EXPECT_EQ("obama", search_term());
EXPECT_EQ("obama", display_text());
EXPECT_EQ("/m/02mjmr", mid());
EXPECT_TRUE(do_prevent_preload());
}
TEST_F(ContextualSearchDelegateTest, NonJsonResponse) {
CreateDefaultSearchContextAndRequestSearchTerm();
std::string response("Non-JSON Response");
SimulateResponseReturned(response);
EXPECT_FALSE(is_invalid());
EXPECT_EQ(200, response_code());
EXPECT_EQ("", search_term());
EXPECT_EQ("", display_text());
EXPECT_EQ("", mid());
EXPECT_FALSE(do_prevent_preload());
}
TEST_F(ContextualSearchDelegateTest, InvalidResponse) {
CreateDefaultSearchContextAndRequestSearchTerm();
auto* pending_request = test_url_loader_factory_.GetPendingRequest(0);
test_url_loader_factory_.SimulateResponseForPendingRequest(
pending_request->request.url, network::URLLoaderCompletionStatus(net::OK),
network::ResourceResponseHead(), std::string());
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(do_prevent_preload());
EXPECT_TRUE(is_invalid());
}
TEST_F(ContextualSearchDelegateTest, ExpandSelectionToEnd) {
base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
std::string selected_text = "Barack";
CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0, 6);
SetResponseStringAndSimulateResponse(selected_text, "0", "12");
EXPECT_EQ(0, start_adjust());
EXPECT_EQ(6, end_adjust());
}
TEST_F(ContextualSearchDelegateTest, ExpandSelectionToStart) {
base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
std::string selected_text = "Obama";
CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 7, 12);
SetResponseStringAndSimulateResponse(selected_text, "0", "12");
EXPECT_EQ(-7, start_adjust());
EXPECT_EQ(0, end_adjust());
}
TEST_F(ContextualSearchDelegateTest, ExpandSelectionBothDirections) {
base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
std::string selected_text = "Ob";
CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 7, 9);
SetResponseStringAndSimulateResponse(selected_text, "0", "12");
EXPECT_EQ(-7, start_adjust());
EXPECT_EQ(3, end_adjust());
}
TEST_F(ContextualSearchDelegateTest, ExpandSelectionInvalidRange) {
base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
std::string selected_text = "Ob";
CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 7, 9);
SetResponseStringAndSimulateResponse(selected_text, "0", "200");
EXPECT_EQ(0, start_adjust());
EXPECT_EQ(0, end_adjust());
}
TEST_F(ContextualSearchDelegateTest, ExpandSelectionInvalidDistantStart) {
base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
std::string selected_text = "Ob";
CreateSearchContextAndRequestSearchTerm(selected_text, surrounding,
0xffffffff, 0xffffffff - 2);
SetResponseStringAndSimulateResponse(selected_text, "0", "12");
EXPECT_EQ(0, start_adjust());
EXPECT_EQ(0, end_adjust());
}
TEST_F(ContextualSearchDelegateTest, ExpandSelectionInvalidNoOverlap) {
base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
std::string selected_text = "Ob";
CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0, 12);
SetResponseStringAndSimulateResponse(selected_text, "12", "14");
EXPECT_EQ(0, start_adjust());
EXPECT_EQ(0, end_adjust());
}
TEST_F(ContextualSearchDelegateTest, ExpandSelectionInvalidDistantEndAndRange) {
base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
std::string selected_text = "Ob";
CreateSearchContextAndRequestSearchTerm(selected_text, surrounding,
0xffffffff, 0xffffffff - 2);
SetResponseStringAndSimulateResponse(selected_text, "0", "268435455");
EXPECT_EQ(0, start_adjust());
EXPECT_EQ(0, end_adjust());
}
TEST_F(ContextualSearchDelegateTest, ExpandSelectionLargeNumbers) {
base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
std::string selected_text = "Ob";
CreateSearchContextAndRequestSearchTerm(selected_text, surrounding,
268435450, 268435455);
SetResponseStringAndSimulateResponse(selected_text, "268435440", "268435455");
EXPECT_EQ(-10, start_adjust());
EXPECT_EQ(0, end_adjust());
}
TEST_F(ContextualSearchDelegateTest, ContractSelectionValid) {
base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
std::string selected_text = "Barack Obama just";
CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0, 17);
SetResponseStringAndSimulateResponse(selected_text, "0", "12");
EXPECT_EQ(0, start_adjust());
EXPECT_EQ(-5, end_adjust());
}
TEST_F(ContextualSearchDelegateTest, ContractSelectionInvalid) {
base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
std::string selected_text = "Barack Obama just";
CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0, 17);
SetResponseStringAndSimulateResponse(selected_text, "5", "5");
EXPECT_EQ(0, start_adjust());
EXPECT_EQ(0, end_adjust());
}
TEST_F(ContextualSearchDelegateTest, ExtractMentionsStartEnd) {
ListValue mentions_list;
mentions_list.AppendInteger(1);
mentions_list.AppendInteger(2);
int start = 0;
int end = 0;
delegate_->ExtractMentionsStartEnd(mentions_list, &start, &end);
EXPECT_EQ(1, start);
EXPECT_EQ(2, end);
}
TEST_F(ContextualSearchDelegateTest, SampleSurroundingText) {
base::string16 sample = base::ASCIIToUTF16("this is Barack Obama in office.");
int limit_each_side = 3;
size_t start = 8;
size_t end = 20;
base::string16 result =
delegate_->SampleSurroundingText(sample, limit_each_side, &start, &end);
EXPECT_EQ(static_cast<size_t>(3), start);
EXPECT_EQ(static_cast<size_t>(15), end);
EXPECT_EQ(base::ASCIIToUTF16("is Barack Obama in"), result);
}
TEST_F(ContextualSearchDelegateTest, SampleSurroundingTextNegativeLimit) {
base::string16 sample = base::ASCIIToUTF16("this is Barack Obama in office.");
int limit_each_side = -2;
size_t start = 8;
size_t end = 20;
base::string16 result =
delegate_->SampleSurroundingText(sample, limit_each_side, &start, &end);
EXPECT_EQ(static_cast<size_t>(0), start);
EXPECT_EQ(static_cast<size_t>(12), end);
EXPECT_EQ(base::ASCIIToUTF16("Barack Obama"), result);
}
TEST_F(ContextualSearchDelegateTest, SampleSurroundingTextSameStartEnd) {
base::string16 sample = base::ASCIIToUTF16("this is Barack Obama in office.");
int limit_each_side = 3;
size_t start = 11;
size_t end = 11;
base::string16 result =
delegate_->SampleSurroundingText(sample, limit_each_side, &start, &end);
VLOG(0) << "start " << start;
VLOG(0) << "end " << end;
VLOG(0) << "result " << result;
EXPECT_EQ(static_cast<size_t>(3), start);
EXPECT_EQ(static_cast<size_t>(3), end);
EXPECT_EQ(base::ASCIIToUTF16("Barack"), result);
}
TEST_F(ContextualSearchDelegateTest, DecodeSearchTermFromJsonResponse) {
std::string json_with_escape =
")]}'\n"
"{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\","
"\"info_text\":\"44th U.S. President\","
"\"display_text\":\"Barack Obama\", \"mentions\":[0,15],"
"\"selected_text\":\"obama\", \"resolved_term\":\"barack obama\"}";
std::string search_term;
std::string display_text;
std::string alternate_term;
std::string mid;
std::string prevent_preload;
int mention_start;
int mention_end;
std::string context_language;
std::string thumbnail_url;
std::string caption;
std::string quick_action_uri;
QuickActionCategory quick_action_category = QUICK_ACTION_CATEGORY_NONE;
delegate_->DecodeSearchTermFromJsonResponse(
json_with_escape, &search_term, &display_text, &alternate_term,
&mid, &prevent_preload, &mention_start, &mention_end, &context_language,
&thumbnail_url, &caption, &quick_action_uri, &quick_action_category);
EXPECT_EQ("obama", search_term);
EXPECT_EQ("Barack Obama", display_text);
EXPECT_EQ("barack obama", alternate_term);
EXPECT_EQ("/m/02mjmr", mid);
EXPECT_EQ("", prevent_preload);
EXPECT_EQ("", context_language);
EXPECT_EQ("", thumbnail_url);
EXPECT_EQ("", caption);
EXPECT_EQ("", quick_action_uri);
EXPECT_EQ(QUICK_ACTION_CATEGORY_NONE, quick_action_category);
}
TEST_F(ContextualSearchDelegateTest, ResponseWithLanguage) {
CreateDefaultSearchContextAndRequestSearchTerm();
std::string response(
"{\"mid\":\"/m/02mjmr\",\"search_term\":\"obama\","
"\"mentions\":[0,15],\"prevent_preload\":\"1\", "
"\"lang\":\"de\"}");
SimulateResponseReturned(response);
EXPECT_FALSE(is_invalid());
EXPECT_EQ(200, response_code());
EXPECT_EQ("obama", search_term());
EXPECT_EQ("obama", display_text());
EXPECT_EQ("/m/02mjmr", mid());
EXPECT_TRUE(do_prevent_preload());
EXPECT_EQ("de", context_language());
}
TEST_F(ContextualSearchDelegateTest, HeaderContainsBasePageUrl) {
CreateDefaultSearchContextAndRequestSearchTerm();
EXPECT_EQ(kSomeSpecificBasePage, getBasePageUrlFromRequest());
}
// Missing all Contextual Cards data.
TEST_F(ContextualSearchDelegateTest, ContextualCardsResponseWithNoData) {
CreateDefaultSearchWithAdditionalJsonData("");
EXPECT_EQ("", caption());
EXPECT_EQ("", thumbnail_url());
}
// Test just the root level caption.
TEST_F(ContextualSearchDelegateTest, ContextualCardsResponseWithCaption) {
CreateDefaultSearchWithAdditionalJsonData(", |caption|:|aCaption|");
EXPECT_EQ("aCaption", caption());
EXPECT_EQ("", thumbnail_url());
}
// Test just the root level thumbnail.
TEST_F(ContextualSearchDelegateTest, ContextualCardsResponseWithThumbnail) {
CreateDefaultSearchWithAdditionalJsonData(
", |thumbnail|:|https://t0.gstatic.com/images?q=tbn:ANd9|");
EXPECT_EQ("", caption());
EXPECT_EQ("https://t0.gstatic.com/images?q=tbn:ANd9", thumbnail_url());
}
// Test that we can destroy the context while resolving without a crash.
TEST_F(ContextualSearchDelegateTest, DestroyContextDuringResolve) {
CreateTestContext();
CallResolveSearchTermFromContext();
DestroyTestContext();
std::string response("Any response as it does not matter here.");
SimulateResponseReturned(response);
EXPECT_TRUE(is_invalid());
}
// Test that we can destroy the context while gathering surrounding text.
TEST_F(ContextualSearchDelegateTest, DestroyContextDuringGatherSurroundings) {
CreateTestContext();
DestroyTestContext();
CallOnTextSurroundingSelectionAvailable();
}