Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / ui / app_list / search / history_unittest.cc
blob95462157a8e203d36780cd1725407a545dbe069a
1 // Copyright 2013 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 #include "base/basictypes.h"
6 #include "base/bind.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/threading/platform_thread.h"
13 #include "chrome/browser/ui/app_list/search/history_factory.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/app_list/search/dictionary_data_store.h"
16 #include "ui/app_list/search/history.h"
17 #include "ui/app_list/search/history_data.h"
18 #include "ui/app_list/search/history_data_observer.h"
19 #include "ui/app_list/search/history_data_store.h"
21 namespace app_list {
22 namespace test {
24 namespace {
26 const size_t kMaxPrimary = 3;
27 const size_t kMaxSecondary = 2;
29 // HistoryDataLoadWaiter waits for give |data| to be loaded from underlying
30 // store on the blocking pool. The waiter waits on the main message loop until
31 // OnHistoryDataLoadedFromStore() is invoked or the maximum allowed wait time
32 // has passed.
33 class HistoryDataLoadWaiter : public HistoryDataObserver {
34 public:
35 explicit HistoryDataLoadWaiter(HistoryData* data) : data_(data) {}
36 ~HistoryDataLoadWaiter() override {}
38 void Wait() {
39 data_->AddObserver(this);
41 run_loop_.reset(new base::RunLoop);
42 run_loop_->Run();
44 data_->RemoveObserver(this);
47 private:
48 // HistoryDataObserver overrides:
49 void OnHistoryDataLoadedFromStore() override { run_loop_->Quit(); }
51 HistoryData* data_; // Not owned.
52 scoped_ptr<base::RunLoop> run_loop_;
54 DISALLOW_COPY_AND_ASSIGN(HistoryDataLoadWaiter);
57 // StoreFlushWaiter waits for the given |store| to flush its data to disk.
58 // The flush and disk write happens on the blocking pool. The waiter waits
59 // on the main message loop until the OnFlushed() is invoked or the maximum
60 // allowed wait time has passed.
61 class StoreFlushWaiter {
62 public:
63 explicit StoreFlushWaiter(HistoryDataStore* store) : store_(store) {}
64 ~StoreFlushWaiter() {}
66 void Wait() {
67 store_->Flush(
68 base::Bind(&StoreFlushWaiter::OnFlushed, base::Unretained(this)));
70 run_loop_.reset(new base::RunLoop);
71 run_loop_->Run();
74 private:
75 void OnFlushed() {
76 run_loop_->Quit();
79 HistoryDataStore* store_; // Not owned.
80 scoped_ptr<base::RunLoop> run_loop_;
82 DISALLOW_COPY_AND_ASSIGN(StoreFlushWaiter);
85 } // namespace
87 class SearchHistoryTest : public testing::Test {
88 public:
89 SearchHistoryTest() {}
90 ~SearchHistoryTest() override {}
92 // testing::Test overrides:
93 void SetUp() override {
94 worker_pool_ = new base::SequencedWorkerPool(1, "AppLauncherTest");
95 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
96 CreateHistory();
98 void TearDown() override { Flush(); }
100 void CreateHistory() {
101 const char kStoreDataFileName[] = "app-launcher-test";
102 const base::FilePath data_file =
103 temp_dir_.path().AppendASCII(kStoreDataFileName);
104 scoped_refptr<DictionaryDataStore> dictionary_data_store(
105 new DictionaryDataStore(data_file, worker_pool_.get()));
106 history_.reset(new History(scoped_refptr<HistoryDataStore>(
107 new HistoryDataStore(dictionary_data_store))));
109 // Replace |data_| with test params.
110 history_->data_->RemoveObserver(history_.get());
111 history_->data_.reset(
112 new HistoryData(history_->store_.get(), kMaxPrimary, kMaxSecondary));
113 history_->data_->AddObserver(history_.get());
115 HistoryDataLoadWaiter(history_->data_.get()).Wait();
116 ASSERT_TRUE(history_->IsReady());
119 void Flush() {
120 StoreFlushWaiter(history_->store_.get()).Wait();
123 size_t GetKnownResults(const std::string& query) {
124 known_results_ = history()->GetKnownResults(query).Pass();
125 return known_results_->size();
128 KnownResultType GetResultType(const std::string& result_id) {
129 return known_results_->find(result_id) != known_results_->end()
130 ? (*known_results_.get())[result_id]
131 : UNKNOWN_RESULT;
134 History* history() { return history_.get(); }
135 const HistoryData::Associations& associations() const {
136 return history_->data_->associations();
139 private:
140 base::MessageLoopForUI message_loop_;
141 base::ScopedTempDir temp_dir_;
142 scoped_refptr<base::SequencedWorkerPool> worker_pool_;
144 scoped_ptr<History> history_;
145 scoped_ptr<KnownResults> known_results_;
147 DISALLOW_COPY_AND_ASSIGN(SearchHistoryTest);
150 TEST_F(SearchHistoryTest, Persistence) {
151 // Ensure it's empty.
152 EXPECT_EQ(0u, GetKnownResults("cal"));
154 // Add one launch event.
155 history()->AddLaunchEvent("cal", "calendar");
156 EXPECT_EQ(1u, GetKnownResults("cal"));
158 // Flush and recreate the history object.
159 Flush();
160 CreateHistory();
162 // History should be initialized with data just added.
163 EXPECT_EQ(1u, GetKnownResults("cal"));
166 TEST_F(SearchHistoryTest, PerfectAndPrefixMatch) {
167 const char kQuery[] = "cal";
168 const char kQueryPrefix[] = "c";
169 const char kPrimary[] = "calendar";
170 const char kSecondary[] = "calculator";
172 history()->AddLaunchEvent(kQuery, kPrimary);
173 history()->AddLaunchEvent(kQuery, kSecondary);
175 EXPECT_EQ(2u, GetKnownResults(kQuery));
176 EXPECT_EQ(PERFECT_PRIMARY, GetResultType(kPrimary));
177 EXPECT_EQ(PERFECT_SECONDARY, GetResultType(kSecondary));
179 EXPECT_EQ(2u, GetKnownResults(kQueryPrefix));
180 EXPECT_EQ(PREFIX_PRIMARY, GetResultType(kPrimary));
181 EXPECT_EQ(PREFIX_SECONDARY, GetResultType(kSecondary));
184 TEST_F(SearchHistoryTest, StickyPrimary) {
185 const char kQuery[] = "cal";
186 const char kPrimary[] = "calendar";
187 const char kSecondary[] = "calculator";
188 const char kOther[] = "other";
190 // Add two launch events. kPrimary becomes primary.
191 history()->AddLaunchEvent(kQuery, kPrimary);
192 history()->AddLaunchEvent(kQuery, kSecondary);
194 EXPECT_EQ(2u, GetKnownResults(kQuery));
195 EXPECT_EQ(PERFECT_PRIMARY, GetResultType(kPrimary));
196 EXPECT_EQ(PERFECT_SECONDARY, GetResultType(kSecondary));
198 // These launch events should not change primary.
199 history()->AddLaunchEvent(kQuery, kPrimary);
200 history()->AddLaunchEvent(kQuery, kSecondary);
201 history()->AddLaunchEvent(kQuery, kPrimary);
202 history()->AddLaunchEvent(kQuery, kSecondary);
203 history()->AddLaunchEvent(kQuery, kPrimary);
204 history()->AddLaunchEvent(kQuery, kSecondary);
205 history()->AddLaunchEvent(kQuery, kOther);
206 history()->AddLaunchEvent(kQuery, kSecondary);
207 history()->AddLaunchEvent(kQuery, kOther);
208 history()->AddLaunchEvent(kQuery, kSecondary);
209 history()->AddLaunchEvent(kQuery, kOther);
211 EXPECT_EQ(3u, GetKnownResults(kQuery));
212 EXPECT_EQ(PERFECT_PRIMARY, GetResultType(kPrimary));
213 EXPECT_EQ(PERFECT_SECONDARY, GetResultType(kSecondary));
214 EXPECT_EQ(PERFECT_SECONDARY, GetResultType(kOther));
217 TEST_F(SearchHistoryTest, PromoteSecondary) {
218 const char kQuery[] = "cal";
219 const char kPrimary[] = "calendar";
220 const char kSecondary[] = "calculator";
222 history()->AddLaunchEvent(kQuery, kPrimary);
223 history()->AddLaunchEvent(kQuery, kSecondary);
225 EXPECT_EQ(2u, GetKnownResults(kQuery));
226 EXPECT_EQ(PERFECT_PRIMARY, GetResultType(kPrimary));
227 EXPECT_EQ(PERFECT_SECONDARY, GetResultType(kSecondary));
229 // The 2nd launch in a row promotes it to be primary.
230 history()->AddLaunchEvent(kQuery, kSecondary);
232 EXPECT_EQ(2u, GetKnownResults(kQuery));
233 EXPECT_EQ(PERFECT_PRIMARY, GetResultType(kSecondary));
234 EXPECT_EQ(PERFECT_SECONDARY, GetResultType(kPrimary));
237 TEST_F(SearchHistoryTest, MaxPrimary) {
238 for (size_t i = 0; i < kMaxPrimary; ++i) {
239 std::string query = base::StringPrintf("%d", static_cast<int>(i));
240 history()->AddLaunchEvent(query, "app");
242 EXPECT_EQ(kMaxPrimary, associations().size());
244 // Oldest entries still exists.
245 EXPECT_TRUE(associations().find("0") != associations().end());
246 EXPECT_TRUE(associations().find("1") != associations().end());
248 // Primary entry trimming is based on time. The code could run here too fast
249 // and Time::Now has not changed on some platform. Sleep a bit here to ensure
250 // that some time has passed to get rid of the flake.
251 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(25));
253 // Touches the oldest and 2nd oldest becomes oldest now.
254 history()->AddLaunchEvent("0", "app");
256 // Adds one more
257 history()->AddLaunchEvent("extra", "app");
259 // Number of entries are capped to kMaxPrimary.
260 EXPECT_EQ(kMaxPrimary, associations().size());
262 // Oldest entry is trimmed.
263 EXPECT_FALSE(associations().find("1") != associations().end());
265 // The touched oldest survived.
266 EXPECT_TRUE(associations().find("0") != associations().end());
269 TEST_F(SearchHistoryTest, MaxSecondary) {
270 const char kQuery[] = "query";
271 history()->AddLaunchEvent(kQuery, "primary");
272 for (size_t i = 0; i < kMaxSecondary; ++i) {
273 std::string result_id = base::StringPrintf("%d", static_cast<int>(i));
274 history()->AddLaunchEvent(kQuery, result_id);
277 EXPECT_EQ(kMaxSecondary + 1, GetKnownResults(kQuery));
278 EXPECT_EQ(PERFECT_SECONDARY, GetResultType("0"));
279 EXPECT_EQ(PERFECT_SECONDARY, GetResultType("1"));
281 // Touches the oldest secondary.
282 history()->AddLaunchEvent(kQuery, "0");
284 // Adds one more.
285 history()->AddLaunchEvent(kQuery, "extra");
287 // Total number of results is capped.
288 EXPECT_EQ(kMaxSecondary + 1, GetKnownResults(kQuery));
290 // The oldest secondary is gone.
291 EXPECT_EQ(UNKNOWN_RESULT, GetResultType("1"));
293 // Touched oldest survived.
294 EXPECT_EQ(PERFECT_SECONDARY, GetResultType("0"));
297 } // namespace test
298 } // namespace app_list