| // Copyright 2023 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "chrome/browser/chained_back_navigation_tracker.h" | 
 |  | 
 | #include "base/test/bind.h" | 
 | #include "base/test/task_environment.h" | 
 | #include "chrome/test/base/chrome_render_view_host_test_harness.h" | 
 | #include "content/public/browser/web_contents.h" | 
 | #include "content/public/test/browser_test_utils.h" | 
 | #include "content/public/test/navigation_simulator.h" | 
 |  | 
 | namespace chrome { | 
 |  | 
 | class ChainedBackNavigationTrackerTest | 
 |     : public ChromeRenderViewHostTestHarness { | 
 |  public: | 
 |   ChainedBackNavigationTrackerTest() | 
 |       : ChromeRenderViewHostTestHarness( | 
 |             base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} | 
 |  | 
 |  protected: | 
 |   const uint32_t min_navigation_cnt_ = | 
 |       ChainedBackNavigationTracker::kMinimumChainedBackNavigationLength; | 
 |   const int64_t max_navigation_interval_ = ChainedBackNavigationTracker:: | 
 |       kMaxChainedBackNavigationIntervalInMilliseconds; | 
 | }; | 
 |  | 
 | TEST_F(ChainedBackNavigationTrackerTest, ChainedBackNavigationStatus) { | 
 |   std::vector<const GURL> urls; | 
 |   for (uint32_t i = 0; i < min_navigation_cnt_ * 2; ++i) { | 
 |     urls.push_back(GURL("http://foo/" + base::NumberToString(i))); | 
 |   } | 
 |   for (const GURL& url : urls) { | 
 |     NavigateAndCommit(url); | 
 |   } | 
 |  | 
 |   ChainedBackNavigationTracker::CreateForWebContents(web_contents()); | 
 |   const ChainedBackNavigationTracker* tracker = | 
 |       ChainedBackNavigationTracker::FromWebContents(web_contents()); | 
 |   ASSERT_TRUE(tracker); | 
 |  | 
 |   // Before any back navigation, the return value for these two checker | 
 |   // functions should be false. | 
 |   ASSERT_FALSE(tracker->IsChainedBackNavigationRecentlyPerformed()); | 
 |   ASSERT_FALSE(tracker->IsBackButtonChainedBackNavigationRecentlyPerformed()); | 
 |  | 
 |   for (uint32_t i = 1; i < urls.size(); ++i) { | 
 |     content::NavigationSimulator::GoBack(web_contents()); | 
 |     // Since `RecordBackButtonClickForChainedBackNavigation()` is never called, | 
 |     // `IsBackButtonChainedBackNavigationRecentlyPerformed()` should always | 
 |     // returns false. | 
 |     ASSERT_FALSE(tracker->IsBackButtonChainedBackNavigationRecentlyPerformed()); | 
 |     // The check should only return true when the number of consecutive back | 
 |     // navigation is smaller than `kMinimumChainedBackNavigationLength`. | 
 |     if (i < min_navigation_cnt_) { | 
 |       ASSERT_FALSE(tracker->IsChainedBackNavigationRecentlyPerformed()); | 
 |     } else { | 
 |       ASSERT_TRUE(tracker->IsChainedBackNavigationRecentlyPerformed()); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | TEST_F(ChainedBackNavigationTrackerTest, | 
 |        ChainedBackNavigationStatus_ResetCountIfIntervalIsTooLong) { | 
 |   std::vector<const GURL> urls; | 
 |   for (uint32_t i = 0; i < min_navigation_cnt_ * 2; ++i) { | 
 |     urls.push_back(GURL("http://foo/" + base::NumberToString(i))); | 
 |   } | 
 |   for (const GURL& url : urls) { | 
 |     NavigateAndCommit(url); | 
 |   } | 
 |  | 
 |   ChainedBackNavigationTracker::CreateForWebContents(web_contents()); | 
 |   const ChainedBackNavigationTracker* tracker = | 
 |       ChainedBackNavigationTracker::FromWebContents(web_contents()); | 
 |   ASSERT_TRUE(tracker); | 
 |  | 
 |   // Before any back navigation, the return value for these two checker | 
 |   // functions should be false. | 
 |   ASSERT_FALSE(tracker->IsChainedBackNavigationRecentlyPerformed()); | 
 |   ASSERT_FALSE(tracker->IsBackButtonChainedBackNavigationRecentlyPerformed()); | 
 |  | 
 |   for (uint32_t i = 1; i < min_navigation_cnt_; ++i) { | 
 |     content::NavigationSimulator::GoBack(web_contents()); | 
 |     // The checks should always return false since the number of consecutive | 
 |     // back navigation is smaller than `kMinimumChainedBackNavigationLength`. | 
 |     ASSERT_FALSE(tracker->IsChainedBackNavigationRecentlyPerformed()); | 
 |     ASSERT_FALSE(tracker->IsBackButtonChainedBackNavigationRecentlyPerformed()); | 
 |   } | 
 |  | 
 |   // After waiting for sufficiently long interval, the counter should be reset | 
 |   // so the checks should always return false. | 
 |   task_environment()->FastForwardBy( | 
 |       base::Milliseconds(max_navigation_interval_ * 2)); | 
 |   ASSERT_FALSE(tracker->IsChainedBackNavigationRecentlyPerformed()); | 
 |   ASSERT_FALSE(tracker->IsBackButtonChainedBackNavigationRecentlyPerformed()); | 
 |  | 
 |   for (uint32_t i = 1; i < min_navigation_cnt_; ++i) { | 
 |     content::NavigationSimulator::GoBack(web_contents()); | 
 |     ASSERT_FALSE(tracker->IsBackButtonChainedBackNavigationRecentlyPerformed()); | 
 |     ASSERT_FALSE(tracker->IsChainedBackNavigationRecentlyPerformed()); | 
 |   } | 
 | } | 
 |  | 
 | TEST_F( | 
 |     ChainedBackNavigationTrackerTest, | 
 |     ChainedBackNavigationStatus_ResetCountIfNonBackForwardNavigationHappens) { | 
 |   std::vector<const GURL> urls; | 
 |   for (uint32_t i = 0; i < min_navigation_cnt_ * 2; ++i) { | 
 |     urls.push_back(GURL("http://foo/" + base::NumberToString(i))); | 
 |   } | 
 |   for (const GURL& url : urls) { | 
 |     NavigateAndCommit(url); | 
 |   } | 
 |  | 
 |   ChainedBackNavigationTracker::CreateForWebContents(web_contents()); | 
 |   const ChainedBackNavigationTracker* tracker = | 
 |       ChainedBackNavigationTracker::FromWebContents(web_contents()); | 
 |   ASSERT_TRUE(tracker); | 
 |  | 
 |   // Before any back navigation, the return value for these two checker | 
 |   // functions should be false. | 
 |   ASSERT_FALSE(tracker->IsChainedBackNavigationRecentlyPerformed()); | 
 |   ASSERT_FALSE(tracker->IsBackButtonChainedBackNavigationRecentlyPerformed()); | 
 |  | 
 |   for (uint32_t i = 1; i < min_navigation_cnt_; ++i) { | 
 |     content::NavigationSimulator::GoBack(web_contents()); | 
 |     ASSERT_FALSE(tracker->IsBackButtonChainedBackNavigationRecentlyPerformed()); | 
 |     ASSERT_FALSE(tracker->IsChainedBackNavigationRecentlyPerformed()); | 
 |   } | 
 |  | 
 |   // After performing another non history navigation, the counter should be | 
 |   // reset so the checks should always return false. | 
 |   NavigateAndCommit(GURL("http://bar/1")); | 
 |   ASSERT_EQ(0u, tracker->chained_back_navigation_count_); | 
 |  | 
 |   for (uint32_t i = 1; i < min_navigation_cnt_; ++i) { | 
 |     content::NavigationSimulator::GoBack(web_contents()); | 
 |     ASSERT_FALSE(tracker->IsBackButtonChainedBackNavigationRecentlyPerformed()); | 
 |     ASSERT_FALSE(tracker->IsChainedBackNavigationRecentlyPerformed()); | 
 |   } | 
 | } | 
 |  | 
 | TEST_F(ChainedBackNavigationTrackerTest, | 
 |        ChainedBackNavigationStatus_BackButtonClicked) { | 
 |   std::vector<const GURL> urls; | 
 |   for (uint32_t i = 0; i < min_navigation_cnt_ * 2; ++i) { | 
 |     urls.push_back(GURL("http://foo/" + base::NumberToString(i))); | 
 |   } | 
 |   for (const GURL& url : urls) { | 
 |     NavigateAndCommit(url); | 
 |   } | 
 |  | 
 |   ChainedBackNavigationTracker::CreateForWebContents(web_contents()); | 
 |   ChainedBackNavigationTracker* tracker = | 
 |       ChainedBackNavigationTracker::FromWebContents(web_contents()); | 
 |   ASSERT_TRUE(tracker); | 
 |  | 
 |   // Before any back navigation, the return value for these two checker | 
 |   // functions should be false. | 
 |   ASSERT_FALSE(tracker->IsChainedBackNavigationRecentlyPerformed()); | 
 |   ASSERT_FALSE(tracker->IsBackButtonChainedBackNavigationRecentlyPerformed()); | 
 |  | 
 |   for (uint32_t i = 1; i < urls.size(); ++i) { | 
 |     tracker->RecordBackButtonClickForChainedBackNavigation(); | 
 |     content::NavigationSimulator::GoBack(web_contents()); | 
 |     // The checks should only return true when the number of consecutive back | 
 |     // navigation is greater than or equal to | 
 |     // `kMinimumChainedBackNavigationLength`. | 
 |     if (i >= min_navigation_cnt_) { | 
 |       ASSERT_TRUE(tracker->IsChainedBackNavigationRecentlyPerformed()); | 
 |       ASSERT_TRUE( | 
 |           tracker->IsBackButtonChainedBackNavigationRecentlyPerformed()); | 
 |     } else { | 
 |       ASSERT_FALSE(tracker->IsChainedBackNavigationRecentlyPerformed()); | 
 |       ASSERT_FALSE( | 
 |           tracker->IsBackButtonChainedBackNavigationRecentlyPerformed()); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace chrome |