// Copyright (c) 2012 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. #ifndef NET_BASE_TEST_COMPLETION_CALLBACK_H_ #define NET_BASE_TEST_COMPLETION_CALLBACK_H_ #include #include #include #include "base/callback.h" #include "base/compiler_specific.h" #include "base/memory/raw_ptr.h" #include "net/base/completion_once_callback.h" #include "net/base/net_errors.h" #include "third_party/abseil-cpp/absl/types/optional.h" //----------------------------------------------------------------------------- // completion callback helper // A helper class for completion callbacks, designed to make it easy to run // tests involving asynchronous operations. Just call WaitForResult to wait // for the asynchronous operation to complete. Uses a RunLoop to spin the // current MessageLoop while waiting. The callback must be invoked on the same // thread WaitForResult is called on. // // NOTE: Since this runs a message loop to wait for the completion callback, // there could be other side-effects resulting from WaitForResult. For this // reason, this class is probably not ideal for a general application. // namespace base { class RunLoop; } namespace net { class IOBuffer; namespace internal { class TestCompletionCallbackBaseInternal { public: TestCompletionCallbackBaseInternal( const TestCompletionCallbackBaseInternal&) = delete; TestCompletionCallbackBaseInternal& operator=( const TestCompletionCallbackBaseInternal&) = delete; bool have_result() const { return have_result_; } protected: TestCompletionCallbackBaseInternal(); virtual ~TestCompletionCallbackBaseInternal(); void DidSetResult(); void WaitForResult(); private: // RunLoop. Only non-NULL during the call to WaitForResult, so the class is // reusable. std::unique_ptr run_loop_; bool have_result_ = false; }; template struct NetErrorIsPendingHelper { bool operator()(R status) const { return status == ERR_IO_PENDING; } }; template > class TestCompletionCallbackTemplate : public TestCompletionCallbackBaseInternal { public: TestCompletionCallbackTemplate(const TestCompletionCallbackTemplate&) = delete; TestCompletionCallbackTemplate& operator=( const TestCompletionCallbackTemplate&) = delete; ~TestCompletionCallbackTemplate() override = default; R WaitForResult() { TestCompletionCallbackBaseInternal::WaitForResult(); return std::move(result_); } R GetResult(R result) { IsPendingHelper check_pending; if (!check_pending(result)) return std::move(result); return WaitForResult(); } protected: TestCompletionCallbackTemplate() : result_(R()) {} // Override this method to gain control as the callback is running. virtual void SetResult(R result) { result_ = std::move(result); DidSetResult(); } private: R result_; }; } // namespace internal class TestClosure : public internal::TestCompletionCallbackBaseInternal { public: using internal::TestCompletionCallbackBaseInternal::WaitForResult; TestClosure() = default; TestClosure(const TestClosure&) = delete; TestClosure& operator=(const TestClosure&) = delete; ~TestClosure() override; base::OnceClosure closure() { return base::BindOnce(&TestClosure::DidSetResult, base::Unretained(this)); } }; // Base class overridden by custom implementations of TestCompletionCallback. typedef internal::TestCompletionCallbackTemplate TestCompletionCallbackBase; typedef internal::TestCompletionCallbackTemplate TestInt64CompletionCallbackBase; class TestCompletionCallback : public TestCompletionCallbackBase { public: TestCompletionCallback() = default; TestCompletionCallback(const TestCompletionCallback&) = delete; TestCompletionCallback& operator=(const TestCompletionCallback&) = delete; ~TestCompletionCallback() override; CompletionOnceCallback callback() { return base::BindOnce(&TestCompletionCallback::SetResult, base::Unretained(this)); } }; class TestInt64CompletionCallback : public TestInt64CompletionCallbackBase { public: TestInt64CompletionCallback() = default; TestInt64CompletionCallback(const TestInt64CompletionCallback&) = delete; TestInt64CompletionCallback& operator=(const TestInt64CompletionCallback&) = delete; ~TestInt64CompletionCallback() override; Int64CompletionOnceCallback callback() { return base::BindOnce(&TestInt64CompletionCallback::SetResult, base::Unretained(this)); } }; // Makes sure that the buffer is not referenced when the callback runs. class ReleaseBufferCompletionCallback: public TestCompletionCallback { public: explicit ReleaseBufferCompletionCallback(IOBuffer* buffer); ReleaseBufferCompletionCallback(const ReleaseBufferCompletionCallback&) = delete; ReleaseBufferCompletionCallback& operator=( const ReleaseBufferCompletionCallback&) = delete; ~ReleaseBufferCompletionCallback() override; private: void SetResult(int result) override; raw_ptr buffer_; }; } // namespace net #endif // NET_BASE_TEST_COMPLETION_CALLBACK_H_