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 "base/memory/scoped_ptr.h"
6#include "chrome/browser/instant/instant_loader.h"
7#include "chrome/browser/instant/instant_loader_delegate.h"
8#include "chrome/browser/instant/instant_loader_manager.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11namespace {
12
13class InstantLoaderDelegateImpl : public InstantLoaderDelegate {
14 public:
15  InstantLoaderDelegateImpl() {}
16
17  virtual void InstantStatusChanged(InstantLoader* loader) OVERRIDE {}
18
19  virtual void SetSuggestedTextFor(InstantLoader* loader,
20                                   const string16& text,
21                                   InstantCompleteBehavior behavior) OVERRIDE {}
22
23  virtual gfx::Rect GetInstantBounds() OVERRIDE {
24    return gfx::Rect();
25  }
26
27  virtual bool ShouldCommitInstantOnMouseUp() OVERRIDE {
28    return false;
29  }
30
31  virtual void CommitInstantLoader(InstantLoader* loader) OVERRIDE {
32  }
33
34  virtual void InstantLoaderDoesntSupportInstant(
35      InstantLoader* loader) OVERRIDE {
36  }
37
38  virtual void AddToBlacklist(InstantLoader* loader,
39                              const GURL& url) OVERRIDE {
40  }
41
42 private:
43  DISALLOW_COPY_AND_ASSIGN(InstantLoaderDelegateImpl);
44};
45
46}
47
48class InstantLoaderManagerTest : public testing::Test {
49 public:
50  InstantLoaderManagerTest() {}
51
52  void MarkReady(InstantLoader* loader) {
53    loader->ready_ = true;
54  }
55
56 private:
57  DISALLOW_COPY_AND_ASSIGN(InstantLoaderManagerTest);
58};
59
60// Makes sure UpdateLoader works when invoked once.
61TEST_F(InstantLoaderManagerTest, Basic) {
62  InstantLoaderDelegateImpl delegate;
63  InstantLoaderManager manager(&delegate);
64  scoped_ptr<InstantLoader> loader;
65  manager.UpdateLoader(0, &loader);
66  EXPECT_EQ(NULL, loader.get());
67  EXPECT_TRUE(manager.current_loader());
68  EXPECT_EQ(NULL, manager.pending_loader());
69  EXPECT_EQ(0, manager.current_loader()->template_url_id());
70}
71
72// Make sure invoking update twice for non-instant results keeps the same
73// loader.
74TEST_F(InstantLoaderManagerTest, UpdateTwice) {
75  InstantLoaderDelegateImpl delegate;
76  InstantLoaderManager manager(&delegate);
77  scoped_ptr<InstantLoader> loader;
78  manager.UpdateLoader(0, &loader);
79  InstantLoader* current_loader = manager.current_loader();
80  manager.UpdateLoader(0, &loader);
81  EXPECT_EQ(NULL, loader.get());
82  EXPECT_EQ(current_loader, manager.current_loader());
83  EXPECT_EQ(NULL, manager.pending_loader());
84}
85
86// Make sure invoking update twice for instant results keeps the same loader.
87TEST_F(InstantLoaderManagerTest, UpdateInstantTwice) {
88  InstantLoaderDelegateImpl delegate;
89  InstantLoaderManager manager(&delegate);
90  scoped_ptr<InstantLoader> loader;
91  manager.UpdateLoader(1, &loader);
92  InstantLoader* current_loader = manager.current_loader();
93  manager.UpdateLoader(1, &loader);
94  EXPECT_EQ(NULL, loader.get());
95  EXPECT_EQ(current_loader, manager.current_loader());
96  EXPECT_EQ(NULL, manager.pending_loader());
97  EXPECT_EQ(1u, manager.num_instant_loaders());
98}
99
100// Makes sure transitioning from non-instant to instant works.
101TEST_F(InstantLoaderManagerTest, NonInstantToInstant) {
102  InstantLoaderDelegateImpl delegate;
103  InstantLoaderManager manager(&delegate);
104  scoped_ptr<InstantLoader> loader;
105  manager.UpdateLoader(0, &loader);
106  InstantLoader* current_loader = manager.current_loader();
107  manager.UpdateLoader(1, &loader);
108  EXPECT_TRUE(loader.get() != NULL);
109  EXPECT_NE(current_loader, manager.current_loader());
110  EXPECT_EQ(NULL, manager.pending_loader());
111  EXPECT_EQ(1u, manager.num_instant_loaders());
112}
113
114// Makes sure instant loaders aren't deleted when invoking update with different
115// ids.
116TEST_F(InstantLoaderManagerTest, DontDeleteInstantLoaders) {
117  InstantLoaderDelegateImpl delegate;
118  InstantLoaderManager manager(&delegate);
119  scoped_ptr<InstantLoader> loader;
120  manager.UpdateLoader(1, &loader);
121  InstantLoader* current_loader = manager.current_loader();
122  manager.UpdateLoader(2, &loader);
123  EXPECT_EQ(NULL, loader.get());
124  EXPECT_NE(current_loader, manager.current_loader());
125  EXPECT_EQ(NULL, manager.pending_loader());
126  EXPECT_EQ(2u, manager.num_instant_loaders());
127}
128
129// Makes sure a new loader is created and assigned to secondary when
130// transitioning from a ready non-instant to instant.
131TEST_F(InstantLoaderManagerTest, CreateSecondaryWhenReady) {
132  InstantLoaderDelegateImpl delegate;
133  InstantLoaderManager manager(&delegate);
134  scoped_ptr<InstantLoader> loader;
135  manager.UpdateLoader(0, &loader);
136  InstantLoader* current_loader = manager.current_loader();
137  ASSERT_TRUE(current_loader);
138  MarkReady(current_loader);
139
140  manager.UpdateLoader(1, &loader);
141  EXPECT_EQ(NULL, loader.get());
142  EXPECT_EQ(current_loader, manager.current_loader());
143  EXPECT_TRUE(manager.pending_loader());
144  EXPECT_NE(current_loader, manager.pending_loader());
145  EXPECT_EQ(1u, manager.num_instant_loaders());
146
147  // Make the pending loader current.
148  InstantLoader* pending_loader = manager.pending_loader();
149  manager.MakePendingCurrent(&loader);
150  EXPECT_TRUE(loader.get());
151  EXPECT_EQ(pending_loader, manager.current_loader());
152  EXPECT_EQ(NULL, manager.pending_loader());
153  EXPECT_EQ(1u, manager.num_instant_loaders());
154}
155
156// Makes sure releasing an instant updates maps currectly.
157TEST_F(InstantLoaderManagerTest, ReleaseInstant) {
158  InstantLoaderDelegateImpl delegate;
159  InstantLoaderManager manager(&delegate);
160  scoped_ptr<InstantLoader> loader;
161  manager.UpdateLoader(1, &loader);
162  scoped_ptr<InstantLoader> current_loader(manager.ReleaseCurrentLoader());
163  EXPECT_TRUE(current_loader.get());
164  EXPECT_EQ(NULL, manager.current_loader());
165  EXPECT_EQ(0u, manager.num_instant_loaders());
166}
167
168// Tests transitioning from a non-instant ready loader to an instant ready
169// loader is immediate.
170TEST_F(InstantLoaderManagerTest, NonInstantToInstantWhenReady) {
171  InstantLoaderDelegateImpl delegate;
172  InstantLoaderManager manager(&delegate);
173  scoped_ptr<InstantLoader> loader;
174  manager.UpdateLoader(1, &loader);
175  ASSERT_TRUE(manager.current_loader());
176  EXPECT_EQ(1, manager.current_loader()->template_url_id());
177  InstantLoader* instant_loader = manager.current_loader();
178
179  manager.UpdateLoader(0, &loader);
180  InstantLoader* non_instant_loader = manager.current_loader();
181  ASSERT_TRUE(non_instant_loader);
182  MarkReady(non_instant_loader);
183  EXPECT_NE(non_instant_loader, instant_loader);
184
185  MarkReady(instant_loader);
186  manager.UpdateLoader(1, &loader);
187  EXPECT_EQ(non_instant_loader, loader.get());
188  EXPECT_EQ(instant_loader, manager.current_loader());
189  EXPECT_EQ(NULL, manager.pending_loader());
190  EXPECT_EQ(1u, manager.num_instant_loaders());
191}
192
193// Tests transitioning between 3 instant loaders, all ready.
194TEST_F(InstantLoaderManagerTest, ThreeInstant) {
195  InstantLoaderDelegateImpl delegate;
196  InstantLoaderManager manager(&delegate);
197  scoped_ptr<InstantLoader> loader;
198  manager.UpdateLoader(1, &loader);
199  ASSERT_TRUE(manager.current_loader());
200  EXPECT_EQ(1, manager.current_loader()->template_url_id());
201  InstantLoader* instant_loader1 = manager.current_loader();
202  MarkReady(instant_loader1);
203
204  manager.UpdateLoader(2, &loader);
205  InstantLoader* instant_loader2 = manager.pending_loader();
206  ASSERT_TRUE(instant_loader2);
207  EXPECT_EQ(2, instant_loader2->template_url_id());
208  EXPECT_NE(instant_loader1, instant_loader2);
209  EXPECT_EQ(instant_loader1, manager.current_loader());
210
211  manager.UpdateLoader(3, &loader);
212  InstantLoader* instant_loader3 = manager.pending_loader();
213  ASSERT_TRUE(instant_loader3);
214  EXPECT_EQ(3, instant_loader3->template_url_id());
215  EXPECT_NE(instant_loader1, instant_loader3);
216  EXPECT_NE(instant_loader2, instant_loader3);
217  EXPECT_EQ(instant_loader1, manager.current_loader());
218}
219
220// Tests DestroyLoader with an instant loader.
221TEST_F(InstantLoaderManagerTest, DestroyInstantLoader) {
222  InstantLoaderDelegateImpl delegate;
223  InstantLoaderManager manager(&delegate);
224  scoped_ptr<InstantLoader> loader;
225  manager.UpdateLoader(1, &loader);
226  ASSERT_TRUE(manager.current_loader());
227  EXPECT_EQ(1, manager.current_loader()->template_url_id());
228  // Now destroy it.
229  manager.DestroyLoader(manager.current_loader());
230
231  // There should be no current, pending and 0 instant loaders.
232  ASSERT_EQ(NULL, manager.current_loader());
233  ASSERT_EQ(NULL, manager.pending_loader());
234  EXPECT_EQ(0u, manager.num_instant_loaders());
235}
236
237// Tests DestroyLoader when the loader is pending.
238TEST_F(InstantLoaderManagerTest, DestroyPendingLoader) {
239  InstantLoaderDelegateImpl delegate;
240  InstantLoaderManager manager(&delegate);
241  scoped_ptr<InstantLoader> loader;
242  manager.UpdateLoader(1, &loader);
243  InstantLoader* first_loader = manager.active_loader();
244  MarkReady(first_loader);
245
246  // Create another loader.
247  manager.UpdateLoader(0, &loader);
248  InstantLoader* second_loader = manager.pending_loader();
249  ASSERT_TRUE(second_loader);
250  ASSERT_NE(second_loader, first_loader);
251
252  // Destroy it.
253  manager.DestroyLoader(second_loader);
254  EXPECT_EQ(NULL, manager.pending_loader());
255  EXPECT_EQ(first_loader, manager.current_loader());
256}
257
258// Makes sure WillUpateChangeActiveLoader works.
259TEST_F(InstantLoaderManagerTest, WillUpateChangeActiveLoader) {
260  InstantLoaderDelegateImpl delegate;
261  InstantLoaderManager manager(&delegate);
262  scoped_ptr<InstantLoader> loader;
263
264  // When there is no loader WillUpateChangeActiveLoader should return true.
265  EXPECT_TRUE(manager.WillUpateChangeActiveLoader(0));
266  EXPECT_TRUE(manager.WillUpateChangeActiveLoader(1));
267
268  // Add a loder with id 0 and test again.
269  manager.UpdateLoader(0, &loader);
270  EXPECT_FALSE(manager.WillUpateChangeActiveLoader(0));
271  EXPECT_TRUE(manager.WillUpateChangeActiveLoader(1));
272  ASSERT_TRUE(manager.active_loader());
273  MarkReady(manager.active_loader());
274
275  // Add a loader with id 1 and test again.
276  manager.UpdateLoader(1, &loader);
277  EXPECT_TRUE(manager.WillUpateChangeActiveLoader(0));
278  EXPECT_FALSE(manager.WillUpateChangeActiveLoader(1));
279}
280
281// Makes sure UpdateLoader doesn't schedule a loader for deletion when asked
282// to update and the pending loader is ready.
283TEST_F(InstantLoaderManagerTest, UpdateWithReadyPending) {
284  InstantLoaderDelegateImpl delegate;
285  InstantLoaderManager manager(&delegate);
286
287  {
288    scoped_ptr<InstantLoader> loader;
289    manager.UpdateLoader(1, &loader);
290  }
291  InstantLoader* instant_loader = manager.current_loader();
292  ASSERT_TRUE(instant_loader);
293  MarkReady(instant_loader);
294
295  {
296    scoped_ptr<InstantLoader> loader;
297    manager.UpdateLoader(0, &loader);
298  }
299  InstantLoader* non_instant_loader = manager.active_loader();
300  ASSERT_TRUE(non_instant_loader);
301  ASSERT_NE(instant_loader, non_instant_loader);
302  MarkReady(non_instant_loader);
303
304  // This makes the non_instant_loader the current loader since it was ready.
305  scoped_ptr<InstantLoader> loader;
306  manager.UpdateLoader(0, &loader);
307  ASSERT_NE(loader.get(), non_instant_loader);
308}
309