// Copyright 2021 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/task/delayed_task_handle.h" #include "base/memory/raw_ptr.h" #include "base/test/gtest_util.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { namespace { // A non-working delegate that allows the testing of DelayedTaskHandle. class TestDelegate : public DelayedTaskHandle::Delegate { public: explicit TestDelegate(bool* was_cancel_task_called = nullptr) : was_cancel_task_called_(was_cancel_task_called) { DCHECK(!was_cancel_task_called_ || !*was_cancel_task_called_); } ~TestDelegate() override = default; bool IsValid() const override { return is_valid_; } void CancelTask() override { is_valid_ = false; if (was_cancel_task_called_) *was_cancel_task_called_ = true; } private: // Indicates if this delegate is currently valid. bool is_valid_ = true; // Indicates if CancelTask() was invoked, if not null. Must outlives |this|. raw_ptr was_cancel_task_called_; }; } // namespace // Tests that a default-constructed handle is invalid. TEST(DelayedTaskHandleTest, DefaultConstructor) { DelayedTaskHandle delayed_task_handle; EXPECT_FALSE(delayed_task_handle.IsValid()); } // Tests that creating a handle with an invalid delegate will DCHECK. TEST(DelayedTaskHandleTest, RequiresValidDelegateOnConstruction) { auto delegate = std::make_unique(); EXPECT_TRUE(delegate->IsValid()); // Invalidate the delegate before creating the handle. delegate->CancelTask(); EXPECT_FALSE(delegate->IsValid()); EXPECT_DCHECK_DEATH( { DelayedTaskHandle delayed_task_handle(std::move(delegate)); }); } // Tests that calling CancelTask() on the handle will call CancelTask() on the // delegate and invalidate it. TEST(DelayedTaskHandleTest, CancelTask) { bool was_cancel_task_called = false; auto delegate = std::make_unique(&was_cancel_task_called); EXPECT_FALSE(was_cancel_task_called); EXPECT_TRUE(delegate->IsValid()); auto* delegate_ptr = delegate.get(); DelayedTaskHandle delayed_task_handle(std::move(delegate)); EXPECT_FALSE(was_cancel_task_called); EXPECT_TRUE(delegate_ptr->IsValid()); EXPECT_TRUE(delayed_task_handle.IsValid()); delayed_task_handle.CancelTask(); EXPECT_TRUE(was_cancel_task_called); EXPECT_FALSE(delayed_task_handle.IsValid()); } // Tests that calling CancelTask() on a handle with no delegate will no-op. TEST(DelayedTaskHandleTest, CancelTaskNoDelegate) { DelayedTaskHandle delayed_task_handle; EXPECT_FALSE(delayed_task_handle.IsValid()); delayed_task_handle.CancelTask(); EXPECT_FALSE(delayed_task_handle.IsValid()); } // Tests that calling CancelTask() on a handle with an invalid delegate doesn't // crash and keeps the handle invalid. TEST(DelayedTaskHandleTest, CancelTaskInvalidDelegate) { bool was_cancel_task_called = false; auto delegate = std::make_unique(&was_cancel_task_called); EXPECT_FALSE(was_cancel_task_called); EXPECT_TRUE(delegate->IsValid()); auto* delegate_ptr = delegate.get(); DelayedTaskHandle delayed_task_handle(std::move(delegate)); EXPECT_FALSE(was_cancel_task_called); EXPECT_TRUE(delegate_ptr->IsValid()); EXPECT_TRUE(delayed_task_handle.IsValid()); delegate_ptr->CancelTask(); EXPECT_TRUE(was_cancel_task_called); EXPECT_FALSE(delegate_ptr->IsValid()); EXPECT_FALSE(delayed_task_handle.IsValid()); // Reset |was_cancel_task_called| to ensure Delegate::CancelTask() is still // invoked on an invalid delegate. was_cancel_task_called = false; delayed_task_handle.CancelTask(); EXPECT_TRUE(was_cancel_task_called); EXPECT_FALSE(delayed_task_handle.IsValid()); } // Tests that invalidating the delegate will also invalidate the handle. TEST(DelayedTaskHandleTest, InvalidateDelegate) { auto delegate = std::make_unique(); EXPECT_TRUE(delegate->IsValid()); auto* delegate_ptr = delegate.get(); DelayedTaskHandle delayed_task_handle(std::move(delegate)); EXPECT_TRUE(delegate_ptr->IsValid()); EXPECT_TRUE(delayed_task_handle.IsValid()); delegate_ptr->CancelTask(); EXPECT_FALSE(delegate_ptr->IsValid()); EXPECT_FALSE(delayed_task_handle.IsValid()); } // Tests that destroying a valid handle will DCHECK. TEST(DelayedTaskHandleTest, InvalidOnDestuction) { auto delegate = std::make_unique(); EXPECT_TRUE(delegate->IsValid()); auto* delegate_ptr = delegate.get(); EXPECT_DCHECK_DEATH({ DelayedTaskHandle delayed_task_handle(std::move(delegate)); EXPECT_TRUE(delegate_ptr->IsValid()); EXPECT_TRUE(delayed_task_handle.IsValid()); }); } // Tests the move-constructor. TEST(DelayedTaskHandleTest, MoveConstructor) { auto delegate = std::make_unique(); EXPECT_TRUE(delegate->IsValid()); auto* delegate_ptr = delegate.get(); DelayedTaskHandle delayed_task_handle(std::move(delegate)); EXPECT_TRUE(delegate_ptr->IsValid()); EXPECT_TRUE(delayed_task_handle.IsValid()); DelayedTaskHandle other_delayed_task_handle(std::move(delayed_task_handle)); EXPECT_TRUE(delegate_ptr->IsValid()); EXPECT_TRUE(other_delayed_task_handle.IsValid()); // Clean-up. other_delayed_task_handle.CancelTask(); } // Tests the move-assignment. TEST(DelayedTaskHandleTest, MoveAssignment) { auto delegate = std::make_unique(); EXPECT_TRUE(delegate->IsValid()); auto* delegate_ptr = delegate.get(); DelayedTaskHandle delayed_task_handle(std::move(delegate)); EXPECT_TRUE(delegate_ptr->IsValid()); EXPECT_TRUE(delayed_task_handle.IsValid()); DelayedTaskHandle other_delayed_task_handle; EXPECT_FALSE(other_delayed_task_handle.IsValid()); other_delayed_task_handle = std::move(delayed_task_handle); EXPECT_TRUE(delegate_ptr->IsValid()); EXPECT_TRUE(other_delayed_task_handle.IsValid()); // Clean-up. other_delayed_task_handle.CancelTask(); } // Tests that assigning to a valid handle will DCHECK. TEST(DelayedTaskHandleTest, AssignToValidHandle) { auto delegate = std::make_unique(); EXPECT_TRUE(delegate->IsValid()); auto* delegate_ptr = delegate.get(); DelayedTaskHandle delayed_task_handle(std::move(delegate)); EXPECT_TRUE(delegate_ptr->IsValid()); EXPECT_TRUE(delayed_task_handle.IsValid()); EXPECT_DCHECK_DEATH({ delayed_task_handle = DelayedTaskHandle(); }); // Clean-up. delayed_task_handle.CancelTask(); } } // namespace base