• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/back_forward_menu_model.h"
6 
7 #include "base/path_service.h"
8 #include "base/string_util.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/history/history.h"
11 #include "chrome/browser/profiles/profile_manager.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/common/url_constants.h"
14 #include "chrome/test/testing_profile.h"
15 #include "content/browser/browser_thread.h"
16 #include "content/browser/renderer_host/test_render_view_host.h"
17 #include "content/browser/tab_contents/navigation_controller.h"
18 #include "content/browser/tab_contents/navigation_entry.h"
19 #include "content/browser/tab_contents/tab_contents.h"
20 #include "content/browser/tab_contents/test_tab_contents.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "third_party/skia/include/core/SkBitmap.h"
23 #include "ui/gfx/codec/png_codec.h"
24 
25 namespace {
26 
27 // Creates a bitmap of the specified color.
CreateBitmap(SkColor color)28 SkBitmap CreateBitmap(SkColor color) {
29   SkBitmap bitmap;
30   bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
31   bitmap.allocPixels();
32   bitmap.eraseColor(color);
33   return bitmap;
34 }
35 
36 class FaviconDelegate : public ui::MenuModelDelegate {
37  public:
FaviconDelegate()38   FaviconDelegate() : was_called_(false) {}
39 
OnIconChanged(int model_index)40   void OnIconChanged(int model_index) {
41     was_called_ = true;
42     MessageLoop::current()->Quit();
43   }
44 
was_called() const45   bool was_called() const { return was_called_; }
46 
47  private:
48   bool was_called_;
49 
50   DISALLOW_COPY_AND_ASSIGN(FaviconDelegate);
51 };
52 
53 }  // namespace
54 
55 class BackFwdMenuModelTest : public RenderViewHostTestHarness {
56  public:
BackFwdMenuModelTest()57   BackFwdMenuModelTest()
58       : ui_thread_(BrowserThread::UI, &message_loop_) {
59   }
60 
ValidateModel(BackForwardMenuModel * model,int history_items,int chapter_stops)61   void ValidateModel(BackForwardMenuModel* model, int history_items,
62                      int chapter_stops) {
63     int h = std::min(BackForwardMenuModel::kMaxHistoryItems, history_items);
64     int c = std::min(BackForwardMenuModel::kMaxChapterStops, chapter_stops);
65     EXPECT_EQ(h, model->GetHistoryItemCount());
66     EXPECT_EQ(c, model->GetChapterStopCount(h));
67     if (h > 0)
68       h += 2;  // Separator and View History link.
69     if (c > 0)
70       ++c;
71     EXPECT_EQ(h + c, model->GetItemCount());
72   }
73 
LoadURLAndUpdateState(const char * url,const char * title)74   void LoadURLAndUpdateState(const char* url, const char* title) {
75     NavigateAndCommit(GURL(url));
76     controller().GetLastCommittedEntry()->set_title(UTF8ToUTF16(title));
77   }
78 
79   // Navigate back or forward the given amount and commits the entry (which
80   // will be pending after we ask to navigate there).
NavigateToOffset(int offset)81   void NavigateToOffset(int offset) {
82     controller().GoToOffset(offset);
83     contents()->CommitPendingNavigation();
84   }
85 
86   // Same as NavigateToOffset but goes to an absolute index.
NavigateToIndex(int index)87   void NavigateToIndex(int index) {
88     controller().GoToIndex(index);
89     contents()->CommitPendingNavigation();
90   }
91 
92   // Goes back/forward and commits the load.
GoBack()93   void GoBack() {
94     controller().GoBack();
95     contents()->CommitPendingNavigation();
96   }
GoForward()97   void GoForward() {
98     controller().GoForward();
99     contents()->CommitPendingNavigation();
100   }
101 
102   BrowserThread ui_thread_;
103 };
104 
TEST_F(BackFwdMenuModelTest,BasicCase)105 TEST_F(BackFwdMenuModelTest, BasicCase) {
106   scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel(
107       NULL, BackForwardMenuModel::BACKWARD_MENU));
108   back_model->set_test_tab_contents(contents());
109 
110   scoped_ptr<BackForwardMenuModel> forward_model(new BackForwardMenuModel(
111       NULL, BackForwardMenuModel::FORWARD_MENU));
112   forward_model->set_test_tab_contents(contents());
113 
114   EXPECT_EQ(0, back_model->GetItemCount());
115   EXPECT_EQ(0, forward_model->GetItemCount());
116   EXPECT_FALSE(back_model->ItemHasCommand(1));
117 
118   // Seed the controller with a few URLs
119   LoadURLAndUpdateState("http://www.a.com/1", "A1");
120   LoadURLAndUpdateState("http://www.a.com/2", "A2");
121   LoadURLAndUpdateState("http://www.a.com/3", "A3");
122   LoadURLAndUpdateState("http://www.b.com/1", "B1");
123   LoadURLAndUpdateState("http://www.b.com/2", "B2");
124   LoadURLAndUpdateState("http://www.c.com/1", "C1");
125   LoadURLAndUpdateState("http://www.c.com/2", "C2");
126   LoadURLAndUpdateState("http://www.c.com/3", "C3");
127 
128   // There're two more items here: a separator and a "Show Full History".
129   EXPECT_EQ(9, back_model->GetItemCount());
130   EXPECT_EQ(0, forward_model->GetItemCount());
131   EXPECT_EQ(ASCIIToUTF16("C2"), back_model->GetLabelAt(0));
132   EXPECT_EQ(ASCIIToUTF16("A1"), back_model->GetLabelAt(6));
133   EXPECT_EQ(back_model->GetShowFullHistoryLabel(),
134             back_model->GetLabelAt(8));
135 
136   EXPECT_TRUE(back_model->ItemHasCommand(0));
137   EXPECT_TRUE(back_model->ItemHasCommand(6));
138   EXPECT_TRUE(back_model->IsSeparator(7));
139   EXPECT_TRUE(back_model->ItemHasCommand(8));
140   EXPECT_FALSE(back_model->ItemHasCommand(9));
141   EXPECT_FALSE(back_model->ItemHasCommand(9));
142 
143   NavigateToOffset(-7);
144 
145   EXPECT_EQ(0, back_model->GetItemCount());
146   EXPECT_EQ(9, forward_model->GetItemCount());
147   EXPECT_EQ(ASCIIToUTF16("A2"), forward_model->GetLabelAt(0));
148   EXPECT_EQ(ASCIIToUTF16("C3"), forward_model->GetLabelAt(6));
149   EXPECT_EQ(forward_model->GetShowFullHistoryLabel(),
150             forward_model->GetLabelAt(8));
151 
152   EXPECT_TRUE(forward_model->ItemHasCommand(0));
153   EXPECT_TRUE(forward_model->ItemHasCommand(6));
154   EXPECT_TRUE(forward_model->IsSeparator(7));
155   EXPECT_TRUE(forward_model->ItemHasCommand(8));
156   EXPECT_FALSE(forward_model->ItemHasCommand(7));
157   EXPECT_FALSE(forward_model->ItemHasCommand(9));
158 
159   NavigateToOffset(4);
160 
161   EXPECT_EQ(6, back_model->GetItemCount());
162   EXPECT_EQ(5, forward_model->GetItemCount());
163   EXPECT_EQ(ASCIIToUTF16("B1"), back_model->GetLabelAt(0));
164   EXPECT_EQ(ASCIIToUTF16("A1"), back_model->GetLabelAt(3));
165   EXPECT_EQ(back_model->GetShowFullHistoryLabel(),
166             back_model->GetLabelAt(5));
167   EXPECT_EQ(ASCIIToUTF16("C1"), forward_model->GetLabelAt(0));
168   EXPECT_EQ(ASCIIToUTF16("C3"), forward_model->GetLabelAt(2));
169   EXPECT_EQ(forward_model->GetShowFullHistoryLabel(),
170             forward_model->GetLabelAt(4));
171 }
172 
TEST_F(BackFwdMenuModelTest,MaxItemsTest)173 TEST_F(BackFwdMenuModelTest, MaxItemsTest) {
174   scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel(
175       NULL, BackForwardMenuModel::BACKWARD_MENU));
176   back_model->set_test_tab_contents(contents());
177 
178   scoped_ptr<BackForwardMenuModel> forward_model(new BackForwardMenuModel(
179       NULL, BackForwardMenuModel::FORWARD_MENU));
180   forward_model->set_test_tab_contents(contents());
181 
182   // Seed the controller with 32 URLs
183   LoadURLAndUpdateState("http://www.a.com/1", "A1");
184   LoadURLAndUpdateState("http://www.a.com/2", "A2");
185   LoadURLAndUpdateState("http://www.a.com/3", "A3");
186   LoadURLAndUpdateState("http://www.b.com/1", "B1");
187   LoadURLAndUpdateState("http://www.b.com/2", "B2");
188   LoadURLAndUpdateState("http://www.b.com/3", "B3");
189   LoadURLAndUpdateState("http://www.c.com/1", "C1");
190   LoadURLAndUpdateState("http://www.c.com/2", "C2");
191   LoadURLAndUpdateState("http://www.c.com/3", "C3");
192   LoadURLAndUpdateState("http://www.d.com/1", "D1");
193   LoadURLAndUpdateState("http://www.d.com/2", "D2");
194   LoadURLAndUpdateState("http://www.d.com/3", "D3");
195   LoadURLAndUpdateState("http://www.e.com/1", "E1");
196   LoadURLAndUpdateState("http://www.e.com/2", "E2");
197   LoadURLAndUpdateState("http://www.e.com/3", "E3");
198   LoadURLAndUpdateState("http://www.f.com/1", "F1");
199   LoadURLAndUpdateState("http://www.f.com/2", "F2");
200   LoadURLAndUpdateState("http://www.f.com/3", "F3");
201   LoadURLAndUpdateState("http://www.g.com/1", "G1");
202   LoadURLAndUpdateState("http://www.g.com/2", "G2");
203   LoadURLAndUpdateState("http://www.g.com/3", "G3");
204   LoadURLAndUpdateState("http://www.h.com/1", "H1");
205   LoadURLAndUpdateState("http://www.h.com/2", "H2");
206   LoadURLAndUpdateState("http://www.h.com/3", "H3");
207   LoadURLAndUpdateState("http://www.i.com/1", "I1");
208   LoadURLAndUpdateState("http://www.i.com/2", "I2");
209   LoadURLAndUpdateState("http://www.i.com/3", "I3");
210   LoadURLAndUpdateState("http://www.j.com/1", "J1");
211   LoadURLAndUpdateState("http://www.j.com/2", "J2");
212   LoadURLAndUpdateState("http://www.j.com/3", "J3");
213   LoadURLAndUpdateState("http://www.k.com/1", "K1");
214   LoadURLAndUpdateState("http://www.k.com/2", "K2");
215 
216   // Also there're two more for a separator and a "Show Full History".
217   int chapter_stop_offset = 6;
218   EXPECT_EQ(BackForwardMenuModel::kMaxHistoryItems + 2 + chapter_stop_offset,
219             back_model->GetItemCount());
220   EXPECT_EQ(0, forward_model->GetItemCount());
221   EXPECT_EQ(ASCIIToUTF16("K1"), back_model->GetLabelAt(0));
222   EXPECT_EQ(back_model->GetShowFullHistoryLabel(),
223       back_model->GetLabelAt(BackForwardMenuModel::kMaxHistoryItems + 1 +
224                                chapter_stop_offset));
225 
226   // Test for out of bounds (beyond Show Full History).
227   EXPECT_FALSE(back_model->ItemHasCommand(
228       BackForwardMenuModel::kMaxHistoryItems + chapter_stop_offset + 2));
229 
230   EXPECT_TRUE(back_model->ItemHasCommand(
231               BackForwardMenuModel::kMaxHistoryItems - 1));
232   EXPECT_TRUE(back_model->IsSeparator(
233               BackForwardMenuModel::kMaxHistoryItems));
234 
235   NavigateToIndex(0);
236 
237   EXPECT_EQ(BackForwardMenuModel::kMaxHistoryItems + 2 + chapter_stop_offset,
238             forward_model->GetItemCount());
239   EXPECT_EQ(0, back_model->GetItemCount());
240   EXPECT_EQ(ASCIIToUTF16("A2"), forward_model->GetLabelAt(0));
241   EXPECT_EQ(forward_model->GetShowFullHistoryLabel(),
242       forward_model->GetLabelAt(BackForwardMenuModel::kMaxHistoryItems + 1 +
243                                     chapter_stop_offset));
244 
245   // Out of bounds
246   EXPECT_FALSE(forward_model->ItemHasCommand(
247       BackForwardMenuModel::kMaxHistoryItems + 2 + chapter_stop_offset));
248 
249   EXPECT_TRUE(forward_model->ItemHasCommand(
250       BackForwardMenuModel::kMaxHistoryItems - 1));
251   EXPECT_TRUE(forward_model->IsSeparator(
252       BackForwardMenuModel::kMaxHistoryItems));
253 }
254 
TEST_F(BackFwdMenuModelTest,ChapterStops)255 TEST_F(BackFwdMenuModelTest, ChapterStops) {
256   scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel(
257     NULL, BackForwardMenuModel::BACKWARD_MENU));
258   back_model->set_test_tab_contents(contents());
259 
260   scoped_ptr<BackForwardMenuModel> forward_model(new BackForwardMenuModel(
261       NULL, BackForwardMenuModel::FORWARD_MENU));
262   forward_model->set_test_tab_contents(contents());
263 
264   // Seed the controller with 32 URLs.
265   int i = 0;
266   LoadURLAndUpdateState("http://www.a.com/1", "A1");
267   ValidateModel(back_model.get(), i++, 0);
268   LoadURLAndUpdateState("http://www.a.com/2", "A2");
269   ValidateModel(back_model.get(), i++, 0);
270   LoadURLAndUpdateState("http://www.a.com/3", "A3");
271   ValidateModel(back_model.get(), i++, 0);
272   LoadURLAndUpdateState("http://www.b.com/1", "B1");
273   ValidateModel(back_model.get(), i++, 0);
274   LoadURLAndUpdateState("http://www.b.com/2", "B2");
275   ValidateModel(back_model.get(), i++, 0);
276   // i = 5
277   LoadURLAndUpdateState("http://www.b.com/3", "B3");
278   ValidateModel(back_model.get(), i++, 0);
279   LoadURLAndUpdateState("http://www.c.com/1", "C1");
280   ValidateModel(back_model.get(), i++, 0);
281   LoadURLAndUpdateState("http://www.c.com/2", "C2");
282   ValidateModel(back_model.get(), i++, 0);
283   LoadURLAndUpdateState("http://www.c.com/3", "C3");
284   ValidateModel(back_model.get(), i++, 0);
285   LoadURLAndUpdateState("http://www.d.com/1", "D1");
286   ValidateModel(back_model.get(), i++, 0);
287   // i = 10
288   LoadURLAndUpdateState("http://www.d.com/2", "D2");
289   ValidateModel(back_model.get(), i++, 0);
290   LoadURLAndUpdateState("http://www.d.com/3", "D3");
291   ValidateModel(back_model.get(), i++, 0);
292   LoadURLAndUpdateState("http://www.e.com/1", "E1");
293   ValidateModel(back_model.get(), i++, 0);
294   LoadURLAndUpdateState("http://www.e.com/2", "E2");
295   ValidateModel(back_model.get(), i++, 0);
296   LoadURLAndUpdateState("http://www.e.com/3", "E3");
297   ValidateModel(back_model.get(), i++, 0);
298   // i = 15
299   LoadURLAndUpdateState("http://www.f.com/1", "F1");
300   ValidateModel(back_model.get(), i++, 1);
301   LoadURLAndUpdateState("http://www.f.com/2", "F2");
302   ValidateModel(back_model.get(), i++, 1);
303   LoadURLAndUpdateState("http://www.f.com/3", "F3");
304   ValidateModel(back_model.get(), i++, 1);
305   LoadURLAndUpdateState("http://www.g.com/1", "G1");
306   ValidateModel(back_model.get(), i++, 2);
307   LoadURLAndUpdateState("http://www.g.com/2", "G2");
308   ValidateModel(back_model.get(), i++, 2);
309   // i = 20
310   LoadURLAndUpdateState("http://www.g.com/3", "G3");
311   ValidateModel(back_model.get(), i++, 2);
312   LoadURLAndUpdateState("http://www.h.com/1", "H1");
313   ValidateModel(back_model.get(), i++, 3);
314   LoadURLAndUpdateState("http://www.h.com/2", "H2");
315   ValidateModel(back_model.get(), i++, 3);
316   LoadURLAndUpdateState("http://www.h.com/3", "H3");
317   ValidateModel(back_model.get(), i++, 3);
318   LoadURLAndUpdateState("http://www.i.com/1", "I1");
319   ValidateModel(back_model.get(), i++, 4);
320   // i = 25
321   LoadURLAndUpdateState("http://www.i.com/2", "I2");
322   ValidateModel(back_model.get(), i++, 4);
323   LoadURLAndUpdateState("http://www.i.com/3", "I3");
324   ValidateModel(back_model.get(), i++, 4);
325   LoadURLAndUpdateState("http://www.j.com/1", "J1");
326   ValidateModel(back_model.get(), i++, 5);
327   LoadURLAndUpdateState("http://www.j.com/2", "J2");
328   ValidateModel(back_model.get(), i++, 5);
329   LoadURLAndUpdateState("http://www.j.com/3", "J3");
330   ValidateModel(back_model.get(), i++, 5);
331   // i = 30
332   LoadURLAndUpdateState("http://www.k.com/1", "K1");
333   ValidateModel(back_model.get(), i++, 6);
334   LoadURLAndUpdateState("http://www.k.com/2", "K2");
335   ValidateModel(back_model.get(), i++, 6);
336   // i = 32
337   LoadURLAndUpdateState("http://www.k.com/3", "K3");
338   ValidateModel(back_model.get(), i++, 6);
339 
340   // A chapter stop is defined as the last page the user
341   // browsed to within the same domain.
342 
343   // Check to see if the chapter stops have the right labels.
344   int index = BackForwardMenuModel::kMaxHistoryItems;
345   // Empty string indicates item is a separator.
346   EXPECT_EQ(ASCIIToUTF16(""), back_model->GetLabelAt(index++));
347   EXPECT_EQ(ASCIIToUTF16("F3"), back_model->GetLabelAt(index++));
348   EXPECT_EQ(ASCIIToUTF16("E3"), back_model->GetLabelAt(index++));
349   EXPECT_EQ(ASCIIToUTF16("D3"), back_model->GetLabelAt(index++));
350   EXPECT_EQ(ASCIIToUTF16("C3"), back_model->GetLabelAt(index++));
351   // The menu should only show a maximum of 5 chapter stops.
352   EXPECT_EQ(ASCIIToUTF16("B3"), back_model->GetLabelAt(index));
353   // Empty string indicates item is a separator.
354   EXPECT_EQ(ASCIIToUTF16(""), back_model->GetLabelAt(index + 1));
355   EXPECT_EQ(back_model->GetShowFullHistoryLabel(),
356             back_model->GetLabelAt(index + 2));
357 
358   // If we go back two we should still see the same chapter stop at the end.
359   GoBack();
360   EXPECT_EQ(ASCIIToUTF16("B3"), back_model->GetLabelAt(index));
361   GoBack();
362   EXPECT_EQ(ASCIIToUTF16("B3"), back_model->GetLabelAt(index));
363   // But if we go back again, it should change.
364   GoBack();
365   EXPECT_EQ(ASCIIToUTF16("A3"), back_model->GetLabelAt(index));
366   GoBack();
367   EXPECT_EQ(ASCIIToUTF16("A3"), back_model->GetLabelAt(index));
368   GoBack();
369   EXPECT_EQ(ASCIIToUTF16("A3"), back_model->GetLabelAt(index));
370   GoBack();
371   // It is now a separator.
372   EXPECT_EQ(ASCIIToUTF16(""), back_model->GetLabelAt(index));
373   // Undo our position change.
374   NavigateToOffset(6);
375 
376   // Go back enough to make sure no chapter stops should appear.
377   NavigateToOffset(-BackForwardMenuModel::kMaxHistoryItems);
378   ValidateModel(forward_model.get(), BackForwardMenuModel::kMaxHistoryItems, 0);
379   // Go forward (still no chapter stop)
380   GoForward();
381   ValidateModel(forward_model.get(),
382                 BackForwardMenuModel::kMaxHistoryItems - 1, 0);
383   // Go back two (one chapter stop should show up)
384   GoBack();
385   GoBack();
386   ValidateModel(forward_model.get(),
387                 BackForwardMenuModel::kMaxHistoryItems, 1);
388 
389   // Go to beginning.
390   NavigateToIndex(0);
391 
392   // Check to see if the chapter stops have the right labels.
393   index = BackForwardMenuModel::kMaxHistoryItems;
394   // Empty string indicates item is a separator.
395   EXPECT_EQ(ASCIIToUTF16(""), forward_model->GetLabelAt(index++));
396   EXPECT_EQ(ASCIIToUTF16("E3"), forward_model->GetLabelAt(index++));
397   EXPECT_EQ(ASCIIToUTF16("F3"), forward_model->GetLabelAt(index++));
398   EXPECT_EQ(ASCIIToUTF16("G3"), forward_model->GetLabelAt(index++));
399   EXPECT_EQ(ASCIIToUTF16("H3"), forward_model->GetLabelAt(index++));
400   // The menu should only show a maximum of 5 chapter stops.
401   EXPECT_EQ(ASCIIToUTF16("I3"), forward_model->GetLabelAt(index));
402   // Empty string indicates item is a separator.
403   EXPECT_EQ(ASCIIToUTF16(""), forward_model->GetLabelAt(index + 1));
404   EXPECT_EQ(forward_model->GetShowFullHistoryLabel(),
405       forward_model->GetLabelAt(index + 2));
406 
407   // If we advance one we should still see the same chapter stop at the end.
408   GoForward();
409   EXPECT_EQ(ASCIIToUTF16("I3"), forward_model->GetLabelAt(index));
410   // But if we advance one again, it should change.
411   GoForward();
412   EXPECT_EQ(ASCIIToUTF16("J3"), forward_model->GetLabelAt(index));
413   GoForward();
414   EXPECT_EQ(ASCIIToUTF16("J3"), forward_model->GetLabelAt(index));
415   GoForward();
416   EXPECT_EQ(ASCIIToUTF16("J3"), forward_model->GetLabelAt(index));
417   GoForward();
418   EXPECT_EQ(ASCIIToUTF16("K3"), forward_model->GetLabelAt(index));
419 
420   // Now test the boundary cases by using the chapter stop function directly.
421   // Out of bounds, first too far right (incrementing), then too far left.
422   EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(33, false));
423   EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(-1, true));
424   // Test being at end and going right, then at beginning going left.
425   EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(32, true));
426   EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(0, false));
427   // Test success: beginning going right and end going left.
428   EXPECT_EQ(2,  back_model->GetIndexOfNextChapterStop(0, true));
429   EXPECT_EQ(29, back_model->GetIndexOfNextChapterStop(32, false));
430   // Now see when the chapter stops begin to show up.
431   EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(1, false));
432   EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(2, false));
433   EXPECT_EQ(2,  back_model->GetIndexOfNextChapterStop(3, false));
434   // Now see when the chapter stops end.
435   EXPECT_EQ(32, back_model->GetIndexOfNextChapterStop(30, true));
436   EXPECT_EQ(32, back_model->GetIndexOfNextChapterStop(31, true));
437   EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(32, true));
438 
439   // Bug found during review (two different sites, but first wasn't considered
440   // a chapter-stop).
441   // Go to A1;
442   NavigateToIndex(0);
443   LoadURLAndUpdateState("http://www.b.com/1", "B1");
444   EXPECT_EQ(0, back_model->GetIndexOfNextChapterStop(1, false));
445   EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(0, true));
446 
447   // Now see if it counts 'www.x.com' and 'mail.x.com' as same domain, which
448   // it should.
449   // Go to A1.
450   NavigateToIndex(0);
451   LoadURLAndUpdateState("http://mail.a.com/2", "A2-mai");
452   LoadURLAndUpdateState("http://www.b.com/1", "B1");
453   LoadURLAndUpdateState("http://mail.b.com/2", "B2-mai");
454   LoadURLAndUpdateState("http://new.site.com", "new");
455   EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(0, true));
456   EXPECT_EQ(3, back_model->GetIndexOfNextChapterStop(1, true));
457   EXPECT_EQ(3, back_model->GetIndexOfNextChapterStop(2, true));
458   EXPECT_EQ(4, back_model->GetIndexOfNextChapterStop(3, true));
459   // And try backwards as well.
460   EXPECT_EQ(3, back_model->GetIndexOfNextChapterStop(4, false));
461   EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(3, false));
462   EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(2, false));
463   EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(1, false));
464 }
465 
TEST_F(BackFwdMenuModelTest,EscapeLabel)466 TEST_F(BackFwdMenuModelTest, EscapeLabel) {
467   scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel(
468       NULL, BackForwardMenuModel::BACKWARD_MENU));
469   back_model->set_test_tab_contents(contents());
470 
471   EXPECT_EQ(0, back_model->GetItemCount());
472   EXPECT_FALSE(back_model->ItemHasCommand(1));
473 
474   LoadURLAndUpdateState("http://www.a.com/1", "A B");
475   LoadURLAndUpdateState("http://www.a.com/1", "A & B");
476   LoadURLAndUpdateState("http://www.a.com/2", "A && B");
477   LoadURLAndUpdateState("http://www.a.com/2", "A &&& B");
478   LoadURLAndUpdateState("http://www.a.com/3", "");
479 
480   EXPECT_EQ(6, back_model->GetItemCount());
481 
482   // On Mac ui::MenuModel::GetLabelAt should return unescaped strings.
483 #if defined(OS_MACOSX)
484   EXPECT_EQ(ASCIIToUTF16("A B"), back_model->GetLabelAt(3));
485   EXPECT_EQ(ASCIIToUTF16("A & B"), back_model->GetLabelAt(2));
486   EXPECT_EQ(ASCIIToUTF16("A && B"), back_model->GetLabelAt(1));
487   EXPECT_EQ(ASCIIToUTF16("A &&& B"), back_model->GetLabelAt(0));
488 #else
489   EXPECT_EQ(ASCIIToUTF16("A B"), back_model->GetLabelAt(3));
490   EXPECT_EQ(ASCIIToUTF16("A && B"), back_model->GetLabelAt(2));
491   EXPECT_EQ(ASCIIToUTF16("A &&&& B"), back_model->GetLabelAt(1));
492   EXPECT_EQ(ASCIIToUTF16("A &&&&&& B"), back_model->GetLabelAt(0));
493 #endif // defined(OS_MACOSX)
494 }
495 
496 // Test asynchronous loading of favicon from history service.
TEST_F(BackFwdMenuModelTest,FaviconLoadTest)497 TEST_F(BackFwdMenuModelTest, FaviconLoadTest) {
498   profile()->CreateHistoryService(true, false);
499   profile()->CreateFaviconService();
500   Browser browser(Browser::TYPE_NORMAL, profile());
501   FaviconDelegate favicon_delegate;
502 
503   BackForwardMenuModel back_model(
504       &browser, BackForwardMenuModel::BACKWARD_MENU);
505   back_model.set_test_tab_contents(controller().tab_contents());
506   back_model.SetMenuModelDelegate(&favicon_delegate);
507 
508   SkBitmap new_icon(CreateBitmap(SK_ColorRED));
509   std::vector<unsigned char> icon_data;
510   gfx::PNGCodec::EncodeBGRASkBitmap(new_icon, false, &icon_data);
511 
512   GURL url1 = GURL("http://www.a.com/1");
513   GURL url2 = GURL("http://www.a.com/2");
514   GURL url1_favicon("http://www.a.com/1/favicon.ico");
515 
516   NavigateAndCommit(url1);
517   // Navigate to a new URL so that url1 will be in the BackForwardMenuModel.
518   NavigateAndCommit(url2);
519 
520   // Set the desired favicon for url1.
521   profile()->GetHistoryService(Profile::EXPLICIT_ACCESS)->AddPage(url1,
522       history::SOURCE_BROWSED);
523   profile()->GetFaviconService(Profile::EXPLICIT_ACCESS)->SetFavicon(url1,
524       url1_favicon, icon_data, history::FAVICON);
525 
526   // Will return the current icon (default) but start an anync call
527   // to retrieve the favicon from the favicon service.
528   SkBitmap default_icon;
529   back_model.GetIconAt(0, &default_icon);
530 
531   // Make the favicon service run GetFavIconForURL,
532   // FaviconDelegate.OnIconChanged will be called.
533   MessageLoop::current()->Run();
534 
535   // Verify that the callback executed.
536   EXPECT_TRUE(favicon_delegate.was_called());
537 
538   // Verify the bitmaps match.
539   SkBitmap valid_icon;
540   // This time we will get the new favicon returned.
541   back_model.GetIconAt(0, &valid_icon);
542   SkAutoLockPixels a(new_icon);
543   SkAutoLockPixels b(valid_icon);
544   SkAutoLockPixels c(default_icon);
545   // Verify we did not get the default favicon.
546   EXPECT_NE(0, memcmp(default_icon.getPixels(), valid_icon.getPixels(),
547                default_icon.getSize()));
548   // Verify we did get the expected favicon.
549   EXPECT_EQ(0, memcmp(new_icon.getPixels(), valid_icon.getPixels(),
550               new_icon.getSize()));
551 
552   // Make sure the browser deconstructor doesn't have problems.
553   browser.CloseAllTabs();
554   // This is required to prevent the message loop from hanging.
555   profile()->DestroyHistoryService();
556 }
557 
558