blob: 0312474a5cc747ab807e3c8134af9df0e987bea1 [file] [log] [blame]
mattreynolds5afc01692016-08-19 22:09:561// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/omnibox/browser/physical_web_provider.h"
6
7#include <memory>
8#include <string>
9
10#include "base/memory/ptr_util.h"
11#include "base/strings/string_number_conversions.h"
12#include "base/strings/utf_string_conversions.h"
13#include "base/values.h"
14#include "components/metrics/proto/omnibox_event.pb.h"
15#include "components/omnibox/browser/mock_autocomplete_provider_client.h"
16#include "components/omnibox/browser/test_scheme_classifier.h"
17#include "components/physical_web/data_source/physical_web_data_source.h"
18#include "grit/components_strings.h"
19#include "testing/gmock/include/gmock/gmock.h"
20#include "testing/gtest/include/gtest/gtest.h"
21#include "ui/base/l10n/l10n_util.h"
22#include "url/gurl.h"
23
24namespace {
25
26// A mock implementation of the Physical Web data source that allows setting
27// metadata for nearby URLs directly.
28class MockPhysicalWebDataSource : public PhysicalWebDataSource {
29 public:
30 MockPhysicalWebDataSource() : metadata_(new base::ListValue()) {}
31 ~MockPhysicalWebDataSource() override {}
32
33 void StartDiscovery(bool network_request_enabled) override {}
34 void StopDiscovery() override {}
35
36 std::unique_ptr<base::ListValue> GetMetadata() override {
37 return metadata_->CreateDeepCopy();
38 }
39
40 bool HasUnresolvedDiscoveries() override {
41 return false;
42 }
43
44 // for testing
45 void SetMetadata(std::unique_ptr<base::ListValue> metadata) {
46 metadata_ = std::move(metadata);
47 }
48
49 private:
50 std::unique_ptr<base::ListValue> metadata_;
51};
52
53// An autocomplete provider client that embeds the mock Physical Web data
54// source.
55class FakeAutocompleteProviderClient
56 : public testing::NiceMock<MockAutocompleteProviderClient> {
57 public:
58 FakeAutocompleteProviderClient()
59 : physical_web_data_source_(base::MakeUnique<MockPhysicalWebDataSource>())
60 {
61 }
62
63 const AutocompleteSchemeClassifier& GetSchemeClassifier() const override {
64 return scheme_classifier_;
65 }
66
67 PhysicalWebDataSource* GetPhysicalWebDataSource() override {
68 return physical_web_data_source_.get();
69 }
70
71 // Convenience method to avoid downcasts when accessing the mock data source.
72 MockPhysicalWebDataSource* GetMockPhysicalWebDataSource() {
73 return physical_web_data_source_.get();
74 }
75
76 private:
77 std::unique_ptr<MockPhysicalWebDataSource> physical_web_data_source_;
78 TestSchemeClassifier scheme_classifier_;
79};
80
81class PhysicalWebProviderTest : public testing::Test {
82 protected:
83 PhysicalWebProviderTest() : provider_(NULL) {}
84 ~PhysicalWebProviderTest() override {}
85
86 void SetUp() override {
87 client_.reset(new FakeAutocompleteProviderClient());
88 provider_ = PhysicalWebProvider::Create(client_.get());
89 }
90
91 void TearDown() override {
92 provider_ = NULL;
93 }
94
95 // Create a dummy metadata list with |metadata_count| items. Each item is
96 // populated with a unique scanned URL and page metadata.
97 static std::unique_ptr<base::ListValue> CreateMetadata(
98 size_t metadata_count) {
99 auto metadata_list = base::MakeUnique<base::ListValue>();
100 for (size_t i = 0; i < metadata_count; ++i) {
101 std::string item_id = base::SizeTToString(i);
102 std::string url = "https://example.com/" + item_id;
103 auto metadata_item = base::MakeUnique<base::DictionaryValue>();
104 metadata_item->SetString("scannedUrl", url);
105 metadata_item->SetString("resolvedUrl", url);
106 metadata_item->SetString("icon", url);
107 metadata_item->SetString("title", "Example title " + item_id);
108 metadata_item->SetString("description", "Example description " + item_id);
109 metadata_list->Append(std::move(metadata_item));
110 }
111 return metadata_list;
112 }
113
114 std::unique_ptr<FakeAutocompleteProviderClient> client_;
115 scoped_refptr<PhysicalWebProvider> provider_;
116
117 private:
118 DISALLOW_COPY_AND_ASSIGN(PhysicalWebProviderTest);
119};
120
121TEST_F(PhysicalWebProviderTest, TestEmptyMetadataListCreatesNoMatches) {
122 MockPhysicalWebDataSource* data_source =
123 client_->GetMockPhysicalWebDataSource();
124 EXPECT_TRUE(data_source);
125
126 data_source->SetMetadata(CreateMetadata(0));
127
128 // Construct an AutocompleteInput representing a typical "zero-suggest"
129 // case. The provider will verify that the content of the omnibox input field
130 // was not entered by the user.
131 std::string url("http://www.cnn.com/");
132 const AutocompleteInput input(base::ASCIIToUTF16(url), base::string16::npos,
133 std::string(), GURL(url), metrics::OmniboxEventProto::OTHER,
134 true, false, true, true, true, TestSchemeClassifier());
135 provider_->Start(input, false);
136
137 EXPECT_TRUE(provider_->matches().empty());
138}
139
140TEST_F(PhysicalWebProviderTest, TestSingleMetadataItemCreatesOneMatch) {
141 MockPhysicalWebDataSource* data_source =
142 client_->GetMockPhysicalWebDataSource();
143 EXPECT_TRUE(data_source);
144
145 // Extract the URL and title before inserting the metadata into the data
146 // source.
147 std::unique_ptr<base::ListValue> metadata_list = CreateMetadata(1);
148 base::DictionaryValue* metadata_item;
149 EXPECT_TRUE(metadata_list->GetDictionary(0, &metadata_item));
150 std::string resolved_url;
151 EXPECT_TRUE(metadata_item->GetString("resolvedUrl", &resolved_url));
152 std::string title;
153 EXPECT_TRUE(metadata_item->GetString("title", &title));
154
155 data_source->SetMetadata(std::move(metadata_list));
156
157 // Construct an AutocompleteInput representing a typical "zero-suggest"
158 // case. The provider will verify that the content of the omnibox input field
159 // was not entered by the user.
160 std::string url("http://www.cnn.com/");
161 const AutocompleteInput input(base::ASCIIToUTF16(url), base::string16::npos,
162 std::string(), GURL(url), metrics::OmniboxEventProto::OTHER,
163 true, false, true, true, true, TestSchemeClassifier());
164 provider_->Start(input, false);
165
166 // Check that there is only one match item and its fields are correct.
167 EXPECT_EQ(1U, provider_->matches().size());
168 const AutocompleteMatch& metadata_match = provider_->matches().front();
169 EXPECT_EQ(AutocompleteMatchType::PHYSICAL_WEB, metadata_match.type);
170 EXPECT_EQ(resolved_url, metadata_match.destination_url.spec());
171 EXPECT_EQ(resolved_url, base::UTF16ToASCII(metadata_match.contents));
172 EXPECT_EQ(title, base::UTF16ToASCII(metadata_match.description));
173}
174
175TEST_F(PhysicalWebProviderTest, TestManyMetadataItemsCreatesOverflowItem) {
176 // This test is intended to verify that an overflow item is created when the
177 // number of nearby Physical Web URLs exceeds the maximum allowable matches
178 // for this provider. The actual limit for the PhysicalWebProvider may be
179 // changed in the future, so create enough metadata to exceed the
180 // AutocompleteProvider's limit.
181 const size_t metadata_count = AutocompleteProvider::kMaxMatches + 1;
182
183 MockPhysicalWebDataSource* data_source =
184 client_->GetMockPhysicalWebDataSource();
185 EXPECT_TRUE(data_source);
186
187 data_source->SetMetadata(CreateMetadata(metadata_count));
188
189 // Construct an AutocompleteInput representing a typical "zero-suggest"
190 // case. The provider will verify that the content of the omnibox input field
191 // was not entered by the user.
192 std::string url("http://www.cnn.com/");
193 const AutocompleteInput input(base::ASCIIToUTF16(url), base::string16::npos,
194 std::string(), GURL(url), metrics::OmniboxEventProto::OTHER,
195 true, false, true, true, true, TestSchemeClassifier());
196 provider_->Start(input, false);
197
198 const size_t match_count = provider_->matches().size();
199 EXPECT_LT(match_count, metadata_count);
200
201 // Check that the overflow item is at the end of the match list and its fields
202 // are correct.
203 const AutocompleteMatch& overflow_match = provider_->matches().back();
204 EXPECT_EQ(AutocompleteMatchType::PHYSICAL_WEB_OVERFLOW, overflow_match.type);
205 EXPECT_EQ("chrome://physical-web/", overflow_match.destination_url.spec());
206 EXPECT_EQ("chrome://physical-web/",
207 base::UTF16ToASCII(overflow_match.contents));
208 std::string description = l10n_util::GetPluralStringFUTF8(
209 IDS_PHYSICAL_WEB_OVERFLOW, metadata_count - match_count + 1);
210 EXPECT_EQ(description, base::UTF16ToASCII(overflow_match.description));
211}
212
213TEST_F(PhysicalWebProviderTest, TestNoMatchesWithUserInput) {
214 MockPhysicalWebDataSource* data_source =
215 client_->GetMockPhysicalWebDataSource();
216 EXPECT_TRUE(data_source);
217
218 data_source->SetMetadata(CreateMetadata(1));
219
220 // Construct an AutocompleteInput to simulate user input in the omnibox input
221 // field. The provider should not generate any matches.
222 std::string text("user input");
223 const AutocompleteInput input(base::ASCIIToUTF16(text), text.length(),
224 std::string(), GURL(),
225 metrics::OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS,
226 true, false, true, true, false, TestSchemeClassifier());
227 provider_->Start(input, false);
228
229 EXPECT_TRUE(provider_->matches().empty());
230}
231
232}