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 "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
   1002