blob: fb382a7b4ba81ce783593d2d8cc1bac262de5520 [file] [log] [blame]
[email protected]33d22102012-01-25 17:46:531// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]be052212011-12-14 18:40:402// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <string>
6
7#include "base/bind.h"
8#include "base/file_path.h"
9#include "base/logging.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/stl_util.h"
12#include "base/string16.h"
13#include "base/time.h"
14#include "base/values.h"
[email protected]0a2bafc2012-02-01 22:35:0015#include "chrome/browser/download/download_query.h"
[email protected]b7d000b2012-06-02 22:18:2116#include "content/public/test/mock_download_item.h"
[email protected]be052212011-12-14 18:40:4017#include "testing/gmock/include/gmock/gmock.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20using ::testing::Return;
21using ::testing::ReturnRef;
22using ::testing::_;
23using base::Time;
24using base::Value;
[email protected]e582fdd2011-12-20 16:48:1725using content::DownloadItem;
[email protected]be052212011-12-14 18:40:4026typedef DownloadQuery::DownloadVector DownloadVector;
27
28namespace {
29
30bool IdNotEqual(int not_id, const DownloadItem& item) {
31 return item.GetId() != not_id;
32}
33
34bool AlwaysReturn(bool result, const DownloadItem& item) {
35 return result;
36}
37
38} // anonymous namespace
39
40class DownloadQueryTest : public testing::Test {
41 public:
42 DownloadQueryTest() {}
43
44 virtual ~DownloadQueryTest() {}
45
46 virtual void TearDown() {
47 STLDeleteElements(&mocks_);
48 }
49
50 void CreateMocks(int count) {
51 for (int i = 0; i < count; ++i) {
[email protected]75e51b52012-02-04 16:57:5452 mocks_.push_back(new content::MockDownloadItem());
[email protected]be052212011-12-14 18:40:4053 }
54 }
55
[email protected]75e51b52012-02-04 16:57:5456 content::MockDownloadItem& mock(int index) { return *mocks_[index]; }
[email protected]be052212011-12-14 18:40:4057
58 DownloadQuery* query() { return &query_; }
59
60 template<typename ValueType> void AddFilter(
61 DownloadQuery::FilterType name, ValueType value);
62
63 void Search() {
64 query_.Search(mocks_.begin(), mocks_.end(), &results_);
65 }
66
67 DownloadVector* results() { return &results_; }
68
69 private:
[email protected]75e51b52012-02-04 16:57:5470 std::vector<content::MockDownloadItem*> mocks_;
[email protected]be052212011-12-14 18:40:4071 DownloadQuery query_;
72 DownloadVector results_;
73
74 DISALLOW_COPY_AND_ASSIGN(DownloadQueryTest);
75};
76
77template<> void DownloadQueryTest::AddFilter(
78 DownloadQuery::FilterType name, bool cpp_value) {
79 scoped_ptr<base::Value> value(Value::CreateBooleanValue(cpp_value));
80 CHECK(query_.AddFilter(name, *value.get()));
81}
82
83template<> void DownloadQueryTest::AddFilter(
84 DownloadQuery::FilterType name, int cpp_value) {
85 scoped_ptr<base::Value> value(Value::CreateIntegerValue(cpp_value));
86 CHECK(query_.AddFilter(name, *value.get()));
87}
88
89template<> void DownloadQueryTest::AddFilter(
90 DownloadQuery::FilterType name, const char* cpp_value) {
91 scoped_ptr<base::Value> value(Value::CreateStringValue(cpp_value));
92 CHECK(query_.AddFilter(name, *value.get()));
93}
94
95template<> void DownloadQueryTest::AddFilter(
96 DownloadQuery::FilterType name, const char16* cpp_value) {
97 scoped_ptr<base::Value> value(Value::CreateStringValue(string16(cpp_value)));
98 CHECK(query_.AddFilter(name, *value.get()));
99}
100
101TEST_F(DownloadQueryTest, DownloadQueryEmptyNoItems) {
102 Search();
103 EXPECT_EQ(0U, results()->size());
104}
105
106TEST_F(DownloadQueryTest, DownloadQueryEmptySomeItems) {
107 CreateMocks(3);
108 Search();
109 EXPECT_EQ(3U, results()->size());
110}
111
112TEST_F(DownloadQueryTest, DownloadQueryInvalidFilters) {
113 scoped_ptr<base::Value> value(Value::CreateIntegerValue(0));
114 EXPECT_FALSE(query()->AddFilter(
115 static_cast<DownloadQuery::FilterType>(kint32max),
116 *value.get()));
117}
118
119TEST_F(DownloadQueryTest, DownloadQueryLimit) {
120 CreateMocks(2);
121 query()->Limit(1);
122 Search();
123 EXPECT_EQ(1U, results()->size());
124}
125
126// Syntactic sugar for an expression version of the switch-case statement.
127// Cf. Lisp's |case| form.
128#define SWITCH2(_index, _col1, _ret1, _default) \
129 ((_index == (_col1)) ? _ret1 : _default)
130#define SWITCH3(_index, _col1, _ret1, _col2, _ret2, _default) \
131 SWITCH2(_index, _col1, _ret1, SWITCH2(_index, _col2, _ret2, _default))
132#define SWITCH4(_index, _col1, _ret1, _col2, _ret2, _col3, _ret3, _default) \
133 SWITCH3(_index, _col1, _ret1, _col2, _ret2, \
134 SWITCH2(_index, _col3, _ret3, _default))
135
136TEST_F(DownloadQueryTest, DownloadQueryAllFilters) {
137 // Set up mocks such that only mock(0) matches all filters, and every other
138 // mock fails a different filter (or two for GREATER/LESS filters).
139 static const size_t kNumItems = 19;
140 CreateMocks(kNumItems);
141 FilePath refail_filename(FILE_PATH_LITERAL("z"));
142 FilePath fail_filename(FILE_PATH_LITERAL("fail"));
143 FilePath match_filename(FILE_PATH_LITERAL("match"));
144 GURL refail_url("http://z.com/");
145 GURL fail_url("http://example.com/fail");
146 GURL match_url("http://example.com/match");
147 // Picture a 2D matrix. The rows are MockDownloadItems and the columns are
148 // filter types. Every cell contains a value that matches all filters, except
149 // for the diagonal. Every item matches all the filters except one filter,
150 // which it fails, except one item, which matches all the filters without
151 // exception. Each mocked method is used to test (corresponds to) one or more
152 // filter types (columns). For example, GetTotalBytes() is used to test
153 // FILTER_TOTAL_BYTES_GREATER, FILTER_TOTAL_BYTES_LESS, and
154 // FILTER_TOTAL_BYTES, so it uses 3 columns: it returns 1 for row (item) 11,
155 // it returns 4 for row 12, 3 for 13, and it returns 2 for all other rows
156 // (items).
157 for (size_t i = 0; i < kNumItems; ++i) {
158 EXPECT_CALL(mock(i), GetId()).WillRepeatedly(Return(i));
159 EXPECT_CALL(mock(i), GetReceivedBytes()).WillRepeatedly(Return(SWITCH2(i,
160 1, 2,
161 1)));
162 EXPECT_CALL(mock(i), GetSafetyState()).WillRepeatedly(Return(SWITCH2(i,
163 2, DownloadItem::DANGEROUS,
164 DownloadItem::DANGEROUS_BUT_VALIDATED)));
165 EXPECT_CALL(mock(i), GetFullPath()).WillRepeatedly(ReturnRef(SWITCH3(i,
166 3, refail_filename,
167 4, fail_filename,
168 match_filename)));
169 EXPECT_CALL(mock(i), GetMimeType()).WillRepeatedly(Return(SWITCH2(i,
170 5, "image",
171 "text")));
172 EXPECT_CALL(mock(i), IsPaused()).WillRepeatedly(Return(SWITCH2(i,
173 6, false,
174 true)));
175 EXPECT_CALL(mock(i), MatchesQuery(_)).WillRepeatedly(Return(SWITCH2(i,
176 7, false,
177 true)));
178 EXPECT_CALL(mock(i), GetStartTime()).WillRepeatedly(Return(SWITCH4(i,
179 8, base::Time::FromTimeT(1),
180 9, base::Time::FromTimeT(4),
181 10, base::Time::FromTimeT(3),
182 base::Time::FromTimeT(2))));
183 EXPECT_CALL(mock(i), GetTotalBytes()).WillRepeatedly(Return(SWITCH4(i,
184 11, 1,
185 12, 4,
186 13, 3,
187 2)));
188 EXPECT_CALL(mock(i), GetOriginalUrl()).WillRepeatedly(ReturnRef(SWITCH3(i,
189 14, refail_url,
190 15, fail_url,
191 match_url)));
192 EXPECT_CALL(mock(i), GetState()).WillRepeatedly(Return(SWITCH2(i,
193 17, DownloadItem::CANCELLED,
194 DownloadItem::IN_PROGRESS)));
195 EXPECT_CALL(mock(i), GetDangerType()).WillRepeatedly(Return(SWITCH2(i,
[email protected]a62d42902012-01-24 17:24:38196 18, content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
197 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)));
[email protected]be052212011-12-14 18:40:40198 }
199 for (size_t i = 0; i < kNumItems; ++i) {
200 switch (i) {
201 case 0: break;
202 case 1: AddFilter(DownloadQuery::FILTER_BYTES_RECEIVED, 1); break;
203 case 2: AddFilter(DownloadQuery::FILTER_DANGER_ACCEPTED, true);
204 break;
205 case 3: AddFilter(DownloadQuery::FILTER_FILENAME_REGEX, "a"); break;
206 case 4: AddFilter(DownloadQuery::FILTER_FILENAME,
207 match_filename.value().c_str()); break;
208 case 5: AddFilter(DownloadQuery::FILTER_MIME, "text"); break;
209 case 6: AddFilter(DownloadQuery::FILTER_PAUSED, true); break;
210 case 7: AddFilter(DownloadQuery::FILTER_QUERY, ""); break;
211 case 8: AddFilter(DownloadQuery::FILTER_STARTED_AFTER, 1000); break;
212 case 9: AddFilter(DownloadQuery::FILTER_STARTED_BEFORE, 4000);
213 break;
214 case 10: AddFilter(DownloadQuery::FILTER_START_TIME, 2000); break;
215 case 11: AddFilter(DownloadQuery::FILTER_TOTAL_BYTES_GREATER, 1);
216 break;
217 case 12: AddFilter(DownloadQuery::FILTER_TOTAL_BYTES_LESS, 4);
218 break;
219 case 13: AddFilter(DownloadQuery::FILTER_TOTAL_BYTES, 2); break;
220 case 14: AddFilter(DownloadQuery::FILTER_URL_REGEX, "example");
221 break;
222 case 15: AddFilter(DownloadQuery::FILTER_URL,
223 match_url.spec().c_str()); break;
224 case 16: CHECK(query()->AddFilter(base::Bind(&IdNotEqual, 16))); break;
225 case 17: query()->AddFilter(DownloadItem::IN_PROGRESS); break;
[email protected]a62d42902012-01-24 17:24:38226 case 18: query()->AddFilter(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
227 break;
[email protected]be052212011-12-14 18:40:40228 default: NOTREACHED(); break;
229 }
230 Search();
231 ASSERT_EQ(kNumItems - i, results()->size())
232 << "Failing filter: " << i;
233 if (i > 0) {
234 ASSERT_EQ(0, results()->at(0)->GetId())
235 << "Failing filter: " << i;
236 for (size_t j = 1; j < kNumItems - i; ++j) {
237 ASSERT_EQ(static_cast<int32>(j + i), results()->at(j)->GetId())
238 << "Failing filter: " << i;
239 }
240 }
241 }
242}
243
244TEST_F(DownloadQueryTest, DownloadQuerySortBytesReceived) {
245 CreateMocks(2);
246 EXPECT_CALL(mock(0), GetReceivedBytes()).WillRepeatedly(Return(0));
247 EXPECT_CALL(mock(1), GetReceivedBytes()).WillRepeatedly(Return(1));
248 query()->AddSorter(
249 DownloadQuery::SORT_BYTES_RECEIVED, DownloadQuery::DESCENDING);
250 Search();
251 EXPECT_EQ(1, results()->at(0)->GetReceivedBytes());
252 EXPECT_EQ(0, results()->at(1)->GetReceivedBytes());
253}
254
255TEST_F(DownloadQueryTest, DownloadQuerySortDanger) {
256 CreateMocks(2);
257 EXPECT_CALL(mock(0), GetDangerType()).WillRepeatedly(Return(
[email protected]a62d42902012-01-24 17:24:38258 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE));
[email protected]be052212011-12-14 18:40:40259 EXPECT_CALL(mock(1), GetDangerType()).WillRepeatedly(Return(
[email protected]a62d42902012-01-24 17:24:38260 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS));
[email protected]be052212011-12-14 18:40:40261 query()->AddSorter(
262 DownloadQuery::SORT_DANGER, DownloadQuery::ASCENDING);
263 Search();
[email protected]a62d42902012-01-24 17:24:38264 EXPECT_EQ(content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
[email protected]be052212011-12-14 18:40:40265 results()->at(0)->GetDangerType());
[email protected]a62d42902012-01-24 17:24:38266 EXPECT_EQ(content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
[email protected]be052212011-12-14 18:40:40267 results()->at(1)->GetDangerType());
268}
269
270TEST_F(DownloadQueryTest, DownloadQuerySortDangerAccepted) {
271 CreateMocks(2);
272 EXPECT_CALL(mock(0), GetSafetyState()).WillRepeatedly(Return(
273 DownloadItem::DANGEROUS));
274 EXPECT_CALL(mock(1), GetSafetyState()).WillRepeatedly(Return(
275 DownloadItem::DANGEROUS_BUT_VALIDATED));
276 query()->AddSorter(
277 DownloadQuery::SORT_DANGER_ACCEPTED, DownloadQuery::DESCENDING);
278 Search();
279 EXPECT_EQ(DownloadItem::DANGEROUS_BUT_VALIDATED,
280 results()->at(0)->GetSafetyState());
281 EXPECT_EQ(DownloadItem::DANGEROUS, results()->at(1)->GetSafetyState());
282}
283
284TEST_F(DownloadQueryTest, DownloadQuerySortFilename) {
285 CreateMocks(2);
286 FilePath a_filename(FILE_PATH_LITERAL("a"));
287 FilePath b_filename(FILE_PATH_LITERAL("b"));
288 EXPECT_CALL(mock(0), GetFullPath()).WillRepeatedly(ReturnRef(b_filename));
289 EXPECT_CALL(mock(1), GetFullPath()).WillRepeatedly(ReturnRef(a_filename));
290 query()->AddSorter(
291 DownloadQuery::SORT_FILENAME, DownloadQuery::ASCENDING);
292 Search();
293 EXPECT_EQ(a_filename, results()->at(0)->GetFullPath());
294 EXPECT_EQ(b_filename, results()->at(1)->GetFullPath());
295}
296
297TEST_F(DownloadQueryTest, DownloadQuerySortMime) {
298 CreateMocks(2);
299 EXPECT_CALL(mock(0), GetMimeType()).WillRepeatedly(Return("a"));
300 EXPECT_CALL(mock(1), GetMimeType()).WillRepeatedly(Return("b"));
301 query()->AddSorter(
302 DownloadQuery::SORT_MIME, DownloadQuery::DESCENDING);
303 Search();
304 EXPECT_EQ("b", results()->at(0)->GetMimeType());
305 EXPECT_EQ("a", results()->at(1)->GetMimeType());
306}
307
308TEST_F(DownloadQueryTest, DownloadQuerySortPaused) {
309 CreateMocks(2);
310 EXPECT_CALL(mock(0), IsPaused()).WillRepeatedly(Return(true));
311 EXPECT_CALL(mock(1), IsPaused()).WillRepeatedly(Return(false));
312 query()->AddSorter(
313 DownloadQuery::SORT_PAUSED, DownloadQuery::ASCENDING);
314 Search();
[email protected]7610ed72011-12-19 12:28:28315 EXPECT_FALSE(results()->at(0)->IsPaused());
316 EXPECT_TRUE(results()->at(1)->IsPaused());
[email protected]be052212011-12-14 18:40:40317}
318
319TEST_F(DownloadQueryTest, DownloadQuerySortStartTime) {
320 CreateMocks(2);
321 EXPECT_CALL(mock(0), GetStartTime()).WillRepeatedly(Return(
322 base::Time::FromTimeT(0)));
323 EXPECT_CALL(mock(1), GetStartTime()).WillRepeatedly(Return(
324 base::Time::FromTimeT(1)));
325 query()->AddSorter(
326 DownloadQuery::SORT_START_TIME, DownloadQuery::DESCENDING);
327 Search();
328 EXPECT_EQ(base::Time::FromTimeT(1), results()->at(0)->GetStartTime());
329 EXPECT_EQ(base::Time::FromTimeT(0), results()->at(1)->GetStartTime());
330}
331
332TEST_F(DownloadQueryTest, DownloadQuerySortState) {
333 CreateMocks(2);
334 EXPECT_CALL(mock(0), GetState()).WillRepeatedly(Return(
335 DownloadItem::IN_PROGRESS));
336 EXPECT_CALL(mock(1), GetState()).WillRepeatedly(Return(
337 DownloadItem::COMPLETE));
338 query()->AddSorter(
339 DownloadQuery::SORT_STATE, DownloadQuery::ASCENDING);
340 Search();
341 EXPECT_EQ(DownloadItem::IN_PROGRESS, results()->at(0)->GetState());
342 EXPECT_EQ(DownloadItem::COMPLETE, results()->at(1)->GetState());
343}
344
345TEST_F(DownloadQueryTest, DownloadQuerySortTotalBytes) {
346 CreateMocks(2);
347 EXPECT_CALL(mock(0), GetTotalBytes()).WillRepeatedly(Return(0));
348 EXPECT_CALL(mock(1), GetTotalBytes()).WillRepeatedly(Return(1));
349 query()->AddSorter(
350 DownloadQuery::SORT_TOTAL_BYTES, DownloadQuery::DESCENDING);
351 Search();
352 EXPECT_EQ(1, results()->at(0)->GetTotalBytes());
353 EXPECT_EQ(0, results()->at(1)->GetTotalBytes());
354}
355
356TEST_F(DownloadQueryTest, DownloadQuerySortUrl) {
357 CreateMocks(2);
358 GURL a_url("http://example.com/a");
359 GURL b_url("http://example.com/b");
360 EXPECT_CALL(mock(0), GetOriginalUrl()).WillRepeatedly(ReturnRef(b_url));
361 EXPECT_CALL(mock(1), GetOriginalUrl()).WillRepeatedly(ReturnRef(a_url));
362 query()->AddSorter(
363 DownloadQuery::SORT_URL, DownloadQuery::ASCENDING);
364 Search();
365 EXPECT_EQ(a_url, results()->at(0)->GetOriginalUrl());
366 EXPECT_EQ(b_url, results()->at(1)->GetOriginalUrl());
367}
368
369TEST_F(DownloadQueryTest, DownloadQuerySortId) {
370 CreateMocks(2);
371 EXPECT_CALL(mock(0), GetReceivedBytes()).WillRepeatedly(Return(0));
372 EXPECT_CALL(mock(1), GetReceivedBytes()).WillRepeatedly(Return(0));
373 EXPECT_CALL(mock(0), GetId()).WillRepeatedly(Return(1));
374 EXPECT_CALL(mock(1), GetId()).WillRepeatedly(Return(0));
375 query()->AddSorter(
376 DownloadQuery::SORT_BYTES_RECEIVED, DownloadQuery::DESCENDING);
377 Search();
378 EXPECT_EQ(0, results()->at(0)->GetId());
379 EXPECT_EQ(1, results()->at(1)->GetId());
380}
381
382TEST_F(DownloadQueryTest, DownloadQueryFilterPerformance) {
383 static const int kNumItems = 10000;
384 static const int kNumFilters = 1000;
385 CreateMocks(kNumItems);
386 for (size_t i = 0; i < (kNumFilters - 1); ++i) {
387 query()->AddFilter(base::Bind(&AlwaysReturn, true));
388 }
389 query()->AddFilter(base::Bind(&AlwaysReturn, false));
390 base::Time start = base::Time::Now();
391 Search();
392 base::Time end = base::Time::Now();
393 double nanos = (end - start).InMillisecondsF() * 1000.0 * 1000.0;
394 double nanos_per_item = nanos / static_cast<double>(kNumItems);
395 double nanos_per_item_per_filter = nanos_per_item
396 / static_cast<double>(kNumFilters);
397 std::cout << "Search took " << nanos_per_item_per_filter
398 << " nanoseconds per item per filter.\n";
399}