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 #include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
7 #include "base/path_service.h"
8 #include "base/strings/string16.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/time/time.h"
12 #include "chrome/browser/favicon/favicon_service_factory.h"
13 #include "chrome/browser/history/history_service.h"
14 #include "chrome/browser/history/history_service_factory.h"
15 #include "chrome/browser/profiles/profile_manager.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_tabstrip.h"
18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/common/url_constants.h"
20 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
21 #include "chrome/test/base/test_browser_window.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "content/public/browser/navigation_controller.h"
24 #include "content/public/browser/navigation_entry.h"
25 #include "content/public/browser/web_contents.h"
26 #include "content/public/test/web_contents_tester.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28 #include "third_party/skia/include/core/SkBitmap.h"
29 #include "ui/gfx/codec/png_codec.h"
31 using base::ASCIIToUTF16
;
32 using content::WebContentsTester
;
36 // Creates a bitmap of the specified color.
37 SkBitmap
CreateBitmap(SkColor color
) {
39 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, 16, 16);
41 bitmap
.eraseColor(color
);
45 class FaviconDelegate
: public ui::MenuModelDelegate
{
47 FaviconDelegate() : was_called_(false) {}
49 virtual void OnIconChanged(int model_index
) OVERRIDE
{
51 base::MessageLoop::current()->Quit();
54 bool was_called() const { return was_called_
; }
59 DISALLOW_COPY_AND_ASSIGN(FaviconDelegate
);
64 class BackFwdMenuModelTest
: public ChromeRenderViewHostTestHarness
{
66 void ValidateModel(BackForwardMenuModel
* model
, int history_items
,
68 int h
= std::min(BackForwardMenuModel::kMaxHistoryItems
, history_items
);
69 int c
= std::min(BackForwardMenuModel::kMaxChapterStops
, chapter_stops
);
70 EXPECT_EQ(h
, model
->GetHistoryItemCount());
71 EXPECT_EQ(c
, model
->GetChapterStopCount(h
));
73 h
+= 2; // Separator and View History link.
76 EXPECT_EQ(h
+ c
, model
->GetItemCount());
79 void LoadURLAndUpdateState(const char* url
, const char* title
) {
80 NavigateAndCommit(GURL(url
));
81 controller().GetLastCommittedEntry()->SetTitle(base::UTF8ToUTF16(title
));
84 // Navigate back or forward the given amount and commits the entry (which
85 // will be pending after we ask to navigate there).
86 void NavigateToOffset(int offset
) {
87 controller().GoToOffset(offset
);
88 WebContentsTester::For(web_contents())->CommitPendingNavigation();
91 // Same as NavigateToOffset but goes to an absolute index.
92 void NavigateToIndex(int index
) {
93 controller().GoToIndex(index
);
94 WebContentsTester::For(web_contents())->CommitPendingNavigation();
97 // Goes back/forward and commits the load.
99 controller().GoBack();
100 WebContentsTester::For(web_contents())->CommitPendingNavigation();
103 controller().GoForward();
104 WebContentsTester::For(web_contents())->CommitPendingNavigation();
108 TEST_F(BackFwdMenuModelTest
, BasicCase
) {
109 scoped_ptr
<BackForwardMenuModel
> back_model(new BackForwardMenuModel(
110 NULL
, BackForwardMenuModel::BACKWARD_MENU
));
111 back_model
->set_test_web_contents(web_contents());
113 scoped_ptr
<BackForwardMenuModel
> forward_model(new BackForwardMenuModel(
114 NULL
, BackForwardMenuModel::FORWARD_MENU
));
115 forward_model
->set_test_web_contents(web_contents());
117 EXPECT_EQ(0, back_model
->GetItemCount());
118 EXPECT_EQ(0, forward_model
->GetItemCount());
119 EXPECT_FALSE(back_model
->ItemHasCommand(1));
121 // Seed the controller with a few URLs
122 LoadURLAndUpdateState("http://www.a.com/1", "A1");
123 LoadURLAndUpdateState("http://www.a.com/2", "A2");
124 LoadURLAndUpdateState("http://www.a.com/3", "A3");
125 LoadURLAndUpdateState("http://www.b.com/1", "B1");
126 LoadURLAndUpdateState("http://www.b.com/2", "B2");
127 LoadURLAndUpdateState("http://www.c.com/1", "C1");
128 LoadURLAndUpdateState("http://www.c.com/2", "C2");
129 LoadURLAndUpdateState("http://www.c.com/3", "C3");
131 // There're two more items here: a separator and a "Show Full History".
132 EXPECT_EQ(9, back_model
->GetItemCount());
133 EXPECT_EQ(0, forward_model
->GetItemCount());
134 EXPECT_EQ(ASCIIToUTF16("C2"), back_model
->GetLabelAt(0));
135 EXPECT_EQ(ASCIIToUTF16("A1"), back_model
->GetLabelAt(6));
136 EXPECT_EQ(back_model
->GetShowFullHistoryLabel(),
137 back_model
->GetLabelAt(8));
139 EXPECT_TRUE(back_model
->ItemHasCommand(0));
140 EXPECT_TRUE(back_model
->ItemHasCommand(6));
141 EXPECT_TRUE(back_model
->IsSeparator(7));
142 EXPECT_TRUE(back_model
->ItemHasCommand(8));
143 EXPECT_FALSE(back_model
->ItemHasCommand(9));
144 EXPECT_FALSE(back_model
->ItemHasCommand(9));
146 NavigateToOffset(-7);
148 EXPECT_EQ(0, back_model
->GetItemCount());
149 EXPECT_EQ(9, forward_model
->GetItemCount());
150 EXPECT_EQ(ASCIIToUTF16("A2"), forward_model
->GetLabelAt(0));
151 EXPECT_EQ(ASCIIToUTF16("C3"), forward_model
->GetLabelAt(6));
152 EXPECT_EQ(forward_model
->GetShowFullHistoryLabel(),
153 forward_model
->GetLabelAt(8));
155 EXPECT_TRUE(forward_model
->ItemHasCommand(0));
156 EXPECT_TRUE(forward_model
->ItemHasCommand(6));
157 EXPECT_TRUE(forward_model
->IsSeparator(7));
158 EXPECT_TRUE(forward_model
->ItemHasCommand(8));
159 EXPECT_FALSE(forward_model
->ItemHasCommand(7));
160 EXPECT_FALSE(forward_model
->ItemHasCommand(9));
164 EXPECT_EQ(6, back_model
->GetItemCount());
165 EXPECT_EQ(5, forward_model
->GetItemCount());
166 EXPECT_EQ(ASCIIToUTF16("B1"), back_model
->GetLabelAt(0));
167 EXPECT_EQ(ASCIIToUTF16("A1"), back_model
->GetLabelAt(3));
168 EXPECT_EQ(back_model
->GetShowFullHistoryLabel(),
169 back_model
->GetLabelAt(5));
170 EXPECT_EQ(ASCIIToUTF16("C1"), forward_model
->GetLabelAt(0));
171 EXPECT_EQ(ASCIIToUTF16("C3"), forward_model
->GetLabelAt(2));
172 EXPECT_EQ(forward_model
->GetShowFullHistoryLabel(),
173 forward_model
->GetLabelAt(4));
176 TEST_F(BackFwdMenuModelTest
, MaxItemsTest
) {
177 scoped_ptr
<BackForwardMenuModel
> back_model(new BackForwardMenuModel(
178 NULL
, BackForwardMenuModel::BACKWARD_MENU
));
179 back_model
->set_test_web_contents(web_contents());
181 scoped_ptr
<BackForwardMenuModel
> forward_model(new BackForwardMenuModel(
182 NULL
, BackForwardMenuModel::FORWARD_MENU
));
183 forward_model
->set_test_web_contents(web_contents());
185 // Seed the controller with 32 URLs
186 LoadURLAndUpdateState("http://www.a.com/1", "A1");
187 LoadURLAndUpdateState("http://www.a.com/2", "A2");
188 LoadURLAndUpdateState("http://www.a.com/3", "A3");
189 LoadURLAndUpdateState("http://www.b.com/1", "B1");
190 LoadURLAndUpdateState("http://www.b.com/2", "B2");
191 LoadURLAndUpdateState("http://www.b.com/3", "B3");
192 LoadURLAndUpdateState("http://www.c.com/1", "C1");
193 LoadURLAndUpdateState("http://www.c.com/2", "C2");
194 LoadURLAndUpdateState("http://www.c.com/3", "C3");
195 LoadURLAndUpdateState("http://www.d.com/1", "D1");
196 LoadURLAndUpdateState("http://www.d.com/2", "D2");
197 LoadURLAndUpdateState("http://www.d.com/3", "D3");
198 LoadURLAndUpdateState("http://www.e.com/1", "E1");
199 LoadURLAndUpdateState("http://www.e.com/2", "E2");
200 LoadURLAndUpdateState("http://www.e.com/3", "E3");
201 LoadURLAndUpdateState("http://www.f.com/1", "F1");
202 LoadURLAndUpdateState("http://www.f.com/2", "F2");
203 LoadURLAndUpdateState("http://www.f.com/3", "F3");
204 LoadURLAndUpdateState("http://www.g.com/1", "G1");
205 LoadURLAndUpdateState("http://www.g.com/2", "G2");
206 LoadURLAndUpdateState("http://www.g.com/3", "G3");
207 LoadURLAndUpdateState("http://www.h.com/1", "H1");
208 LoadURLAndUpdateState("http://www.h.com/2", "H2");
209 LoadURLAndUpdateState("http://www.h.com/3", "H3");
210 LoadURLAndUpdateState("http://www.i.com/1", "I1");
211 LoadURLAndUpdateState("http://www.i.com/2", "I2");
212 LoadURLAndUpdateState("http://www.i.com/3", "I3");
213 LoadURLAndUpdateState("http://www.j.com/1", "J1");
214 LoadURLAndUpdateState("http://www.j.com/2", "J2");
215 LoadURLAndUpdateState("http://www.j.com/3", "J3");
216 LoadURLAndUpdateState("http://www.k.com/1", "K1");
217 LoadURLAndUpdateState("http://www.k.com/2", "K2");
219 // Also there're two more for a separator and a "Show Full History".
220 int chapter_stop_offset
= 6;
221 EXPECT_EQ(BackForwardMenuModel::kMaxHistoryItems
+ 2 + chapter_stop_offset
,
222 back_model
->GetItemCount());
223 EXPECT_EQ(0, forward_model
->GetItemCount());
224 EXPECT_EQ(ASCIIToUTF16("K1"), back_model
->GetLabelAt(0));
225 EXPECT_EQ(back_model
->GetShowFullHistoryLabel(),
226 back_model
->GetLabelAt(BackForwardMenuModel::kMaxHistoryItems
+ 1 +
227 chapter_stop_offset
));
229 // Test for out of bounds (beyond Show Full History).
230 EXPECT_FALSE(back_model
->ItemHasCommand(
231 BackForwardMenuModel::kMaxHistoryItems
+ chapter_stop_offset
+ 2));
233 EXPECT_TRUE(back_model
->ItemHasCommand(
234 BackForwardMenuModel::kMaxHistoryItems
- 1));
235 EXPECT_TRUE(back_model
->IsSeparator(
236 BackForwardMenuModel::kMaxHistoryItems
));
240 EXPECT_EQ(BackForwardMenuModel::kMaxHistoryItems
+ 2 + chapter_stop_offset
,
241 forward_model
->GetItemCount());
242 EXPECT_EQ(0, back_model
->GetItemCount());
243 EXPECT_EQ(ASCIIToUTF16("A2"), forward_model
->GetLabelAt(0));
244 EXPECT_EQ(forward_model
->GetShowFullHistoryLabel(),
245 forward_model
->GetLabelAt(BackForwardMenuModel::kMaxHistoryItems
+ 1 +
246 chapter_stop_offset
));
249 EXPECT_FALSE(forward_model
->ItemHasCommand(
250 BackForwardMenuModel::kMaxHistoryItems
+ 2 + chapter_stop_offset
));
252 EXPECT_TRUE(forward_model
->ItemHasCommand(
253 BackForwardMenuModel::kMaxHistoryItems
- 1));
254 EXPECT_TRUE(forward_model
->IsSeparator(
255 BackForwardMenuModel::kMaxHistoryItems
));
258 TEST_F(BackFwdMenuModelTest
, ChapterStops
) {
259 scoped_ptr
<BackForwardMenuModel
> back_model(new BackForwardMenuModel(
260 NULL
, BackForwardMenuModel::BACKWARD_MENU
));
261 back_model
->set_test_web_contents(web_contents());
263 scoped_ptr
<BackForwardMenuModel
> forward_model(new BackForwardMenuModel(
264 NULL
, BackForwardMenuModel::FORWARD_MENU
));
265 forward_model
->set_test_web_contents(web_contents());
267 // Seed the controller with 32 URLs.
269 LoadURLAndUpdateState("http://www.a.com/1", "A1");
270 ValidateModel(back_model
.get(), i
++, 0);
271 LoadURLAndUpdateState("http://www.a.com/2", "A2");
272 ValidateModel(back_model
.get(), i
++, 0);
273 LoadURLAndUpdateState("http://www.a.com/3", "A3");
274 ValidateModel(back_model
.get(), i
++, 0);
275 LoadURLAndUpdateState("http://www.b.com/1", "B1");
276 ValidateModel(back_model
.get(), i
++, 0);
277 LoadURLAndUpdateState("http://www.b.com/2", "B2");
278 ValidateModel(back_model
.get(), i
++, 0);
280 LoadURLAndUpdateState("http://www.b.com/3", "B3");
281 ValidateModel(back_model
.get(), i
++, 0);
282 LoadURLAndUpdateState("http://www.c.com/1", "C1");
283 ValidateModel(back_model
.get(), i
++, 0);
284 LoadURLAndUpdateState("http://www.c.com/2", "C2");
285 ValidateModel(back_model
.get(), i
++, 0);
286 LoadURLAndUpdateState("http://www.c.com/3", "C3");
287 ValidateModel(back_model
.get(), i
++, 0);
288 LoadURLAndUpdateState("http://www.d.com/1", "D1");
289 ValidateModel(back_model
.get(), i
++, 0);
291 LoadURLAndUpdateState("http://www.d.com/2", "D2");
292 ValidateModel(back_model
.get(), i
++, 0);
293 LoadURLAndUpdateState("http://www.d.com/3", "D3");
294 ValidateModel(back_model
.get(), i
++, 0);
295 LoadURLAndUpdateState("http://www.e.com/1", "E1");
296 ValidateModel(back_model
.get(), i
++, 0);
297 LoadURLAndUpdateState("http://www.e.com/2", "E2");
298 ValidateModel(back_model
.get(), i
++, 0);
299 LoadURLAndUpdateState("http://www.e.com/3", "E3");
300 ValidateModel(back_model
.get(), i
++, 0);
302 LoadURLAndUpdateState("http://www.f.com/1", "F1");
303 ValidateModel(back_model
.get(), i
++, 1);
304 LoadURLAndUpdateState("http://www.f.com/2", "F2");
305 ValidateModel(back_model
.get(), i
++, 1);
306 LoadURLAndUpdateState("http://www.f.com/3", "F3");
307 ValidateModel(back_model
.get(), i
++, 1);
308 LoadURLAndUpdateState("http://www.g.com/1", "G1");
309 ValidateModel(back_model
.get(), i
++, 2);
310 LoadURLAndUpdateState("http://www.g.com/2", "G2");
311 ValidateModel(back_model
.get(), i
++, 2);
313 LoadURLAndUpdateState("http://www.g.com/3", "G3");
314 ValidateModel(back_model
.get(), i
++, 2);
315 LoadURLAndUpdateState("http://www.h.com/1", "H1");
316 ValidateModel(back_model
.get(), i
++, 3);
317 LoadURLAndUpdateState("http://www.h.com/2", "H2");
318 ValidateModel(back_model
.get(), i
++, 3);
319 LoadURLAndUpdateState("http://www.h.com/3", "H3");
320 ValidateModel(back_model
.get(), i
++, 3);
321 LoadURLAndUpdateState("http://www.i.com/1", "I1");
322 ValidateModel(back_model
.get(), i
++, 4);
324 LoadURLAndUpdateState("http://www.i.com/2", "I2");
325 ValidateModel(back_model
.get(), i
++, 4);
326 LoadURLAndUpdateState("http://www.i.com/3", "I3");
327 ValidateModel(back_model
.get(), i
++, 4);
328 LoadURLAndUpdateState("http://www.j.com/1", "J1");
329 ValidateModel(back_model
.get(), i
++, 5);
330 LoadURLAndUpdateState("http://www.j.com/2", "J2");
331 ValidateModel(back_model
.get(), i
++, 5);
332 LoadURLAndUpdateState("http://www.j.com/3", "J3");
333 ValidateModel(back_model
.get(), i
++, 5);
335 LoadURLAndUpdateState("http://www.k.com/1", "K1");
336 ValidateModel(back_model
.get(), i
++, 6);
337 LoadURLAndUpdateState("http://www.k.com/2", "K2");
338 ValidateModel(back_model
.get(), i
++, 6);
340 LoadURLAndUpdateState("http://www.k.com/3", "K3");
341 ValidateModel(back_model
.get(), i
++, 6);
343 // A chapter stop is defined as the last page the user
344 // browsed to within the same domain.
346 // Check to see if the chapter stops have the right labels.
347 int index
= BackForwardMenuModel::kMaxHistoryItems
;
348 // Empty string indicates item is a separator.
349 EXPECT_EQ(base::string16(), back_model
->GetLabelAt(index
++));
350 EXPECT_EQ(ASCIIToUTF16("F3"), back_model
->GetLabelAt(index
++));
351 EXPECT_EQ(ASCIIToUTF16("E3"), back_model
->GetLabelAt(index
++));
352 EXPECT_EQ(ASCIIToUTF16("D3"), back_model
->GetLabelAt(index
++));
353 EXPECT_EQ(ASCIIToUTF16("C3"), back_model
->GetLabelAt(index
++));
354 // The menu should only show a maximum of 5 chapter stops.
355 EXPECT_EQ(ASCIIToUTF16("B3"), back_model
->GetLabelAt(index
));
356 // Empty string indicates item is a separator.
357 EXPECT_EQ(base::string16(), back_model
->GetLabelAt(index
+ 1));
358 EXPECT_EQ(back_model
->GetShowFullHistoryLabel(),
359 back_model
->GetLabelAt(index
+ 2));
361 // If we go back two we should still see the same chapter stop at the end.
363 EXPECT_EQ(ASCIIToUTF16("B3"), back_model
->GetLabelAt(index
));
365 EXPECT_EQ(ASCIIToUTF16("B3"), back_model
->GetLabelAt(index
));
366 // But if we go back again, it should change.
368 EXPECT_EQ(ASCIIToUTF16("A3"), back_model
->GetLabelAt(index
));
370 EXPECT_EQ(ASCIIToUTF16("A3"), back_model
->GetLabelAt(index
));
372 EXPECT_EQ(ASCIIToUTF16("A3"), back_model
->GetLabelAt(index
));
374 // It is now a separator.
375 EXPECT_EQ(base::string16(), back_model
->GetLabelAt(index
));
376 // Undo our position change.
379 // Go back enough to make sure no chapter stops should appear.
380 NavigateToOffset(-BackForwardMenuModel::kMaxHistoryItems
);
381 ValidateModel(forward_model
.get(), BackForwardMenuModel::kMaxHistoryItems
, 0);
382 // Go forward (still no chapter stop)
384 ValidateModel(forward_model
.get(),
385 BackForwardMenuModel::kMaxHistoryItems
- 1, 0);
386 // Go back two (one chapter stop should show up)
389 ValidateModel(forward_model
.get(),
390 BackForwardMenuModel::kMaxHistoryItems
, 1);
395 // Check to see if the chapter stops have the right labels.
396 index
= BackForwardMenuModel::kMaxHistoryItems
;
397 // Empty string indicates item is a separator.
398 EXPECT_EQ(base::string16(), forward_model
->GetLabelAt(index
++));
399 EXPECT_EQ(ASCIIToUTF16("E3"), forward_model
->GetLabelAt(index
++));
400 EXPECT_EQ(ASCIIToUTF16("F3"), forward_model
->GetLabelAt(index
++));
401 EXPECT_EQ(ASCIIToUTF16("G3"), forward_model
->GetLabelAt(index
++));
402 EXPECT_EQ(ASCIIToUTF16("H3"), forward_model
->GetLabelAt(index
++));
403 // The menu should only show a maximum of 5 chapter stops.
404 EXPECT_EQ(ASCIIToUTF16("I3"), forward_model
->GetLabelAt(index
));
405 // Empty string indicates item is a separator.
406 EXPECT_EQ(base::string16(), forward_model
->GetLabelAt(index
+ 1));
407 EXPECT_EQ(forward_model
->GetShowFullHistoryLabel(),
408 forward_model
->GetLabelAt(index
+ 2));
410 // If we advance one we should still see the same chapter stop at the end.
412 EXPECT_EQ(ASCIIToUTF16("I3"), forward_model
->GetLabelAt(index
));
413 // But if we advance one again, it should change.
415 EXPECT_EQ(ASCIIToUTF16("J3"), forward_model
->GetLabelAt(index
));
417 EXPECT_EQ(ASCIIToUTF16("J3"), forward_model
->GetLabelAt(index
));
419 EXPECT_EQ(ASCIIToUTF16("J3"), forward_model
->GetLabelAt(index
));
421 EXPECT_EQ(ASCIIToUTF16("K3"), forward_model
->GetLabelAt(index
));
423 // Now test the boundary cases by using the chapter stop function directly.
424 // Out of bounds, first too far right (incrementing), then too far left.
425 EXPECT_EQ(-1, back_model
->GetIndexOfNextChapterStop(33, false));
426 EXPECT_EQ(-1, back_model
->GetIndexOfNextChapterStop(-1, true));
427 // Test being at end and going right, then at beginning going left.
428 EXPECT_EQ(-1, back_model
->GetIndexOfNextChapterStop(32, true));
429 EXPECT_EQ(-1, back_model
->GetIndexOfNextChapterStop(0, false));
430 // Test success: beginning going right and end going left.
431 EXPECT_EQ(2, back_model
->GetIndexOfNextChapterStop(0, true));
432 EXPECT_EQ(29, back_model
->GetIndexOfNextChapterStop(32, false));
433 // Now see when the chapter stops begin to show up.
434 EXPECT_EQ(-1, back_model
->GetIndexOfNextChapterStop(1, false));
435 EXPECT_EQ(-1, back_model
->GetIndexOfNextChapterStop(2, false));
436 EXPECT_EQ(2, back_model
->GetIndexOfNextChapterStop(3, false));
437 // Now see when the chapter stops end.
438 EXPECT_EQ(32, back_model
->GetIndexOfNextChapterStop(30, true));
439 EXPECT_EQ(32, back_model
->GetIndexOfNextChapterStop(31, true));
440 EXPECT_EQ(-1, back_model
->GetIndexOfNextChapterStop(32, true));
442 // Bug found during review (two different sites, but first wasn't considered
446 LoadURLAndUpdateState("http://www.b.com/1", "B1");
447 EXPECT_EQ(0, back_model
->GetIndexOfNextChapterStop(1, false));
448 EXPECT_EQ(1, back_model
->GetIndexOfNextChapterStop(0, true));
450 // Now see if it counts 'www.x.com' and 'mail.x.com' as same domain, which
454 LoadURLAndUpdateState("http://mail.a.com/2", "A2-mai");
455 LoadURLAndUpdateState("http://www.b.com/1", "B1");
456 LoadURLAndUpdateState("http://mail.b.com/2", "B2-mai");
457 LoadURLAndUpdateState("http://new.site.com", "new");
458 EXPECT_EQ(1, back_model
->GetIndexOfNextChapterStop(0, true));
459 EXPECT_EQ(3, back_model
->GetIndexOfNextChapterStop(1, true));
460 EXPECT_EQ(3, back_model
->GetIndexOfNextChapterStop(2, true));
461 EXPECT_EQ(4, back_model
->GetIndexOfNextChapterStop(3, true));
462 // And try backwards as well.
463 EXPECT_EQ(3, back_model
->GetIndexOfNextChapterStop(4, false));
464 EXPECT_EQ(1, back_model
->GetIndexOfNextChapterStop(3, false));
465 EXPECT_EQ(1, back_model
->GetIndexOfNextChapterStop(2, false));
466 EXPECT_EQ(-1, back_model
->GetIndexOfNextChapterStop(1, false));
469 TEST_F(BackFwdMenuModelTest
, EscapeLabel
) {
470 scoped_ptr
<BackForwardMenuModel
> back_model(new BackForwardMenuModel(
471 NULL
, BackForwardMenuModel::BACKWARD_MENU
));
472 back_model
->set_test_web_contents(web_contents());
474 EXPECT_EQ(0, back_model
->GetItemCount());
475 EXPECT_FALSE(back_model
->ItemHasCommand(1));
477 LoadURLAndUpdateState("http://www.a.com/1", "A B");
478 LoadURLAndUpdateState("http://www.a.com/1", "A & B");
479 LoadURLAndUpdateState("http://www.a.com/2", "A && B");
480 LoadURLAndUpdateState("http://www.a.com/2", "A &&& B");
481 LoadURLAndUpdateState("http://www.a.com/3", "");
483 EXPECT_EQ(6, back_model
->GetItemCount());
485 // On Mac ui::MenuModel::GetLabelAt should return unescaped strings.
486 #if defined(OS_MACOSX)
487 EXPECT_EQ(ASCIIToUTF16("A B"), back_model
->GetLabelAt(3));
488 EXPECT_EQ(ASCIIToUTF16("A & B"), back_model
->GetLabelAt(2));
489 EXPECT_EQ(ASCIIToUTF16("A && B"), back_model
->GetLabelAt(1));
490 EXPECT_EQ(ASCIIToUTF16("A &&& B"), back_model
->GetLabelAt(0));
492 EXPECT_EQ(ASCIIToUTF16("A B"), back_model
->GetLabelAt(3));
493 EXPECT_EQ(ASCIIToUTF16("A && B"), back_model
->GetLabelAt(2));
494 EXPECT_EQ(ASCIIToUTF16("A &&&& B"), back_model
->GetLabelAt(1));
495 EXPECT_EQ(ASCIIToUTF16("A &&&&&& B"), back_model
->GetLabelAt(0));
496 #endif // defined(OS_MACOSX)
499 // Test asynchronous loading of favicon from history service.
500 TEST_F(BackFwdMenuModelTest
, FaviconLoadTest
) {
501 ASSERT_TRUE(profile()->CreateHistoryService(true, false));
502 profile()->CreateFaviconService();
503 Browser::CreateParams
native_params(profile(), chrome::GetActiveDesktop());
504 scoped_ptr
<Browser
> browser(
505 chrome::CreateBrowserWithTestWindowForParams(&native_params
));
506 FaviconDelegate favicon_delegate
;
508 BackForwardMenuModel
back_model(
509 browser
.get(), BackForwardMenuModel::BACKWARD_MENU
);
510 back_model
.set_test_web_contents(controller().GetWebContents());
511 back_model
.SetMenuModelDelegate(&favicon_delegate
);
513 SkBitmap
new_icon_bitmap(CreateBitmap(SK_ColorRED
));
515 GURL url1
= GURL("http://www.a.com/1");
516 GURL url2
= GURL("http://www.a.com/2");
517 GURL
url1_favicon("http://www.a.com/1/favicon.ico");
519 NavigateAndCommit(url1
);
520 // Navigate to a new URL so that url1 will be in the BackForwardMenuModel.
521 NavigateAndCommit(url2
);
523 // Set the desired favicon for url1.
524 HistoryServiceFactory::GetForProfile(
525 profile(), Profile::EXPLICIT_ACCESS
)->AddPage(
526 url1
, base::Time::Now(), history::SOURCE_BROWSED
);
527 FaviconServiceFactory::GetForProfile(
528 profile(), Profile::EXPLICIT_ACCESS
)->SetFavicons(
529 url1
, url1_favicon
, chrome::FAVICON
,
530 gfx::Image::CreateFrom1xBitmap(new_icon_bitmap
));
532 // Will return the current icon (default) but start an anync call
533 // to retrieve the favicon from the favicon service.
534 gfx::Image default_icon
;
535 back_model
.GetIconAt(0, &default_icon
);
537 // Make the favicon service run GetFavIconForURL,
538 // FaviconDelegate.OnIconChanged will be called.
539 base::MessageLoop::current()->Run();
541 // Verify that the callback executed.
542 EXPECT_TRUE(favicon_delegate
.was_called());
544 // Verify the bitmaps match.
545 gfx::Image valid_icon
;
546 // This time we will get the new favicon returned.
547 back_model
.GetIconAt(0, &valid_icon
);
549 SkBitmap default_icon_bitmap
= *default_icon
.ToSkBitmap();
550 SkBitmap valid_icon_bitmap
= *valid_icon
.ToSkBitmap();
552 SkAutoLockPixels
a(new_icon_bitmap
);
553 SkAutoLockPixels
b(valid_icon_bitmap
);
554 SkAutoLockPixels
c(default_icon_bitmap
);
555 // Verify we did not get the default favicon.
556 EXPECT_NE(0, memcmp(default_icon_bitmap
.getPixels(),
557 valid_icon_bitmap
.getPixels(),
558 default_icon_bitmap
.getSize()));
559 // Verify we did get the expected favicon.
560 EXPECT_EQ(0, memcmp(new_icon_bitmap
.getPixels(),
561 valid_icon_bitmap
.getPixels(),
562 new_icon_bitmap
.getSize()));
564 // Make sure the browser deconstructor doesn't have problems.
565 browser
->tab_strip_model()->CloseAllTabs();
566 // This is required to prevent the message loop from hanging.
567 profile()->DestroyHistoryService();