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