普通文本  |  309行  |  10.67 KB

// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/memory/scoped_ptr.h"
#include "chrome/browser/instant/instant_loader.h"
#include "chrome/browser/instant/instant_loader_delegate.h"
#include "chrome/browser/instant/instant_loader_manager.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

class InstantLoaderDelegateImpl : public InstantLoaderDelegate {
 public:
  InstantLoaderDelegateImpl() {}

  virtual void InstantStatusChanged(InstantLoader* loader) OVERRIDE {}

  virtual void SetSuggestedTextFor(InstantLoader* loader,
                                   const string16& text,
                                   InstantCompleteBehavior behavior) OVERRIDE {}

  virtual gfx::Rect GetInstantBounds() OVERRIDE {
    return gfx::Rect();
  }

  virtual bool ShouldCommitInstantOnMouseUp() OVERRIDE {
    return false;
  }

  virtual void CommitInstantLoader(InstantLoader* loader) OVERRIDE {
  }

  virtual void InstantLoaderDoesntSupportInstant(
      InstantLoader* loader) OVERRIDE {
  }

  virtual void AddToBlacklist(InstantLoader* loader,
                              const GURL& url) OVERRIDE {
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(InstantLoaderDelegateImpl);
};

}

class InstantLoaderManagerTest : public testing::Test {
 public:
  InstantLoaderManagerTest() {}

