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