Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / webui / ntp / suggestions_combiner_unittest.cc
blobf74b81fcba6342ade108af8647fbf5fb874d7980
1 // Copyright (c) 2012 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.
5 // TODO(beaudoin): What is really needed here?
7 #include <deque>
8 #include <string>
10 #include "base/memory/scoped_ptr.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_util.h"
13 #include "base/values.h"
14 #include "chrome/browser/ui/webui/ntp/suggestions_combiner.h"
15 #include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h"
16 #include "chrome/browser/ui/webui/ntp/suggestions_source.h"
17 #include "chrome/test/base/testing_profile.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 namespace {
22 struct SourceInfo {
23 int weight;
24 const char* source_name;
25 int number_of_suggestions;
28 struct TestDescription {
29 SourceInfo sources[3];
30 const char* results[8];
31 } test_suite[] = {
32 // One source, more than 8 items.
34 {{1, "A", 10}},
35 {"A 0", "A 1", "A 2", "A 3", "A 4", "A 5", "A 6", "A 7"}
37 // One source, exactly 8 items.
39 {{1, "A", 8}},
40 {"A 0", "A 1", "A 2", "A 3", "A 4", "A 5", "A 6", "A 7"}
42 // One source, not enough items.
44 {{1, "A", 3}},
45 {"A 0", "A 1", "A 2"}
47 // One source, no items.
49 {{1, "A", 0}},
52 // Two sources, equal weight, more than 8 items.
54 {{1, "A", 10}, {1, "B", 10}},
55 {"A 0", "A 1", "A 2", "A 3", "B 0", "B 1", "B 2", "B 3"}
57 // Two sources, equal weight, exactly 8 items.
59 {{1, "A", 4}, {1, "B", 4}},
60 {"A 0", "A 1", "A 2", "A 3", "B 0", "B 1", "B 2", "B 3"}
62 // Two sources, equal weight, exactly 8 items but source A has more.
64 {{1, "A", 5}, {1, "B", 3}},
65 {"A 0", "A 1", "A 2", "A 3", "A 4", "B 0", "B 1", "B 2"}
67 // Two sources, equal weight, exactly 8 items but source B has more.
69 {{1, "A", 2}, {1, "B", 6}},
70 {"A 0", "A 1", "B 0", "B 1", "B 2", "B 3", "B 4", "B 5"}
72 // Two sources, equal weight, exactly 8 items but source A has none.
74 {{1, "A", 0}, {1, "B", 8}},
75 {"B 0", "B 1", "B 2", "B 3", "B 4", "B 5", "B 6", "B 7"}
77 // Two sources, equal weight, exactly 8 items but source B has none.
79 {{1, "A", 8}, {1, "B", 0}},
80 {"A 0", "A 1", "A 2", "A 3", "A 4", "A 5", "A 6", "A 7"}
82 // Two sources, equal weight, less than 8 items.
84 {{1, "A", 3}, {1, "B", 3}},
85 {"A 0", "A 1", "A 2", "B 0", "B 1", "B 2"}
87 // Two sources, equal weight, less than 8 items but source A has more.
89 {{1, "A", 4}, {1, "B", 3}},
90 {"A 0", "A 1", "A 2", "A 3", "B 0", "B 1", "B 2"}
92 // Two sources, equal weight, less than 8 items but source B has more.
94 {{1, "A", 1}, {1, "B", 3}},
95 {"A 0", "B 0", "B 1", "B 2"}
97 // Two sources, weights 3/4 A 1/4 B, more than 8 items.
99 {{3, "A", 10}, {1, "B", 10}},
100 {"A 0", "A 1", "A 2", "A 3", "A 4", "A 5", "B 0", "B 1"}
102 // Two sources, weights 1/8 A 7/8 B, more than 8 items.
104 {{1, "A", 10}, {7, "B", 10}},
105 {"A 0", "B 0", "B 1", "B 2", "B 3", "B 4", "B 5", "B 6"}
107 // Two sources, weights 1/3 A 2/3 B, more than 8 items.
109 {{1, "A", 10}, {2, "B", 10}},
110 {"A 0", "A 1", "B 0", "B 1", "B 2", "B 3", "B 4", "B 5"}
112 // Three sources, weights 1/2 A 1/4 B 1/4 C, more than 8 items.
114 {{2, "A", 10}, {1, "B", 10}, {1, "C", 10}},
115 {"A 0", "A 1", "A 2", "A 3", "B 0", "B 1", "C 0", "C 1"}
117 // Three sources, weights 1/3 A 1/3 B 1/3 C, more than 8 items.
119 {{1, "A", 10}, {1, "B", 10}, {1, "C", 10}},
120 {"A 0", "A 1", "B 0", "B 1", "B 2", "C 0", "C 1", "C 2"}
122 // Extra items should be grouped together.
124 {{1, "A", 3}, {1, "B", 4}, {10, "C", 1}},
125 {"A 0", "A 1", "A 2", "B 0", "B 1", "B 2", "B 3", "C 0"}
129 } // namespace
131 // Stub for a SuggestionsSource that can provide a number of fake suggestions.
132 // Fake suggestions are DictionaryValue with a single "title" string field
133 // containing the |source_name| followed by the index of the suggestion.
134 // Not in the empty namespace since it's a friend of SuggestionsCombiner.
135 class SuggestionsSourceStub : public SuggestionsSource {
136 public:
137 explicit SuggestionsSourceStub(int weight,
138 const std::string& source_name, int number_of_suggestions)
139 : combiner_(NULL),
140 weight_(weight),
141 source_name_(source_name),
142 number_of_suggestions_(number_of_suggestions),
143 debug_(false) {
145 virtual ~SuggestionsSourceStub() {
146 STLDeleteElements(&items_);
149 // Call this method to simulate that the SuggestionsSource has received all
150 // its suggestions.
151 void Done() {
152 combiner_->OnItemsReady();
155 private:
156 // SuggestionsSource Override and implementation.
157 virtual void SetDebug(bool enable) OVERRIDE {
158 debug_ = enable;
160 virtual int GetWeight() OVERRIDE {
161 return weight_;
163 virtual int GetItemCount() OVERRIDE {
164 return items_.size();
166 virtual base::DictionaryValue* PopItem() OVERRIDE {
167 if (items_.empty())
168 return NULL;
169 base::DictionaryValue* item = items_.front();
170 items_.pop_front();
171 return item;
174 virtual void FetchItems(Profile* profile) OVERRIDE {
175 char num_str[21]; // Enough to hold all numbers up to 64-bits.
176 for (int i = 0; i < number_of_suggestions_; ++i) {
177 base::snprintf(num_str, sizeof(num_str), "%d", i);
178 AddSuggestion(source_name_ + ' ' + num_str);
182 // Adds a fake suggestion. This suggestion is a DictionaryValue with a single
183 // "title" field containing |title|.
184 void AddSuggestion(const std::string& title) {
185 base::DictionaryValue* item = new base::DictionaryValue();
186 item->SetString("title", title);
187 items_.push_back(item);
190 virtual void SetCombiner(SuggestionsCombiner* combiner) OVERRIDE {
191 DCHECK(!combiner_);
192 combiner_ = combiner;
195 // Our combiner.
196 SuggestionsCombiner* combiner_;
198 int weight_;
199 std::string source_name_;
200 int number_of_suggestions_;
201 bool debug_;
203 // Keep the results of the db query here.
204 std::deque<base::DictionaryValue*> items_;
206 DISALLOW_COPY_AND_ASSIGN(SuggestionsSourceStub);
209 class SuggestionsCombinerTest : public testing::Test {
210 public:
211 SuggestionsCombinerTest() {
214 protected:
215 Profile* profile_;
216 SuggestionsHandler* suggestions_handler_;
217 SuggestionsCombiner* combiner_;
219 void Reset() {
220 delete combiner_;
221 combiner_ = new SuggestionsCombiner(suggestions_handler_, profile_);
224 private:
225 virtual void SetUp() {
226 profile_ = new TestingProfile();
227 suggestions_handler_ = new SuggestionsHandler();
228 combiner_ = new SuggestionsCombiner(suggestions_handler_, profile_);
231 virtual void TearDown() {
232 delete combiner_;
233 delete suggestions_handler_;
234 delete profile_;
237 DISALLOW_COPY_AND_ASSIGN(SuggestionsCombinerTest);
240 TEST_F(SuggestionsCombinerTest, NoSource) {
241 combiner_->FetchItems(NULL);
242 EXPECT_EQ(0UL, combiner_->GetPageValues()->GetSize());
245 TEST_F(SuggestionsCombinerTest, SourcesAreNotDoneFetching) {
246 combiner_->AddSource(new SuggestionsSourceStub(1, "sourceA", 10));
247 combiner_->AddSource(new SuggestionsSourceStub(1, "sourceB", 10));
248 combiner_->FetchItems(NULL);
249 EXPECT_EQ(0UL, combiner_->GetPageValues()->GetSize());
252 TEST_F(SuggestionsCombinerTest, TestSuite) {
253 size_t test_count = arraysize(test_suite);
254 for (size_t i = 0; i < test_count; ++i) {
255 const TestDescription& description = test_suite[i];
256 size_t source_count = arraysize(description.sources);
258 scoped_ptr<SuggestionsSourceStub*[]> sources(
259 new SuggestionsSourceStub*[source_count]);
261 // Setup sources.
262 for (size_t j = 0; j < source_count; ++j) {
263 const SourceInfo& source_info = description.sources[j];
264 // A NULL |source_name| means we shouldn't add this source.
265 if (source_info.source_name) {
266 sources[j] = new SuggestionsSourceStub(source_info.weight,
267 source_info.source_name, source_info.number_of_suggestions);
268 combiner_->AddSource(sources[j]);
269 } else {
270 sources[j] = NULL;
274 // Start fetching.
275 combiner_->FetchItems(NULL);
277 // Sources complete.
278 for (size_t j = 0; j < source_count; ++j) {
279 if (sources[j])
280 sources[j]->Done();
283 // Verify expectations.
284 base::ListValue* results = combiner_->GetPageValues();
285 size_t result_count = results->GetSize();
286 EXPECT_LE(result_count, 8UL);
287 for (size_t j = 0; j < 8; ++j) {
288 if (j < result_count) {
289 std::string value;
290 base::DictionaryValue* dictionary;
291 results->GetDictionary(j, &dictionary);
292 dictionary->GetString("title", &value);
293 EXPECT_STREQ(description.results[j], value.c_str()) <<
294 " test index:" << i;
295 } else {
296 EXPECT_EQ(description.results[j], static_cast<const char*>(NULL)) <<
297 " test index:" << i;
301 Reset();