  void MarkReady(InstantLoader* loader) {
    loader->ready_ = true;
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(InstantLoaderManagerTest);
};

// Makes sure UpdateLoader works when invoked once.
TEST_F(InstantLoaderManagerTest, Basic) {
  InstantLoaderDelegateImpl delegate;
  InstantLoaderManager manager(&delegate);
  scoped_ptr<InstantLoader> loader;
  manager.UpdateLoader(0, &loader);
  EXPECT_EQ(NULL, loader.get());
  EXPECT_TRUE(manager.current_loader());
  EXPECT_EQ(NULL, manager.pending_loader());
  EXPECT_EQ(0, manager.current_loader()->template_url_id());
}

// Make sure invoking update twice for non-instant results keeps the same
// loader.
TEST_F(InstantLoaderManagerTest, UpdateTwice) {
  InstantLoaderDelegateImpl delegate;
  InstantLoaderManager manager(&delegate);
  scoped_ptr<InstantLoader> loader;
  manager.UpdateLoader(0, &loader);
  InstantLoader* current_loader = manager.current_loader();
  manager.UpdateLoader(0, &loader);
  EXPECT_EQ(NULL, loader.get());
  EXPECT_EQ(current_loader, manager.current_loader());
  EXPECT_EQ(NULL, manager.pending_loader());
}

// Make sure invoking update twice for instant results keeps the same loader.
TEST_F(InstantLoaderManagerTest, UpdateInstantTwice) {
  InstantLoaderDelegateImpl delegate;
  InstantLoaderManager manager(&delegate);
  scoped_ptr<InstantLoader> loader;
  manager.UpdateLoader(1, &loader);
  InstantLoader* current_loader = manager.current_loader();
  manager.UpdateLoader(1, &loader);
  EXPECT_EQ(NULL, loader.get());
  EXPECT_EQ(current_loader, manager.current_loader());
  EXPECT_EQ(NULL, manager.pending_loader());
  EXPECT_EQ(1u, manager.num_instant_loaders());
}

// Makes sure transitioning from non-instant to instant works.
TEST_F(InstantLoaderManagerTest, NonInstantToInstant) {
  InstantLoaderDelegateImpl delegate;
  InstantLoaderManager manager(&delegate);
  scoped_ptr<InstantLoader> loader;
  manager.UpdateLoader(0, &loader);
  InstantLoader* current_loader = manager.current_loader();
  manager.UpdateLoader(1, &loader);
  EXPECT_TRUE(loader.get() != NULL);
  EXPECT_NE(current_loader, manager.current_loader());
  EXPECT_EQ(NULL, manager.pending_loader());
  EXPECT_EQ(1u, manager.num_instant_loaders());
}

// Makes sure instant loaders aren't deleted when invoking update with different
// ids.
TEST_F(InstantLoaderManagerTest, DontDeleteInstantLoaders) {
  InstantLoaderDelegateImpl delegate;
  InstantLoaderManager manager(&delegate);
  scoped_ptr<InstantLoader> loader;
  manager.UpdateLoader(1, &loader);
  InstantLoader* current_loader = manager.current_loader();
  manager.UpdateLoader(2, &loader);
  EXPECT_EQ(NULL, loader.get());
  EXPECT_NE(current_loader, manager.current_loader());
  EXPECT_EQ(NULL, manager.pending_loader());
  EXPECT_EQ(2u, manager.num_instant_loaders());
}

// Makes sure a new loader is created and assigned to secondary when
// transitioning from a ready non-instant to instant.
TEST_F(InstantLoaderManagerTest, CreateSecondaryWhenReady) {
  InstantLoaderDelegateImpl delegate;
  InstantLoaderManager manager(&delegate);
  scoped_ptr<InstantLoader> loader;
  manager.UpdateLoader(0, &loader);
  InstantLoader* current_loader = manager.current_loader();
  ASSERT_TRUE(current_loader);
  MarkReady(current_loader);

  manager.UpdateLoader(1, &loader);
  EXPECT_EQ(NULL, loader.get());
  EXPECT_EQ(current_loader, manager.current_loader());
  EXPECT_TRUE(manager.pending_loader());
  EXPECT_NE(current_loader, manager.pending_loader());
  EXPECT_EQ(1u, manager.num_instant_loaders());

  // Make the pending loader current.
  InstantLoader* pending_loader = manager.pending_loader();
  manager.MakePendingCurrent(&loader);
  EXPECT_TRUE(loader.get());
  EXPECT_EQ(pending_loader, manager.current_loader());
  EXPECT_EQ(NULL, manager.pending_loader());
  EXPECT_EQ(1u, manager.num_instant_loaders());
}

// Makes sure releasing an instant updates maps currectly.
TEST_F(InstantLoaderManagerTest, ReleaseInstant) {
  InstantLoaderDelegateImpl delegate;
  InstantLoaderManager manager(&delegate);
  scoped_ptr<InstantLoader> loader;
  manager.UpdateLoader(1, &loader);
  scoped_ptr<InstantLoader> current_loader(manager.ReleaseCurrentLoader());
  EXPECT_TRUE(current_loader.get());
  EXPECT_EQ(NULL, manager.current_loader());
  EXPECT_EQ(0u, manager.num_instant_loaders());
}

// Tests transitioning from a non-instant ready loader to an instant ready
// loader is immediate.
TEST_F(InstantLoaderManagerTest, NonInstantToInstantWhenReady) {
  InstantLoaderDelegateImpl delegate;
  InstantLoaderManager manager(&delegate);
  scoped_ptr<InstantLoader> loader;
  manager.UpdateLoader(1, &loader);
  ASSERT_TRUE(manager.current_loader());
  EXPECT_EQ(1, manager.current_loader()->template_url_id());
  InstantLoader* instant_loader = manager.current_loader();

  manager.UpdateLoader(0, &loader);
  InstantLoader* non_instant_loader = manager.current_loader();
  ASSERT_TRUE(non_instant_loader);
  MarkReady(non_instant_loader);
  EXPECT_NE(non_instant_loader, instant_loader);

  MarkReady(instant_loader);
  manager.UpdateLoader(1, &loader);
  EXPECT_EQ(non_instant_loader, loader.get());
  EXPECT_EQ(instant_loader, manager.current_loader());
  EXPECT_EQ(NULL, manager.pending_loader());
  EXPECT_EQ(1u, manager.num_instant_loaders());
}

// Tests transitioning between 3 instant loaders, all ready.
TEST_F(InstantLoaderManagerTest, ThreeInstant) {
  InstantLoaderDelegateImpl delegate;
  InstantLoaderManager manager(&delegate);
  scoped_ptr<InstantLoader> loader;
  manager.UpdateLoader(1, &loader);
  ASSERT_TRUE(manager.current_loader());
  EXPECT_EQ(1, manager.current_loader()->template_url_id());
  InstantLoader* instant_loader1 = manager.current_loader();
  MarkReady(instant_loader1);

  manager.UpdateLoader(2, &loader);
  InstantLoader* instant_loader2 = manager.pending_loader();
  ASSERT_TRUE(instant_loader2);
  EXPECT_EQ(2, instant_loader2->template_url_id());
  EXPECT_NE(instant_loader1, instant_loader2);
  EXPECT_EQ(instant_loader1, manager.current_loader());

  manager.UpdateLoader(3, &loader);
  InstantLoader* instant_loader3 = manager.pending_loader();
  ASSERT_TRUE(instant_loader3);
  EXPECT_EQ(3, instant_loader3->template_url_id());
  EXPECT_NE(instant_loader1, instant_loader3);
  EXPECT_NE(instant_loader2, instant_loader3);
  EXPECT_EQ(instant_loader1, manager.current_loader());
}

// Tests DestroyLoader with an instant loader.
TEST_F(InstantLoaderManagerTest, DestroyInstantLoader) {
  InstantLoaderDelegateImpl delegate;
  InstantLoaderManager manager(&delegate);
  scoped_ptr<InstantLoader> loader;
  manager.UpdateLoader(1, &loader);
  ASSERT_TRUE(manager.current_loader());
  EXPECT_EQ(1, manager.current_loader()->template_url_id());
  // Now destroy it.
  manager.DestroyLoader(manager.current_loader());

  // There should be no current, pending and 0 instant loaders.
  ASSERT_EQ(NULL, manager.current_loader());
  ASSERT_EQ(NULL, manager.pending_loader());
  EXPECT_EQ(0u, manager.num_instant_loaders());
}

// Tests DestroyLoader when the loader is pending.
TEST_F(InstantLoaderManagerTest, DestroyPendingLoader) {
  InstantLoaderDelegateImpl delegate;
  InstantLoaderManager manager(&delegate);
  scoped_ptr<InstantLoader> loader;
  manager.UpdateLoader(1, &loader);
  InstantLoader* first_loader = manager.active_loader();
  MarkReady(first_loader);

  // Create another loader.
  manager.UpdateLoader(0, &loader);
  InstantLoader* second_loader = manager.pending_loader();
  ASSERT_TRUE(second_loader);
  ASSERT_NE(second_loader, first_loader);

  // Destroy it.
  manager.DestroyLoader(second_loader);
  EXPECT_EQ(NULL, manager.pending_loader());
  EXPECT_EQ(first_loader, manager.current_loader());
}

// Makes sure WillUpateChangeActiveLoader works.
TEST_F(InstantLoaderManagerTest, WillUpateChangeActiveLoader) {
  InstantLoaderDelegateImpl delegate;
  InstantLoaderManager manager(&delegate);
  scoped_ptr<InstantLoader> loader;

  // When there is no loader WillUpateChangeActiveLoader should return true.
  EXPECT_TRUE(manager.WillUpateChangeActiveLoader(0));
  EXPECT_TRUE(manager.WillUpateChangeActiveLoader(1));

  // Add a loder with id 0 and test again.
  manager.UpdateLoader(0, &loader);
  EXPECT_FALSE(manager.WillUpateChangeActiveLoader(0));
  EXPECT_TRUE(manager.WillUpateChangeActiveLoader(1));
  ASSERT_TRUE(manager.active_loader());
  MarkReady(manager.active_loader());

  // Add a loader with id 1 and test again.
  manager.UpdateLoader(1, &loader);
  EXPECT_TRUE(manager.WillUpateChangeActiveLoader(0));
  EXPECT_FALSE(manager.WillUpateChangeActiveLoader(1));
}

// Makes sure UpdateLoader doesn't schedule a loader for deletion when asked
// to update and the pending loader is ready.
TEST_F(InstantLoaderManagerTest, UpdateWithReadyPending) {
  InstantLoaderDelegateImpl delegate;
  InstantLoaderManager manager(&delegate);

  {
    scoped_ptr<InstantLoader> loader;
    manager.UpdateLoader(1, &loader);
  }
  InstantLoader* instant_loader = manager.current_loader();
  ASSERT_TRUE(instant_loader);
  MarkReady(instant_loader);

  {
    scoped_ptr<InstantLoader> loader;
    manager.UpdateLoader(0, &loader);
  }
  InstantLoader* non_instant_loader = manager.active_loader();
  ASSERT_TRUE(non_instant_loader);
  ASSERT_NE(instant_loader, non_instant_loader);
  MarkReady(non_instant_loader);

  // This makes the non_instant_loader the current loader since it was ready.
  scoped_ptr<InstantLoader> loader;
  manager.UpdateLoader(0, &loader);
  ASSERT_NE(loader.get(), non_instant_loader);
}