// 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);
}