123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- // Copyright 2018 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 DEVICE_FIDO_TEST_CALLBACK_RECEIVER_H_
- #define DEVICE_FIDO_TEST_CALLBACK_RECEIVER_H_
- #include <tuple>
- #include <type_traits>
- #include <utility>
- #include "base/bind.h"
- #include "base/callback.h"
- #include "base/callback_helpers.h"
- #include "base/run_loop.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- namespace device {
- namespace test {
- // Serves as a testing callback target on which callbacks with an arbitrary
- // signature `void(CallbackArgs...)` can be invoked on.
- //
- // Example usage:
- // base::test::TaskEnvironment task_environment;
- // TestCallbackReceiver<int> callback_receiver;
- //
- // // Manufacture the base::OnceCallback whose invovcation will be received
- // // by this instance.
- // auto callback = callback_receiver.callback();
- //
- // // Pass |callback| into testing code that will invoke it.
- // DoStuffAndInvokeCallbackWithResult(std::move(callback));
- //
- // // Spin the message loop until the callback is invoked, and read result.
- // callback_receiver.WaitForCallback();
- // DoStuffWithResult(std::get<0>(*callback_receiver.result());
- //
- template <class... CallbackArgs>
- class TestCallbackReceiver {
- public:
- using TupleOfNonReferenceArgs = std::tuple<std::decay_t<CallbackArgs>...>;
- TestCallbackReceiver() = default;
- TestCallbackReceiver(const TestCallbackReceiver&) = delete;
- TestCallbackReceiver& operator=(const TestCallbackReceiver&) = delete;
- ~TestCallbackReceiver() = default;
- // Whether the |callback| was already called.
- bool was_called() const { return was_called_; }
- // The result, which is non-null exactly if the callback was already invoked
- // and the result has not yet been taken with TakeResult().
- const absl::optional<TupleOfNonReferenceArgs>& result() const {
- return result_;
- }
- // Constructs a base::OnceCallback that can be passed into code under test and
- // be waited, but must not be invoked after |this| instance goes out of scope.
- //
- // This method can only be called once during the lifetime of an instance.
- // Construct multiple TestCallbackReceiver instances for multiple callbacks.
- base::OnceCallback<void(CallbackArgs...)> callback() {
- return base::BindOnce(&TestCallbackReceiver::ReceiverMethod,
- base::Unretained(this));
- }
- // Takes a tuple containing the arguments the callback was called with.
- TupleOfNonReferenceArgs TakeResult() {
- auto value = std::move(result_).value();
- result_.reset();
- return value;
- }
- // Returns immediately if the |callback()| was already called, otherwise pumps
- // the current MessageLoop until it is called.
- void WaitForCallback() {
- if (was_called_)
- return;
- wait_for_callback_loop_.Run();
- }
- private:
- void ReceiverMethod(CallbackArgs... args) {
- result_.emplace(std::forward<CallbackArgs>(args)...);
- was_called_ = true;
- wait_for_callback_loop_.Quit();
- }
- bool was_called_ = false;
- base::RunLoop wait_for_callback_loop_;
- absl::optional<TupleOfNonReferenceArgs> result_;
- };
- template <class Value>
- class ValueCallbackReceiver : public TestCallbackReceiver<Value> {
- public:
- const Value& value() const {
- return std::get<0>(*TestCallbackReceiver<Value>::result());
- }
- };
- template <class Status, class Value>
- class StatusAndValueCallbackReceiver
- : public TestCallbackReceiver<Status, Value> {
- public:
- const Status& status() const {
- return std::get<0>(*TestCallbackReceiver<Status, Value>::result());
- }
- const Value& value() const {
- return std::get<1>(*TestCallbackReceiver<Status, Value>::result());
- }
- };
- template <class Status, class... Values>
- class StatusAndValuesCallbackReceiver
- : public TestCallbackReceiver<Status, Values...> {
- public:
- const Status& status() const {
- return std::get<0>(*TestCallbackReceiver<Status, Values...>::result());
- }
- template <size_t I>
- const std::tuple_element_t<I, std::tuple<Values...>>& value() const {
- return std::get<I + 1>(*TestCallbackReceiver<Status, Values...>::result());
- }
- };
- } // namespace test
- } // namespace device
- #endif // DEVICE_FIDO_TEST_CALLBACK_RECEIVER_H_
|