Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / chrome_app_sorting_unittest.cc
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.
4
5 #include "chrome/browser/extensions/chrome_app_sorting.h"
6
7 #include <map>
8
9 #include "chrome/browser/extensions/./extension_prefs_unittest.h"
10 #include "components/crx_file/id_util.h"
11 #include "extensions/common/constants.h"
12 #include "extensions/common/manifest_constants.h"
13 #include "sync/api/string_ordinal.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace extensions {
17
18 namespace keys = manifest_keys;
19
20 class ChromeAppSortingTest : public ExtensionPrefsTest {
21  protected:
22   ChromeAppSorting* app_sorting() {
23     return static_cast<ChromeAppSorting*>(prefs()->app_sorting());
24   }
25 };
26
27 class ChromeAppSortingAppLocation : public ChromeAppSortingTest {
28  public:
29   virtual void Initialize() OVERRIDE {
30     extension_ = prefs_.AddExtension("not_an_app");
31     // Non-apps should not have any app launch ordinal or page ordinal.
32     prefs()->OnExtensionInstalled(extension_.get(),
33                                   Extension::ENABLED,
34                                   syncer::StringOrdinal(),
35                                   std::string());
36   }
37
38   virtual void Verify() OVERRIDE {
39     EXPECT_FALSE(
40         app_sorting()->GetAppLaunchOrdinal(extension_->id()).IsValid());
41     EXPECT_FALSE(
42         app_sorting()->GetPageOrdinal(extension_->id()).IsValid());
43   }
44
45  private:
46   scoped_refptr<Extension> extension_;
47 };
48 TEST_F(ChromeAppSortingAppLocation, ChromeAppSortingAppLocation) {}
49
50 class ChromeAppSortingAppLaunchOrdinal : public ChromeAppSortingTest {
51  public:
52   virtual void Initialize() OVERRIDE {
53     // No extensions yet.
54     syncer::StringOrdinal page = syncer::StringOrdinal::CreateInitialOrdinal();
55     EXPECT_TRUE(syncer::StringOrdinal::CreateInitialOrdinal().Equals(
56         app_sorting()->CreateNextAppLaunchOrdinal(page)));
57
58     extension_ = prefs_.AddApp("on_extension_installed");
59     EXPECT_FALSE(prefs()->IsExtensionDisabled(extension_->id()));
60     prefs()->OnExtensionInstalled(extension_.get(),
61                                   Extension::ENABLED,
62                                   syncer::StringOrdinal(),
63                                   std::string());
64   }
65
66   virtual void Verify() OVERRIDE {
67     syncer::StringOrdinal launch_ordinal =
68         app_sorting()->GetAppLaunchOrdinal(extension_->id());
69     syncer::StringOrdinal page_ordinal =
70         syncer::StringOrdinal::CreateInitialOrdinal();
71
72     // Extension should have been assigned a valid StringOrdinal.
73     EXPECT_TRUE(launch_ordinal.IsValid());
74     EXPECT_TRUE(launch_ordinal.LessThan(
75         app_sorting()->CreateNextAppLaunchOrdinal(page_ordinal)));
76     // Set a new launch ordinal of and verify it comes after.
77     app_sorting()->SetAppLaunchOrdinal(
78         extension_->id(),
79         app_sorting()->CreateNextAppLaunchOrdinal(page_ordinal));
80     syncer::StringOrdinal new_launch_ordinal =
81         app_sorting()->GetAppLaunchOrdinal(extension_->id());
82     EXPECT_TRUE(launch_ordinal.LessThan(new_launch_ordinal));
83
84     // This extension doesn't exist, so it should return an invalid
85     // StringOrdinal.
86     syncer::StringOrdinal invalid_app_launch_ordinal =
87         app_sorting()->GetAppLaunchOrdinal("foo");
88     EXPECT_FALSE(invalid_app_launch_ordinal.IsValid());
89     EXPECT_EQ(-1, app_sorting()->PageStringOrdinalAsInteger(
90         invalid_app_launch_ordinal));
91
92     // The second page doesn't have any apps so its next launch ordinal should
93     // be the first launch ordinal.
94     syncer::StringOrdinal next_page = page_ordinal.CreateAfter();
95     syncer::StringOrdinal next_page_app_launch_ordinal =
96         app_sorting()->CreateNextAppLaunchOrdinal(next_page);
97     EXPECT_TRUE(next_page_app_launch_ordinal.Equals(
98         app_sorting()->CreateFirstAppLaunchOrdinal(next_page)));
99   }
100
101  private:
102   scoped_refptr<Extension> extension_;
103 };
104 TEST_F(ChromeAppSortingAppLaunchOrdinal, ChromeAppSortingAppLaunchOrdinal) {}
105
106 class ChromeAppSortingPageOrdinal : public ChromeAppSortingTest {
107  public:
108   virtual void Initialize() OVERRIDE {
109     extension_ = prefs_.AddApp("page_ordinal");
110     // Install with a page preference.
111     first_page_ = syncer::StringOrdinal::CreateInitialOrdinal();
112     prefs()->OnExtensionInstalled(extension_.get(),
113                                   Extension::ENABLED,
114                                   first_page_,
115                                   std::string());
116     EXPECT_TRUE(first_page_.Equals(
117         app_sorting()->GetPageOrdinal(extension_->id())));
118     EXPECT_EQ(0, app_sorting()->PageStringOrdinalAsInteger(first_page_));
119
120     scoped_refptr<Extension> extension2 = prefs_.AddApp("page_ordinal_2");
121     // Install without any page preference.
122     prefs()->OnExtensionInstalled(extension2.get(),
123                                   Extension::ENABLED,
124                                   syncer::StringOrdinal(),
125                                   std::string());
126     EXPECT_TRUE(first_page_.Equals(
127         app_sorting()->GetPageOrdinal(extension2->id())));
128   }
129   virtual void Verify() OVERRIDE {
130     // Set the page ordinal.
131     syncer::StringOrdinal new_page = first_page_.CreateAfter();
132     app_sorting()->SetPageOrdinal(extension_->id(), new_page);
133     // Verify the page ordinal.
134     EXPECT_TRUE(
135         new_page.Equals(app_sorting()->GetPageOrdinal(extension_->id())));
136     EXPECT_EQ(1, app_sorting()->PageStringOrdinalAsInteger(new_page));
137
138     // This extension doesn't exist, so it should return an invalid
139     // StringOrdinal.
140     EXPECT_FALSE(app_sorting()->GetPageOrdinal("foo").IsValid());
141   }
142
143  private:
144   syncer::StringOrdinal first_page_;
145   scoped_refptr<Extension> extension_;
146 };
147 TEST_F(ChromeAppSortingPageOrdinal, ChromeAppSortingPageOrdinal) {}
148
149 // Ensure that ChromeAppSorting is able to properly initialize off a set
150 // of old page and app launch indices and properly convert them.
151 class ChromeAppSortingInitialize : public PrefsPrepopulatedTestBase {
152  public:
153   ChromeAppSortingInitialize() {}
154   virtual ~ChromeAppSortingInitialize() {}
155
156   virtual void Initialize() OVERRIDE {
157     // A preference determining the order of which the apps appear on the NTP.
158     const char kPrefAppLaunchIndexDeprecated[] = "app_launcher_index";
159     // A preference determining the page on which an app appears in the NTP.
160     const char kPrefPageIndexDeprecated[] = "page_index";
161
162     // Setup the deprecated preferences.
163     ExtensionScopedPrefs* scoped_prefs =
164         static_cast<ExtensionScopedPrefs*>(prefs());
165     scoped_prefs->UpdateExtensionPref(extension1()->id(),
166                                       kPrefAppLaunchIndexDeprecated,
167                                       new base::FundamentalValue(0));
168     scoped_prefs->UpdateExtensionPref(extension1()->id(),
169                                       kPrefPageIndexDeprecated,
170                                       new base::FundamentalValue(0));
171
172     scoped_prefs->UpdateExtensionPref(extension2()->id(),
173                                       kPrefAppLaunchIndexDeprecated,
174                                       new base::FundamentalValue(1));
175     scoped_prefs->UpdateExtensionPref(extension2()->id(),
176                                       kPrefPageIndexDeprecated,
177                                       new base::FundamentalValue(0));
178
179     scoped_prefs->UpdateExtensionPref(extension3()->id(),
180                                       kPrefAppLaunchIndexDeprecated,
181                                       new base::FundamentalValue(0));
182     scoped_prefs->UpdateExtensionPref(extension3()->id(),
183                                       kPrefPageIndexDeprecated,
184                                       new base::FundamentalValue(1));
185
186     // We insert the ids in reserve order so that we have to deal with the
187     // element on the 2nd page before the 1st page is seen.
188     ExtensionIdList ids;
189     ids.push_back(extension3()->id());
190     ids.push_back(extension2()->id());
191     ids.push_back(extension1()->id());
192
193     prefs()->app_sorting()->Initialize(ids);
194   }
195   virtual void Verify() OVERRIDE {
196     syncer::StringOrdinal first_ordinal =
197         syncer::StringOrdinal::CreateInitialOrdinal();
198     AppSorting* app_sorting = prefs()->app_sorting();
199
200     EXPECT_TRUE(first_ordinal.Equals(
201         app_sorting->GetAppLaunchOrdinal(extension1()->id())));
202     EXPECT_TRUE(first_ordinal.LessThan(
203         app_sorting->GetAppLaunchOrdinal(extension2()->id())));
204     EXPECT_TRUE(first_ordinal.Equals(
205         app_sorting->GetAppLaunchOrdinal(extension3()->id())));
206
207     EXPECT_TRUE(first_ordinal.Equals(
208         app_sorting->GetPageOrdinal(extension1()->id())));
209     EXPECT_TRUE(first_ordinal.Equals(
210         app_sorting->GetPageOrdinal(extension2()->id())));
211     EXPECT_TRUE(first_ordinal.LessThan(
212         app_sorting->GetPageOrdinal(extension3()->id())));
213   }
214 };
215 TEST_F(ChromeAppSortingInitialize, ChromeAppSortingInitialize) {}
216
217 // Make sure that initialization still works when no extensions are present
218 // (i.e. make sure that the web store icon is still loaded into the map).
219 class ChromeAppSortingInitializeWithNoApps : public PrefsPrepopulatedTestBase {
220  public:
221   ChromeAppSortingInitializeWithNoApps() {}
222   virtual ~ChromeAppSortingInitializeWithNoApps() {}
223
224   virtual void Initialize() OVERRIDE {
225     AppSorting* app_sorting = prefs()->app_sorting();
226
227     // Make sure that the web store has valid ordinals.
228     syncer::StringOrdinal initial_ordinal =
229         syncer::StringOrdinal::CreateInitialOrdinal();
230     app_sorting->SetPageOrdinal(extensions::kWebStoreAppId,
231                                 initial_ordinal);
232     app_sorting->SetAppLaunchOrdinal(extensions::kWebStoreAppId,
233                                      initial_ordinal);
234
235     ExtensionIdList ids;
236     app_sorting->Initialize(ids);
237   }
238   virtual void Verify() OVERRIDE {
239     ChromeAppSorting* app_sorting =
240         static_cast<ChromeAppSorting*>(prefs()->app_sorting());
241
242     syncer::StringOrdinal page =
243         app_sorting->GetPageOrdinal(extensions::kWebStoreAppId);
244     EXPECT_TRUE(page.IsValid());
245
246     ChromeAppSorting::PageOrdinalMap::iterator page_it =
247         app_sorting->ntp_ordinal_map_.find(page);
248     EXPECT_TRUE(page_it != app_sorting->ntp_ordinal_map_.end());
249
250     syncer::StringOrdinal app_launch =
251         app_sorting->GetPageOrdinal(extensions::kWebStoreAppId);
252     EXPECT_TRUE(app_launch.IsValid());
253
254     ChromeAppSorting::AppLaunchOrdinalMap::iterator app_launch_it =
255         page_it->second.find(app_launch);
256     EXPECT_TRUE(app_launch_it != page_it->second.end());
257   }
258 };
259 TEST_F(ChromeAppSortingInitializeWithNoApps,
260        ChromeAppSortingInitializeWithNoApps) {}
261
262 // Tests the application index to ordinal migration code for values that
263 // shouldn't be converted. This should be removed when the migrate code
264 // is taken out.
265 // http://crbug.com/107376
266 class ChromeAppSortingMigrateAppIndexInvalid
267     : public PrefsPrepopulatedTestBase {
268  public:
269   ChromeAppSortingMigrateAppIndexInvalid() {}
270   virtual ~ChromeAppSortingMigrateAppIndexInvalid() {}
271
272   virtual void Initialize() OVERRIDE {
273     // A preference determining the order of which the apps appear on the NTP.
274     const char kPrefAppLaunchIndexDeprecated[] = "app_launcher_index";
275     // A preference determining the page on which an app appears in the NTP.
276     const char kPrefPageIndexDeprecated[] = "page_index";
277
278     // Setup the deprecated preference.
279     ExtensionScopedPrefs* scoped_prefs =
280         static_cast<ExtensionScopedPrefs*>(prefs());
281     scoped_prefs->UpdateExtensionPref(extension1()->id(),
282                                       kPrefAppLaunchIndexDeprecated,
283                                       new base::FundamentalValue(0));
284     scoped_prefs->UpdateExtensionPref(extension1()->id(),
285                                       kPrefPageIndexDeprecated,
286                                       new base::FundamentalValue(-1));
287
288     ExtensionIdList ids;
289     ids.push_back(extension1()->id());
290
291     prefs()->app_sorting()->Initialize(ids);
292   }
293   virtual void Verify() OVERRIDE {
294     // Make sure that the invalid page_index wasn't converted over.
295     EXPECT_FALSE(prefs()->app_sorting()->GetAppLaunchOrdinal(
296         extension1()->id()).IsValid());
297   }
298 };
299 TEST_F(ChromeAppSortingMigrateAppIndexInvalid,
300        ChromeAppSortingMigrateAppIndexInvalid) {}
301
302 class ChromeAppSortingFixNTPCollisionsAllCollide
303     : public PrefsPrepopulatedTestBase {
304  public:
305   ChromeAppSortingFixNTPCollisionsAllCollide() {}
306   virtual ~ChromeAppSortingFixNTPCollisionsAllCollide() {}
307
308   virtual void Initialize() OVERRIDE {
309     repeated_ordinal_ = syncer::StringOrdinal::CreateInitialOrdinal();
310
311     AppSorting* app_sorting = prefs()->app_sorting();
312
313     app_sorting->SetAppLaunchOrdinal(extension1()->id(),
314                                      repeated_ordinal_);
315     app_sorting->SetPageOrdinal(extension1()->id(), repeated_ordinal_);
316
317     app_sorting->SetAppLaunchOrdinal(extension2()->id(), repeated_ordinal_);
318     app_sorting->SetPageOrdinal(extension2()->id(), repeated_ordinal_);
319
320     app_sorting->SetAppLaunchOrdinal(extension3()->id(), repeated_ordinal_);
321     app_sorting->SetPageOrdinal(extension3()->id(), repeated_ordinal_);
322
323     app_sorting->FixNTPOrdinalCollisions();
324   }
325   virtual void Verify() OVERRIDE {
326     AppSorting* app_sorting = prefs()->app_sorting();
327     syncer::StringOrdinal extension1_app_launch =
328         app_sorting->GetAppLaunchOrdinal(extension1()->id());
329     syncer::StringOrdinal extension2_app_launch =
330         app_sorting->GetAppLaunchOrdinal(extension2()->id());
331     syncer::StringOrdinal extension3_app_launch =
332         app_sorting->GetAppLaunchOrdinal(extension3()->id());
333
334     // The overlapping extensions should have be adjusted so that they are
335     // sorted by their id.
336     EXPECT_EQ(extension1()->id() < extension2()->id(),
337               extension1_app_launch.LessThan(extension2_app_launch));
338     EXPECT_EQ(extension1()->id() < extension3()->id(),
339               extension1_app_launch.LessThan(extension3_app_launch));
340     EXPECT_EQ(extension2()->id() < extension3()->id(),
341               extension2_app_launch.LessThan(extension3_app_launch));
342
343     // The page ordinal should be unchanged.
344     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension1()->id()).Equals(
345         repeated_ordinal_));
346     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension2()->id()).Equals(
347         repeated_ordinal_));
348     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension3()->id()).Equals(
349         repeated_ordinal_));
350   }
351
352  private:
353   syncer::StringOrdinal repeated_ordinal_;
354 };
355 TEST_F(ChromeAppSortingFixNTPCollisionsAllCollide,
356        ChromeAppSortingFixNTPCollisionsAllCollide) {}
357
358 class ChromeAppSortingFixNTPCollisionsSomeCollideAtStart
359     : public PrefsPrepopulatedTestBase {
360  public:
361   ChromeAppSortingFixNTPCollisionsSomeCollideAtStart() {}
362   virtual ~ChromeAppSortingFixNTPCollisionsSomeCollideAtStart() {}
363
364   virtual void Initialize() OVERRIDE {
365     first_ordinal_ = syncer::StringOrdinal::CreateInitialOrdinal();
366     syncer::StringOrdinal second_ordinal = first_ordinal_.CreateAfter();
367
368     AppSorting* app_sorting = prefs()->app_sorting();
369
370     // Have the first two extension in the same position, with a third
371     // (non-colliding) extension after.
372
373     app_sorting->SetAppLaunchOrdinal(extension1()->id(), first_ordinal_);
374     app_sorting->SetPageOrdinal(extension1()->id(), first_ordinal_);
375
376     app_sorting->SetAppLaunchOrdinal(extension2()->id(), first_ordinal_);
377     app_sorting->SetPageOrdinal(extension2()->id(), first_ordinal_);
378
379     app_sorting->SetAppLaunchOrdinal(extension3()->id(), second_ordinal);
380     app_sorting->SetPageOrdinal(extension3()->id(), first_ordinal_);
381
382     app_sorting->FixNTPOrdinalCollisions();
383   }
384   virtual void Verify() OVERRIDE {
385     AppSorting* app_sorting = prefs()->app_sorting();
386     syncer::StringOrdinal extension1_app_launch =
387         app_sorting->GetAppLaunchOrdinal(extension1()->id());
388     syncer::StringOrdinal extension2_app_launch =
389         app_sorting->GetAppLaunchOrdinal(extension2()->id());
390     syncer::StringOrdinal extension3_app_launch =
391         app_sorting->GetAppLaunchOrdinal(extension3()->id());
392
393     // The overlapping extensions should have be adjusted so that they are
394     // sorted by their id, but they both should be before ext3, which wasn't
395     // overlapping.
396     EXPECT_EQ(extension1()->id() < extension2()->id(),
397               extension1_app_launch.LessThan(extension2_app_launch));
398     EXPECT_TRUE(extension1_app_launch.LessThan(extension3_app_launch));
399     EXPECT_TRUE(extension2_app_launch.LessThan(extension3_app_launch));
400
401     // The page ordinal should be unchanged.
402     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension1()->id()).Equals(
403         first_ordinal_));
404     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension2()->id()).Equals(
405         first_ordinal_));
406     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension3()->id()).Equals(
407         first_ordinal_));
408   }
409
410  private:
411   syncer::StringOrdinal first_ordinal_;
412 };
413 TEST_F(ChromeAppSortingFixNTPCollisionsSomeCollideAtStart,
414        ChromeAppSortingFixNTPCollisionsSomeCollideAtStart) {}
415
416 class ChromeAppSortingFixNTPCollisionsSomeCollideAtEnd
417     : public PrefsPrepopulatedTestBase {
418  public:
419   ChromeAppSortingFixNTPCollisionsSomeCollideAtEnd() {}
420   virtual ~ChromeAppSortingFixNTPCollisionsSomeCollideAtEnd() {}
421
422   virtual void Initialize() OVERRIDE {
423     first_ordinal_ = syncer::StringOrdinal::CreateInitialOrdinal();
424     syncer::StringOrdinal second_ordinal = first_ordinal_.CreateAfter();
425
426     AppSorting* app_sorting = prefs()->app_sorting();
427
428     // Have the first extension in a non-colliding position, followed by two
429     // two extension in the same position.
430
431     app_sorting->SetAppLaunchOrdinal(extension1()->id(), first_ordinal_);
432     app_sorting->SetPageOrdinal(extension1()->id(), first_ordinal_);
433
434     app_sorting->SetAppLaunchOrdinal(extension2()->id(), second_ordinal);
435     app_sorting->SetPageOrdinal(extension2()->id(), first_ordinal_);
436
437     app_sorting->SetAppLaunchOrdinal(extension3()->id(), second_ordinal);
438     app_sorting->SetPageOrdinal(extension3()->id(), first_ordinal_);
439
440     app_sorting->FixNTPOrdinalCollisions();
441   }
442   virtual void Verify() OVERRIDE {
443     AppSorting* app_sorting = prefs()->app_sorting();
444     syncer::StringOrdinal extension1_app_launch =
445         app_sorting->GetAppLaunchOrdinal(extension1()->id());
446     syncer::StringOrdinal extension2_app_launch =
447         app_sorting->GetAppLaunchOrdinal(extension2()->id());
448     syncer::StringOrdinal extension3_app_launch =
449         app_sorting->GetAppLaunchOrdinal(extension3()->id());
450
451     // The overlapping extensions should have be adjusted so that they are
452     // sorted by their id, but they both should be after ext1, which wasn't
453     // overlapping.
454     EXPECT_TRUE(extension1_app_launch.LessThan(extension2_app_launch));
455     EXPECT_TRUE(extension1_app_launch.LessThan(extension3_app_launch));
456     EXPECT_EQ(extension2()->id() < extension3()->id(),
457               extension2_app_launch.LessThan(extension3_app_launch));
458
459     // The page ordinal should be unchanged.
460     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension1()->id()).Equals(
461         first_ordinal_));
462     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension2()->id()).Equals(
463         first_ordinal_));
464     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension3()->id()).Equals(
465         first_ordinal_));
466   }
467
468  private:
469   syncer::StringOrdinal first_ordinal_;
470 };
471 TEST_F(ChromeAppSortingFixNTPCollisionsSomeCollideAtEnd,
472        ChromeAppSortingFixNTPCollisionsSomeCollideAtEnd) {}
473
474 class ChromeAppSortingFixNTPCollisionsTwoCollisions
475     : public PrefsPrepopulatedTestBase {
476  public:
477   ChromeAppSortingFixNTPCollisionsTwoCollisions() {}
478   virtual ~ChromeAppSortingFixNTPCollisionsTwoCollisions() {}
479
480   virtual void Initialize() OVERRIDE {
481     first_ordinal_ = syncer::StringOrdinal::CreateInitialOrdinal();
482     syncer::StringOrdinal second_ordinal = first_ordinal_.CreateAfter();
483
484     AppSorting* app_sorting = prefs()->app_sorting();
485
486     // Have two extensions colliding, followed by two more colliding extensions.
487     app_sorting->SetAppLaunchOrdinal(extension1()->id(), first_ordinal_);
488     app_sorting->SetPageOrdinal(extension1()->id(), first_ordinal_);
489
490     app_sorting->SetAppLaunchOrdinal(extension2()->id(), first_ordinal_);
491     app_sorting->SetPageOrdinal(extension2()->id(), first_ordinal_);
492
493     app_sorting->SetAppLaunchOrdinal(extension3()->id(), second_ordinal);
494     app_sorting->SetPageOrdinal(extension3()->id(), first_ordinal_);
495
496     app_sorting->SetAppLaunchOrdinal(extension4()->id(), second_ordinal);
497     app_sorting->SetPageOrdinal(extension4()->id(), first_ordinal_);
498
499     app_sorting->FixNTPOrdinalCollisions();
500   }
501   virtual void Verify() OVERRIDE {
502     AppSorting* app_sorting = prefs()->app_sorting();
503     syncer::StringOrdinal extension1_app_launch =
504         app_sorting->GetAppLaunchOrdinal(extension1()->id());
505     syncer::StringOrdinal extension2_app_launch =
506         app_sorting->GetAppLaunchOrdinal(extension2()->id());
507     syncer::StringOrdinal extension3_app_launch =
508         app_sorting->GetAppLaunchOrdinal(extension3()->id());
509     syncer::StringOrdinal extension4_app_launch =
510         app_sorting->GetAppLaunchOrdinal(extension4()->id());
511
512     // The overlapping extensions should have be adjusted so that they are
513     // sorted by their id, with |ext1| and |ext2| appearing before |ext3| and
514     // |ext4|.
515     EXPECT_TRUE(extension1_app_launch.LessThan(extension3_app_launch));
516     EXPECT_TRUE(extension1_app_launch.LessThan(extension4_app_launch));
517     EXPECT_TRUE(extension2_app_launch.LessThan(extension3_app_launch));
518     EXPECT_TRUE(extension2_app_launch.LessThan(extension4_app_launch));
519
520     EXPECT_EQ(extension1()->id() < extension2()->id(),
521               extension1_app_launch.LessThan(extension2_app_launch));
522     EXPECT_EQ(extension3()->id() < extension4()->id(),
523               extension3_app_launch.LessThan(extension4_app_launch));
524
525     // The page ordinal should be unchanged.
526     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension1()->id()).Equals(
527         first_ordinal_));
528     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension2()->id()).Equals(
529         first_ordinal_));
530     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension3()->id()).Equals(
531         first_ordinal_));
532     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension4()->id()).Equals(
533         first_ordinal_));
534   }
535
536  private:
537   syncer::StringOrdinal first_ordinal_;
538 };
539 TEST_F(ChromeAppSortingFixNTPCollisionsTwoCollisions,
540        ChromeAppSortingFixNTPCollisionsTwoCollisions) {}
541
542 class ChromeAppSortingEnsureValidOrdinals
543     : public PrefsPrepopulatedTestBase {
544  public :
545   ChromeAppSortingEnsureValidOrdinals() {}
546   virtual ~ChromeAppSortingEnsureValidOrdinals() {}
547
548   virtual void Initialize() OVERRIDE {}
549   virtual void Verify() OVERRIDE {
550     AppSorting* app_sorting = prefs()->app_sorting();
551
552     // Give ext1 invalid ordinals and then check that EnsureValidOrdinals fixes
553     // them.
554     app_sorting->SetAppLaunchOrdinal(extension1()->id(),
555                                      syncer::StringOrdinal());
556     app_sorting->SetPageOrdinal(extension1()->id(), syncer::StringOrdinal());
557
558     app_sorting->EnsureValidOrdinals(extension1()->id(),
559                                      syncer::StringOrdinal());
560
561     EXPECT_TRUE(app_sorting->GetAppLaunchOrdinal(extension1()->id()).IsValid());
562     EXPECT_TRUE(app_sorting->GetPageOrdinal(extension1()->id()).IsValid());
563   }
564 };
565 TEST_F(ChromeAppSortingEnsureValidOrdinals,
566        ChromeAppSortingEnsureValidOrdinals) {}
567
568 class ChromeAppSortingPageOrdinalMapping : public PrefsPrepopulatedTestBase {
569  public:
570   ChromeAppSortingPageOrdinalMapping() {}
571   virtual ~ChromeAppSortingPageOrdinalMapping() {}
572
573   virtual void Initialize() OVERRIDE {}
574   virtual void Verify() OVERRIDE {
575     std::string ext_1 = "ext_1";
576     std::string ext_2 = "ext_2";
577
578     ChromeAppSorting* app_sorting =
579         static_cast<ChromeAppSorting*>(prefs()->app_sorting());
580     syncer::StringOrdinal first_ordinal =
581         syncer::StringOrdinal::CreateInitialOrdinal();
582
583     // Ensure attempting to removing a mapping with an invalid page doesn't
584     // modify the map.
585     EXPECT_TRUE(app_sorting->ntp_ordinal_map_.empty());
586     app_sorting->RemoveOrdinalMapping(
587         ext_1, first_ordinal, first_ordinal);
588     EXPECT_TRUE(app_sorting->ntp_ordinal_map_.empty());
589
590     // Add new mappings.
591     app_sorting->AddOrdinalMapping(ext_1, first_ordinal, first_ordinal);
592     app_sorting->AddOrdinalMapping(ext_2, first_ordinal, first_ordinal);
593
594     EXPECT_EQ(1U, app_sorting->ntp_ordinal_map_.size());
595     EXPECT_EQ(2U, app_sorting->ntp_ordinal_map_[first_ordinal].size());
596
597     ChromeAppSorting::AppLaunchOrdinalMap::iterator it =
598         app_sorting->ntp_ordinal_map_[first_ordinal].find(first_ordinal);
599     EXPECT_EQ(ext_1, it->second);
600     ++it;
601     EXPECT_EQ(ext_2, it->second);
602
603     app_sorting->RemoveOrdinalMapping(ext_1, first_ordinal, first_ordinal);
604     EXPECT_EQ(1U, app_sorting->ntp_ordinal_map_.size());
605     EXPECT_EQ(1U, app_sorting->ntp_ordinal_map_[first_ordinal].size());
606
607     it = app_sorting->ntp_ordinal_map_[first_ordinal].find(first_ordinal);
608     EXPECT_EQ(ext_2, it->second);
609
610     // Ensure that attempting to remove an extension with a valid page and app
611     // launch ordinals, but a unused id has no effect.
612     app_sorting->RemoveOrdinalMapping(
613         "invalid_ext", first_ordinal, first_ordinal);
614     EXPECT_EQ(1U, app_sorting->ntp_ordinal_map_.size());
615     EXPECT_EQ(1U, app_sorting->ntp_ordinal_map_[first_ordinal].size());
616
617     it = app_sorting->ntp_ordinal_map_[first_ordinal].find(first_ordinal);
618     EXPECT_EQ(ext_2, it->second);
619   }
620 };
621 TEST_F(ChromeAppSortingPageOrdinalMapping,
622        ChromeAppSortingPageOrdinalMapping) {}
623
624 class ChromeAppSortingPreinstalledAppsBase : public PrefsPrepopulatedTestBase {
625  public:
626   ChromeAppSortingPreinstalledAppsBase() {
627     base::DictionaryValue simple_dict;
628     simple_dict.SetString(keys::kVersion, "1.0.0.0");
629     simple_dict.SetString(keys::kName, "unused");
630     simple_dict.SetString(keys::kApp, "true");
631     simple_dict.SetString(keys::kLaunchLocalPath, "fake.html");
632
633     std::string error;
634     app1_scoped_ = Extension::Create(
635         prefs_.temp_dir().AppendASCII("app1_"), Manifest::EXTERNAL_PREF,
636         simple_dict, Extension::NO_FLAGS, &error);
637     prefs()->OnExtensionInstalled(app1_scoped_.get(),
638                                   Extension::ENABLED,
639                                   syncer::StringOrdinal(),
640                                   std::string());
641
642     app2_scoped_ = Extension::Create(
643         prefs_.temp_dir().AppendASCII("app2_"), Manifest::EXTERNAL_PREF,
644         simple_dict, Extension::NO_FLAGS, &error);
645     prefs()->OnExtensionInstalled(app2_scoped_.get(),
646                                   Extension::ENABLED,
647                                   syncer::StringOrdinal(),
648                                   std::string());
649
650     app1_ = app1_scoped_.get();
651     app2_ = app2_scoped_.get();
652   }
653   virtual ~ChromeAppSortingPreinstalledAppsBase() {}
654
655  protected:
656   // Weak references, for convenience.
657   Extension* app1_;
658   Extension* app2_;
659
660  private:
661   scoped_refptr<Extension> app1_scoped_;
662   scoped_refptr<Extension> app2_scoped_;
663 };
664
665 class ChromeAppSortingGetMinOrMaxAppLaunchOrdinalsOnPage
666     : public ChromeAppSortingPreinstalledAppsBase {
667  public:
668   ChromeAppSortingGetMinOrMaxAppLaunchOrdinalsOnPage() {}
669   virtual ~ChromeAppSortingGetMinOrMaxAppLaunchOrdinalsOnPage() {}
670
671   virtual void Initialize() OVERRIDE {}
672   virtual void Verify() OVERRIDE {
673     syncer::StringOrdinal page = syncer::StringOrdinal::CreateInitialOrdinal();
674     ChromeAppSorting* app_sorting =
675         static_cast<ChromeAppSorting*>(prefs()->app_sorting());
676
677     syncer::StringOrdinal min =
678         app_sorting->GetMinOrMaxAppLaunchOrdinalsOnPage(
679             page,
680             ChromeAppSorting::MIN_ORDINAL);
681     syncer::StringOrdinal max =
682         app_sorting->GetMinOrMaxAppLaunchOrdinalsOnPage(
683             page,
684             ChromeAppSorting::MAX_ORDINAL);
685     EXPECT_TRUE(min.IsValid());
686     EXPECT_TRUE(max.IsValid());
687     EXPECT_TRUE(min.LessThan(max));
688
689     // Ensure that the min and max values aren't set for empty pages.
690     min = syncer::StringOrdinal();
691     max = syncer::StringOrdinal();
692     syncer::StringOrdinal empty_page = page.CreateAfter();
693     EXPECT_FALSE(min.IsValid());
694     EXPECT_FALSE(max.IsValid());
695     min = app_sorting->GetMinOrMaxAppLaunchOrdinalsOnPage(
696         empty_page,
697         ChromeAppSorting::MIN_ORDINAL);
698     max = app_sorting->GetMinOrMaxAppLaunchOrdinalsOnPage(
699         empty_page,
700         ChromeAppSorting::MAX_ORDINAL);
701     EXPECT_FALSE(min.IsValid());
702     EXPECT_FALSE(max.IsValid());
703   }
704 };
705 TEST_F(ChromeAppSortingGetMinOrMaxAppLaunchOrdinalsOnPage,
706        ChromeAppSortingGetMinOrMaxAppLaunchOrdinalsOnPage) {}
707
708 // Make sure that empty pages aren't removed from the integer to ordinal
709 // mapping. See http://crbug.com/109802 for details.
710 class ChromeAppSortingKeepEmptyStringOrdinalPages
711     : public ChromeAppSortingPreinstalledAppsBase {
712  public:
713   ChromeAppSortingKeepEmptyStringOrdinalPages() {}
714   virtual ~ChromeAppSortingKeepEmptyStringOrdinalPages() {}
715
716   virtual void Initialize() OVERRIDE {
717     AppSorting* app_sorting = prefs()->app_sorting();
718
719     syncer::StringOrdinal first_page =
720         syncer::StringOrdinal::CreateInitialOrdinal();
721     app_sorting->SetPageOrdinal(app1_->id(), first_page);
722     EXPECT_EQ(0, app_sorting->PageStringOrdinalAsInteger(first_page));
723
724     last_page_ = first_page.CreateAfter();
725     app_sorting->SetPageOrdinal(app2_->id(), last_page_);
726     EXPECT_EQ(1, app_sorting->PageStringOrdinalAsInteger(last_page_));
727
728     // Move the second app to create an empty page.
729     app_sorting->SetPageOrdinal(app2_->id(), first_page);
730     EXPECT_EQ(0, app_sorting->PageStringOrdinalAsInteger(first_page));
731   }
732   virtual void Verify() OVERRIDE {
733     AppSorting* app_sorting = prefs()->app_sorting();
734
735     // Move the second app to a new empty page at the end, skipping over
736     // the current empty page.
737     last_page_ = last_page_.CreateAfter();
738     app_sorting->SetPageOrdinal(app2_->id(), last_page_);
739     EXPECT_EQ(2, app_sorting->PageStringOrdinalAsInteger(last_page_));
740     EXPECT_TRUE(last_page_.Equals(app_sorting->PageIntegerAsStringOrdinal(2)));
741   }
742
743  private:
744   syncer::StringOrdinal last_page_;
745 };
746 TEST_F(ChromeAppSortingKeepEmptyStringOrdinalPages,
747        ChromeAppSortingKeepEmptyStringOrdinalPages) {}
748
749 class ChromeAppSortingMakesFillerOrdinals
750     : public ChromeAppSortingPreinstalledAppsBase {
751  public:
752   ChromeAppSortingMakesFillerOrdinals() {}
753   virtual ~ChromeAppSortingMakesFillerOrdinals() {}
754
755   virtual void Initialize() OVERRIDE {
756     AppSorting* app_sorting = prefs()->app_sorting();
757
758     syncer::StringOrdinal first_page =
759         syncer::StringOrdinal::CreateInitialOrdinal();
760     app_sorting->SetPageOrdinal(app1_->id(), first_page);
761     EXPECT_EQ(0, app_sorting->PageStringOrdinalAsInteger(first_page));
762   }
763   virtual void Verify() OVERRIDE {
764     AppSorting* app_sorting = prefs()->app_sorting();
765
766     // Because the UI can add an unlimited number of empty pages without an app
767     // on them, this test simulates dropping of an app on the 1st and 4th empty
768     // pages (3rd and 6th pages by index) to ensure we don't crash and that
769     // filler ordinals are created as needed. See: http://crbug.com/122214
770     syncer::StringOrdinal page_three =
771         app_sorting->PageIntegerAsStringOrdinal(2);
772     app_sorting->SetPageOrdinal(app1_->id(), page_three);
773     EXPECT_EQ(2, app_sorting->PageStringOrdinalAsInteger(page_three));
774
775     syncer::StringOrdinal page_six = app_sorting->PageIntegerAsStringOrdinal(5);
776     app_sorting->SetPageOrdinal(app1_->id(), page_six);
777     EXPECT_EQ(5, app_sorting->PageStringOrdinalAsInteger(page_six));
778   }
779 };
780 TEST_F(ChromeAppSortingMakesFillerOrdinals,
781        ChromeAppSortingMakesFillerOrdinals) {}
782
783 class ChromeAppSortingDefaultOrdinalsBase : public ChromeAppSortingTest {
784  public:
785   ChromeAppSortingDefaultOrdinalsBase() {}
786   virtual ~ChromeAppSortingDefaultOrdinalsBase() {}
787
788   virtual void Initialize() OVERRIDE {
789     app_ = CreateApp("app");
790
791     InitDefaultOrdinals();
792     ChromeAppSorting* app_sorting =
793         static_cast<ChromeAppSorting*>(prefs()->app_sorting());
794     ChromeAppSorting::AppOrdinalsMap& sorting_defaults =
795         app_sorting->default_ordinals_;
796     sorting_defaults[app_->id()].page_ordinal = default_page_ordinal_;
797     sorting_defaults[app_->id()].app_launch_ordinal =
798         default_app_launch_ordinal_;
799
800     SetupUserOrdinals();
801     InstallApps();
802   }
803
804  protected:
805   scoped_refptr<Extension> CreateApp(const std::string& name) {
806     base::DictionaryValue simple_dict;
807     simple_dict.SetString(keys::kVersion, "1.0.0.0");
808     simple_dict.SetString(keys::kName, name);
809     simple_dict.SetString(keys::kApp, "true");
810     simple_dict.SetString(keys::kLaunchLocalPath, "fake.html");
811
812     std::string errors;
813     scoped_refptr<Extension> app = Extension::Create(
814         prefs_.temp_dir().AppendASCII(name), Manifest::EXTERNAL_PREF,
815         simple_dict, Extension::NO_FLAGS, &errors);
816     EXPECT_TRUE(app.get()) << errors;
817     EXPECT_TRUE(crx_file::id_util::IdIsValid(app->id()));
818     return app;
819   }
820
821   void InitDefaultOrdinals() {
822     default_page_ordinal_ =
823         syncer::StringOrdinal::CreateInitialOrdinal().CreateAfter();
824     default_app_launch_ordinal_ =
825         syncer::StringOrdinal::CreateInitialOrdinal().CreateBefore();
826   }
827
828   virtual void SetupUserOrdinals() {}
829
830   virtual void InstallApps() {
831     prefs()->OnExtensionInstalled(app_.get(),
832                                   Extension::ENABLED,
833                                   syncer::StringOrdinal(),
834                                   std::string());
835   }
836
837   scoped_refptr<Extension> app_;
838   syncer::StringOrdinal default_page_ordinal_;
839   syncer::StringOrdinal default_app_launch_ordinal_;
840 };
841
842 // Tests that the app gets its default ordinals.
843 class ChromeAppSortingDefaultOrdinals
844     : public ChromeAppSortingDefaultOrdinalsBase {
845  public:
846   ChromeAppSortingDefaultOrdinals() {}
847   virtual ~ChromeAppSortingDefaultOrdinals() {}
848
849   virtual void Verify() OVERRIDE {
850     AppSorting* app_sorting = prefs()->app_sorting();
851     EXPECT_TRUE(app_sorting->GetPageOrdinal(app_->id()).Equals(
852         default_page_ordinal_));
853     EXPECT_TRUE(app_sorting->GetAppLaunchOrdinal(app_->id()).Equals(
854         default_app_launch_ordinal_));
855   }
856 };
857 TEST_F(ChromeAppSortingDefaultOrdinals,
858        ChromeAppSortingDefaultOrdinals) {}
859
860 // Tests that the default page ordinal is overridden by install page ordinal.
861 class ChromeAppSortingDefaultOrdinalOverriddenByInstallPage
862     : public ChromeAppSortingDefaultOrdinalsBase {
863  public:
864   ChromeAppSortingDefaultOrdinalOverriddenByInstallPage() {}
865   virtual ~ChromeAppSortingDefaultOrdinalOverriddenByInstallPage() {}
866
867   virtual void Verify() OVERRIDE {
868     AppSorting* app_sorting = prefs()->app_sorting();
869
870     EXPECT_FALSE(app_sorting->GetPageOrdinal(app_->id()).Equals(
871         default_page_ordinal_));
872     EXPECT_TRUE(app_sorting->GetPageOrdinal(app_->id()).Equals(install_page_));
873   }
874
875  protected:
876   virtual void InstallApps() OVERRIDE {
877     install_page_ = default_page_ordinal_.CreateAfter();
878     prefs()->OnExtensionInstalled(app_.get(),
879                                   Extension::ENABLED,
880                                   install_page_,
881                                   std::string());
882   }
883
884  private:
885   syncer::StringOrdinal install_page_;
886 };
887 TEST_F(ChromeAppSortingDefaultOrdinalOverriddenByInstallPage,
888        ChromeAppSortingDefaultOrdinalOverriddenByInstallPage) {}
889
890 // Tests that the default ordinals are overridden by user values.
891 class ChromeAppSortingDefaultOrdinalOverriddenByUserValue
892     : public ChromeAppSortingDefaultOrdinalsBase {
893  public:
894   ChromeAppSortingDefaultOrdinalOverriddenByUserValue() {}
895   virtual ~ChromeAppSortingDefaultOrdinalOverriddenByUserValue() {}
896
897   virtual void Verify() OVERRIDE {
898     AppSorting* app_sorting = prefs()->app_sorting();
899
900     EXPECT_TRUE(app_sorting->GetPageOrdinal(app_->id()).Equals(
901         user_page_ordinal_));
902     EXPECT_TRUE(app_sorting->GetAppLaunchOrdinal(app_->id()).Equals(
903         user_app_launch_ordinal_));
904   }
905
906  protected:
907   virtual void SetupUserOrdinals() OVERRIDE {
908     user_page_ordinal_ = default_page_ordinal_.CreateAfter();
909     user_app_launch_ordinal_ = default_app_launch_ordinal_.CreateBefore();
910
911     AppSorting* app_sorting = prefs()->app_sorting();
912     app_sorting->SetPageOrdinal(app_->id(), user_page_ordinal_);
913     app_sorting->SetAppLaunchOrdinal(app_->id(), user_app_launch_ordinal_);
914   }
915
916  private:
917   syncer::StringOrdinal user_page_ordinal_;
918   syncer::StringOrdinal user_app_launch_ordinal_;
919 };
920 TEST_F(ChromeAppSortingDefaultOrdinalOverriddenByUserValue,
921        ChromeAppSortingDefaultOrdinalOverriddenByUserValue) {}
922
923 // Tests that the default app launch ordinal is changed to avoid collision.
924 class ChromeAppSortingDefaultOrdinalNoCollision
925     : public ChromeAppSortingDefaultOrdinalsBase {
926  public:
927   ChromeAppSortingDefaultOrdinalNoCollision() {}
928   virtual ~ChromeAppSortingDefaultOrdinalNoCollision() {}
929
930   virtual void Verify() OVERRIDE {
931     AppSorting* app_sorting = prefs()->app_sorting();
932
933     // Use the default page.
934     EXPECT_TRUE(app_sorting->GetPageOrdinal(app_->id()).Equals(
935         default_page_ordinal_));
936     // Not using the default app launch ordinal because of the collision.
937     EXPECT_FALSE(app_sorting->GetAppLaunchOrdinal(app_->id()).Equals(
938         default_app_launch_ordinal_));
939   }
940
941  protected:
942   virtual void SetupUserOrdinals() OVERRIDE {
943     other_app_ = prefs_.AddApp("other_app");
944     // Creates a collision.
945     AppSorting* app_sorting = prefs()->app_sorting();
946     app_sorting->SetPageOrdinal(other_app_->id(), default_page_ordinal_);
947     app_sorting->SetAppLaunchOrdinal(other_app_->id(),
948                                      default_app_launch_ordinal_);
949
950     yet_another_app_ = prefs_.AddApp("yet_aother_app");
951     app_sorting->SetPageOrdinal(yet_another_app_->id(), default_page_ordinal_);
952     app_sorting->SetAppLaunchOrdinal(yet_another_app_->id(),
953                                      default_app_launch_ordinal_);
954   }
955
956  private:
957   scoped_refptr<Extension> other_app_;
958   scoped_refptr<Extension> yet_another_app_;
959 };
960 TEST_F(ChromeAppSortingDefaultOrdinalNoCollision,
961        ChromeAppSortingDefaultOrdinalNoCollision) {}
962
963 // Tests that SetExtensionVisible() correctly hides and unhides extensions.
964 class ChromeAppSortingSetExtensionVisible : public ChromeAppSortingTest {
965  public:
966   ChromeAppSortingSetExtensionVisible() {}
967   virtual ~ChromeAppSortingSetExtensionVisible() {}
968
969   virtual void Initialize() OVERRIDE {
970     first_app_ = prefs_.AddApp("first_app");
971     second_app_ = prefs_.AddApp("second_app");
972   }
973
974   virtual void Verify() OVERRIDE {
975     ChromeAppSorting* sorting = app_sorting();
976     syncer::StringOrdinal page1 = sorting->GetPageOrdinal(first_app_->id());
977     syncer::StringOrdinal page2 = sorting->GetPageOrdinal(second_app_->id());
978     EXPECT_TRUE(sorting->GetAppLaunchOrdinal(first_app_->id()).IsValid());
979     EXPECT_TRUE(sorting->GetAppLaunchOrdinal(second_app_->id()).IsValid());
980     EXPECT_TRUE(page1.IsValid());
981     EXPECT_TRUE(page2.IsValid());
982     EXPECT_TRUE(page1.Equals(page2));
983
984     sorting->SetExtensionVisible(first_app_->id(), false);
985     EXPECT_EQ(
986         1U, sorting->CountItemsVisibleOnNtp(sorting->ntp_ordinal_map_[page1]));
987
988     sorting->SetExtensionVisible(first_app_->id(), true);
989     EXPECT_EQ(
990         2U, sorting->CountItemsVisibleOnNtp(sorting->ntp_ordinal_map_[page1]));
991   }
992
993  private:
994   scoped_refptr<Extension> first_app_;
995   scoped_refptr<Extension> second_app_;
996 };
997 TEST_F(ChromeAppSortingSetExtensionVisible,
998        ChromeAppSortingSetExtensionVisible) {
999 }
1000
1001 }  // namespace extensions