Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Side by Side Diff: chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc

Issue 11298004: alternate ntp: add "Recent Tabs" submenu to wrench menu (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: addressed scott's comments Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h"
6
7 #include "base/rand_util.h"
8 #include "base/string_number_conversions.h"
9 #include "base/stringprintf.h"
10 #include "chrome/app/chrome_command_ids.h"
11 #include "chrome/browser/sessions/session_types.h"
12 #include "chrome/browser/sessions/session_types_test_helper.h"
13 #include "chrome/browser/sync/glue/session_model_associator.h"
14 #include "chrome/browser/sync/glue/synced_session.h"
15 #include "chrome/browser/sync/profile_sync_service_mock.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_tabstrip.h"
18 #include "chrome/test/base/browser_with_test_window_test.h"
19 #include "chrome/test/base/menu_model_test.h"
20 #include "chrome/test/base/testing_profile.h"
21 #include "grit/generated_resources.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace {
26
27 const char kBaseSessionTag[] = "session_tag";
28 const char kBaseSessionName[] = "session_name";
29 const char kBaseTabUrl[] = "http://foo/?";
30 const char kTabTitleFormat[] = "session=%d;window=%d;tab=%d";
31
32 struct TabTime {
33 TabTime(SessionID::id_type session_id,
34 SessionID::id_type window_id,
35 int tab_idx,
36 base::Time timestamp)
37 : session_id(session_id),
38 window_id(window_id),
39 tab_idx(tab_idx),
40 timestamp(timestamp) {}
41
42 SessionID::id_type session_id;
43 SessionID::id_type window_id;
44 int tab_idx;
45 base::Time timestamp;
46 };
47
48 bool SortTabTimesByRecency(const TabTime& t1, const TabTime& t2) {
49 return t1.timestamp > t2.timestamp;
50 }
51
52 std::string ToSessionTag(SessionID::id_type session_id) {
53 return std::string(kBaseSessionTag + base::IntToString(session_id));
54 }
55
56 std::string ToSessionName(SessionID::id_type session_id) {
57 return std::string(kBaseSessionName + base::IntToString(session_id));
58 }
59
60 std::string ToTabTitle(SessionID::id_type session_id,
61 SessionID::id_type window_id,
62 int tab_idx) {
63 return base::StringPrintf(kTabTitleFormat, session_id, window_id, tab_idx);
64 }
65
66 std::string ToTabUrl(SessionID::id_type session_id,
67 SessionID::id_type window_id,
68 int tab_idx) {
69 return std::string(kBaseTabUrl + ToTabTitle(session_id, window_id, tab_idx));
70 }
71
72 // Copies parts of MenuModelTest::Delegate and combines them with the
73 // RecentTabsSubMenuModel since RecentTabsSubMenuModel is a
74 // SimpleMenuModel::Delegate and not just derived from SimpleMenuModel.
75 class TestRecentTabsSubMenuModel : public RecentTabsSubMenuModel {
76 public:
77 TestRecentTabsSubMenuModel(ui::AcceleratorProvider* provider,
78 Browser* browser,
79 bool can_restore_tab)
80 : RecentTabsSubMenuModel(provider, browser),
81 can_restore_tab_(can_restore_tab),
82 execute_count_(0),
83 enable_count_(0) {
84 }
85
86 TestRecentTabsSubMenuModel(ui::AcceleratorProvider* provider,
87 Browser* browser,
88 browser_sync::SessionModelAssociator* associator,
89 bool can_restore_tab)
90 : RecentTabsSubMenuModel(provider, browser, associator, true),
91 can_restore_tab_(can_restore_tab),
92 execute_count_(0),
93 enable_count_(0) {
94 }
95
96 // Testing overrides to ui::SimpleMenuModel::Delegate:
97 virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
98 bool val = command_id == IDC_RESTORE_TAB ? can_restore_tab_ :
99 RecentTabsSubMenuModel::IsCommandIdEnabled(command_id);
100 if (val)
101 ++enable_count_;
102 return val;
103 }
104
105 virtual void ExecuteCommand(int command_id) OVERRIDE {
106 ++execute_count_;
107 }
108
109 bool can_restore_tab_;
110 int execute_count_;
111 int mutable enable_count_; // Mutable because IsCommandIdEnabledAt is const.
112 };
113
114 class TestSessionModelAssociator{
115 public:
116 TestSessionModelAssociator()
117 : sync_service_(&profile_),
118 model_associator_(&sync_service_, true) {}
119
120 void InitWindowPb(int num_tabs, SessionID::id_type* tab_id,
121 sync_pb::SessionWindow* window_pb) {
122 for (int i = 0; i < num_tabs; ++i)
123 window_pb->add_tab((*tab_id)++);
124 window_pb->set_browser_type(sync_pb::SessionWindow_BrowserType_TYPE_TABBED);
125 window_pb->set_selected_tab_index(0);
126 }
127
128 void CreateSession(SessionID::id_type session_id) {
129 browser_sync::SyncedSession* session = GetSession(session_id);
130 session->device_type = browser_sync::SyncedSession::TYPE_CHROMEOS;
131 session->session_name = ToSessionName(session_id);
132 }
133
134 void PutWindowInSessionAndTracker(SessionID::id_type session_id,
135 SessionID::id_type window_id,
136 const sync_pb::SessionWindow& window_pb) {
akalin 2012/11/10 00:08:40 actually, can't you just use the public function A
kuan 2012/11/10 17:07:04 i tried implementing building the SessionSpecifics
kuan 2012/11/10 19:34:46 Done.
137 tracker().PutWindowInSession(ToSessionTag(session_id), window_id);
138 browser_sync::SyncedSession* session = GetSession(session_id);
139 SessionWindow* window = session->windows[window_id];
140 browser_sync::SessionModelAssociator::
141 PopulateSessionWindowFromSpecificsForTest(
142 ToSessionTag(session_id), window_pb, base::Time(), window,
143 &tracker());
144 ASSERT_EQ(static_cast<size_t>(window_pb.tab_size()), window->tabs.size());
145 }
146
147 void MakeTabSyncable(SessionID::id_type session_id,
148 SessionID::id_type window_id,
149 int tab_idx,
150 base::Time timestamp) {
151 browser_sync::SyncedSession* session = GetSession(session_id);
akalin 2012/11/10 00:08:40 can you do this using public functions? Maybe use
kuan 2012/11/10 19:34:46 Done.
152 SessionTab* tab = session->windows[window_id]->tabs[tab_idx];
153 tab->navigations.push_back(SessionTypesTestHelper::CreateNavigation(
154 ToTabUrl(session_id, window_id, tab_idx),
155 ToTabTitle(session_id, window_id, tab_idx)));
156 tab->current_navigation_index = 0;
157 tab->timestamp = timestamp;
158 session->modified_time = timestamp;
159 }
160
161 browser_sync::SyncedSession* GetSession(SessionID::id_type session_id) {
162 return tracker().GetSession(ToSessionTag(session_id));
163 }
164
165 browser_sync::SyncedSessionTracker& tracker() {
166 return model_associator_.GetSyncedSessionTrackerForTest();
167 }
168
169 browser_sync::SessionModelAssociator& model_associator() {
170 return model_associator_;
171 }
172
173 private:
174 TestingProfile profile_;
175 testing::NiceMock<ProfileSyncServiceMock> sync_service_;
176 browser_sync::SessionModelAssociator model_associator_;
177 };
178
179 } // namespace
180
181 class RecentTabsSubMenuModelTest : public BrowserWithTestWindowTest,
182 public ui::AcceleratorProvider {
183 public:
184 // Don't handle accelerators.
185 virtual bool GetAcceleratorForCommandId(
186 int command_id,
187 ui::Accelerator* accelerator) OVERRIDE {
188 return false;
189 }
190 };
191
192 TEST_F(RecentTabsSubMenuModelTest, NoTabs) {
193 TestRecentTabsSubMenuModel model(this, browser(), false);
194
195 // Expected menu:
196 // Menu index Menu items
197 // --------------------------------------
198 // 0 Reopen closed tab
199 // 1 <separator>
200 // 2 No tabs from other Devices
201
202 int num_items = model.GetItemCount();
203 EXPECT_EQ(3, num_items);
204 EXPECT_FALSE(model.IsEnabledAt(0));
205 EXPECT_FALSE(model.IsEnabledAt(2));
206 EXPECT_EQ(0, model.enable_count_);
207 }
208
209 TEST_F(RecentTabsSubMenuModelTest, ReopenClosedTab) {
210 TestRecentTabsSubMenuModel model(this, browser(), true);
211 // Menu contents are identical to NoTabs test.
212 int num_items = model.GetItemCount();
213 EXPECT_EQ(3, num_items);
214 EXPECT_TRUE(model.IsEnabledAt(0));
215 model.ActivatedAt(0);
216 EXPECT_FALSE(model.IsEnabledAt(2));
217 EXPECT_EQ(1, model.enable_count_);
218 EXPECT_EQ(1, model.execute_count_);
219 }
220
221 TEST_F(RecentTabsSubMenuModelTest, OtherDevices) {
222 TestSessionModelAssociator associator;
223 SessionID::id_type id = 0;
224 // Tabs are populated in decreasing timestamp.
225 base::Time now = base::Time::Now();
226
227 // Create 1st session : 1 window, 3 tabs
228 SessionID::id_type session_id = id++;
229 associator.CreateSession(session_id);
230 SessionID::id_type window_id = id++;
231 sync_pb::SessionWindow window_pb;
232 associator.InitWindowPb(3, &id, &window_pb);
233 associator.PutWindowInSessionAndTracker(session_id, window_id, window_pb);
234 base::Time timestamp = now - base::TimeDelta::FromMinutes(window_id * 10);
235 associator.MakeTabSyncable(session_id, window_id, 0, timestamp);
236 associator.MakeTabSyncable(session_id, window_id, 1,
237 timestamp - base::TimeDelta::FromMinutes(1));
238 associator.MakeTabSyncable(session_id, window_id, 2,
239 timestamp - base::TimeDelta::FromMinutes(2));
240 ASSERT_EQ(3U, associator.tracker().num_synced_tabs(ToSessionTag(session_id)));
akalin 2012/11/10 00:08:40 can you get the num synced tabs using GetForeignSe
kuan 2012/11/10 19:34:46 Done.
241
242 // Create 2nd session : 2 windows, 1 tab in 1st window, 2 tabs in 2nd window
243 session_id = id++;
244 associator.CreateSession(session_id);
245 window_id = id++;
246 sync_pb::SessionWindow window_pb0;
247 associator.InitWindowPb(1, &id, &window_pb0);
248 associator.PutWindowInSessionAndTracker(session_id, window_id, window_pb0);
249 timestamp = now - base::TimeDelta::FromMinutes(window_id * 10);
250 associator.MakeTabSyncable(session_id, window_id, 0, timestamp);
251 ASSERT_EQ(1U, associator.tracker().num_synced_tabs(ToSessionTag(session_id)));
252 window_id = id++;
253 sync_pb::SessionWindow window_pb1;
254 associator.InitWindowPb(2, &id, &window_pb1);
255 associator.PutWindowInSessionAndTracker(session_id, window_id, window_pb1);
256 timestamp = now - base::TimeDelta::FromMinutes(window_id * 10);
257 associator.MakeTabSyncable(session_id, window_id, 0, timestamp);
258 associator.MakeTabSyncable(session_id, window_id, 1,
259 timestamp - base::TimeDelta::FromMinutes(1));
260 ASSERT_EQ(3U, associator.tracker().num_synced_tabs(ToSessionTag(session_id)));
261
262 ASSERT_EQ(2U, associator.tracker().num_synced_sessions());
akalin 2012/11/10 00:08:40 GetAllForeignSessions()?
kuan 2012/11/10 19:34:46 Done.
263
264 TestRecentTabsSubMenuModel model(this, browser(),
265 &associator.model_associator(), true);
266
267 // Expected menu:
268 // - first inserted tab is most recent and hence is top
269 // Menu index Menu items
270 // --------------------------------------
271 // 0 Reopen closed tab
272 // 1 <separator>
273 // 2 <section header for 1st session>
274 // 3-5 <3 tabs of the only window of session 0>
275 // 6 <separator>
276 // 7 <section header for 2nd session>
277 // 8 <the only tab of window 0 of session 1>
278 // 9-10 <2 tabs of window 1 of session 2>
279
280 int num_items = model.GetItemCount();
281 EXPECT_EQ(11, num_items);
282 model.ActivatedAt(0);
283 EXPECT_TRUE(model.IsEnabledAt(0));
284 model.ActivatedAt(3);
285 EXPECT_TRUE(model.IsEnabledAt(3));
286 model.ActivatedAt(4);
287 EXPECT_TRUE(model.IsEnabledAt(4));
288 model.ActivatedAt(5);
289 EXPECT_TRUE(model.IsEnabledAt(5));
290 model.ActivatedAt(8);
291 EXPECT_TRUE(model.IsEnabledAt(8));
292 model.ActivatedAt(9);
293 EXPECT_TRUE(model.IsEnabledAt(9));
294 model.ActivatedAt(10);
295 EXPECT_TRUE(model.IsEnabledAt(10));
296 EXPECT_EQ(7, model.enable_count_);
297 EXPECT_EQ(7, model.execute_count_);
298 }
299
300 TEST_F(RecentTabsSubMenuModelTest, MaxSessionsAndRecency) {
301 TestSessionModelAssociator associator;
302 SessionID::id_type id = 0;
303 base::Time now = base::Time::Now();
304
305 // Create 4 sessions : each session has 1 window with 1 tab each .
306 std::vector<TabTime> tab_times;
307 for (int i = 0; i < 4; ++i) {
308 SessionID::id_type session_id = id++;
309 associator.CreateSession(session_id);
310 SessionID::id_type window_id = id++;
311 sync_pb::SessionWindow window_pb;
312 associator.InitWindowPb(1, &id, &window_pb);
313 associator.PutWindowInSessionAndTracker(session_id, window_id, window_pb);
314 base::Time timestamp = now +
315 base::TimeDelta::FromMinutes(base::RandUint64());
316 associator.MakeTabSyncable(session_id, window_id, 0, timestamp);
317 tab_times.push_back(TabTime(session_id, window_id, 0, timestamp));
318 ASSERT_EQ(1U,
319 associator.tracker().num_synced_tabs(ToSessionTag(session_id)));
320 }
321 ASSERT_EQ(4U, associator.tracker().num_synced_sessions());
322
323 TestRecentTabsSubMenuModel model(this, browser(),
324 &associator.model_associator(), true);
325
326 // Expected menu:
327 // - max sessions is 3, so only 3 most-recent sessions will show
328 // Menu index Menu items
329 // --------------------------------------
330 // 0 Reopen closed tab
331 // 1 <separator>
332 // 2 <section header for 1st session>
333 // 3 <the only tab of the only window of session 3>
334 // 4 <separator>
335 // 5 <section header for 2nd session>
336 // 6 <the only tab of the only window of session 2>
337 // 7 <separator>
338 // 8 <section header for 3rd session>
339 // 9 <the only tab of the only window of session 1>
340
341 int num_items = model.GetItemCount();
342 EXPECT_EQ(10, num_items);
343
344 sort(tab_times.begin(), tab_times.end(), SortTabTimesByRecency);
345 EXPECT_EQ(UTF8ToUTF16(ToTabTitle(tab_times[0].session_id,
346 tab_times[0].window_id,
347 tab_times[0].tab_idx)),
348 model.GetLabelAt(3));
349 EXPECT_EQ(UTF8ToUTF16(ToTabTitle(tab_times[1].session_id,
350 tab_times[1].window_id,
351 tab_times[1].tab_idx)),
352 model.GetLabelAt(6));
353 EXPECT_EQ(UTF8ToUTF16(ToTabTitle(tab_times[2].session_id,
354 tab_times[2].window_id,
355 tab_times[2].tab_idx)),
356 model.GetLabelAt(9));
357 }
358
359 TEST_F(RecentTabsSubMenuModelTest, MaxTabsPerSessionAndRecency) {
360 TestSessionModelAssociator associator;
361 SessionID::id_type id = 0;
362 base::Time now = base::Time::Now();
363
364 // Create a session: 2 windows with 5 tabs each.
365 std::vector<TabTime> tab_times;
366 SessionID::id_type session_id = id++;
367 associator.CreateSession(session_id);
368 for (int j = 0; j < 2; ++j) {
369 SessionID::id_type window_id = id++;
370 sync_pb::SessionWindow window_pb;
371 associator.InitWindowPb(5, &id, &window_pb);
372 associator.PutWindowInSessionAndTracker(session_id, window_id, window_pb);
373 for (int k = 0; k < 5; ++k) {
374 base::Time timestamp(now +
375 base::TimeDelta::FromMinutes(base::RandUint64()));
376 associator.MakeTabSyncable(session_id, window_id, k, timestamp);
377 tab_times.push_back(TabTime(session_id, window_id, k, timestamp));
378 }
379 }
380 ASSERT_EQ(10U,
381 associator.tracker().num_synced_tabs(ToSessionTag(session_id)));
382 ASSERT_EQ(1U, associator.tracker().num_synced_sessions());
383
384 TestRecentTabsSubMenuModel model(this, browser(),
385 &associator.model_associator(), true);
386
387 // Expected menu:
388 // - max tabs per session is 4, so only 4 most-recent tabs will show,
389 // independent of which window they came from
390 // Menu index Menu items
391 // --------------------------------------
392 // 0 Reopen closed tab
393 // 1 <separator>
394 // 2 <section header for session>
395 // 3-6 <4 most-recent tabs of session>
396
397 int num_items = model.GetItemCount();
398 EXPECT_EQ(7, num_items);
399
400 sort(tab_times.begin(), tab_times.end(), SortTabTimesByRecency);
401 EXPECT_EQ(UTF8ToUTF16(ToTabTitle(tab_times[0].session_id,
402 tab_times[0].window_id,
403 tab_times[0].tab_idx)),
404 model.GetLabelAt(3));
405 EXPECT_EQ(UTF8ToUTF16(ToTabTitle(tab_times[1].session_id,
406 tab_times[1].window_id,
407 tab_times[1].tab_idx)),
408 model.GetLabelAt(4));
409 EXPECT_EQ(UTF8ToUTF16(ToTabTitle(tab_times[2].session_id,
410 tab_times[2].window_id,
411 tab_times[2].tab_idx)),
412 model.GetLabelAt(5));
413 EXPECT_EQ(UTF8ToUTF16(ToTabTitle(tab_times[3].session_id,
414 tab_times[3].window_id,
415 tab_times[3].tab_idx)),
416 model.GetLabelAt(6));
417 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698