test_callback_receiver.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef DEVICE_FIDO_TEST_CALLBACK_RECEIVER_H_
  5. #define DEVICE_FIDO_TEST_CALLBACK_RECEIVER_H_
  6. #include <tuple>
  7. #include <type_traits>
  8. #include <utility>
  9. #include "base/bind.h"
  10. #include "base/callback.h"
  11. #include "base/callback_helpers.h"
  12. #include "base/run_loop.h"
  13. #include "third_party/abseil-cpp/absl/types/optional.h"
  14. namespace device {
  15. namespace test {
  16. // Serves as a testing callback target on which callbacks with an arbitrary
  17. // signature `void(CallbackArgs...)` can be invoked on.
  18. //
  19. // Example usage:
  20. // base::test::TaskEnvironment task_environment;
  21. // TestCallbackReceiver<int> callback_receiver;
  22. //
  23. // // Manufacture the base::OnceCallback whose invovcation will be received
  24. // // by this instance.
  25. // auto callback = callback_receiver.callback();
  26. //
  27. // // Pass |callback| into testing code that will invoke it.
  28. // DoStuffAndInvokeCallbackWithResult(std::move(callback));
  29. //
  30. // // Spin the message loop until the callback is invoked, and read result.
  31. // callback_receiver.WaitForCallback();
  32. // DoStuffWithResult(std::get<0>(*callback_receiver.result());
  33. //
  34. template <class... CallbackArgs>
  35. class TestCallbackReceiver {
  36. public:
  37. using TupleOfNonReferenceArgs = std::tuple<std::decay_t<CallbackArgs>...>;
  38. TestCallbackReceiver() = default;
  39. TestCallbackReceiver(const TestCallbackReceiver&) = delete;
  40. TestCallbackReceiver& operator=(const TestCallbackReceiver&) = delete;
  41. ~TestCallbackReceiver() = default;
  42. // Whether the |callback| was already called.
  43. bool was_called() const { return was_called_; }
  44. // The result, which is non-null exactly if the callback was already invoked
  45. // and the result has not yet been taken with TakeResult().
  46. const absl::optional<TupleOfNonReferenceArgs>& result() const {
  47. return result_;
  48. }
  49. // Constructs a base::OnceCallback that can be passed into code under test and
  50. // be waited, but must not be invoked after |this| instance goes out of scope.
  51. //
  52. // This method can only be called once during the lifetime of an instance.
  53. // Construct multiple TestCallbackReceiver instances for multiple callbacks.
  54. base::OnceCallback<void(CallbackArgs...)> callback() {
  55. return base::BindOnce(&TestCallbackReceiver::ReceiverMethod,
  56. base::Unretained(this));
  57. }
  58. // Takes a tuple containing the arguments the callback was called with.
  59. TupleOfNonReferenceArgs TakeResult() {
  60. auto value = std::move(result_).value();
  61. result_.reset();
  62. return value;
  63. }
  64. // Returns immediately if the |callback()| was already called, otherwise pumps
  65. // the current MessageLoop until it is called.
  66. void WaitForCallback() {
  67. if (was_called_)
  68. return;
  69. wait_for_callback_loop_.Run();
  70. }
  71. private:
  72. void ReceiverMethod(CallbackArgs... args) {
  73. result_.emplace(std::forward<CallbackArgs>(args)...);
  74. was_called_ = true;
  75. wait_for_callback_loop_.Quit();
  76. }
  77. bool was_called_ = false;
  78. base::RunLoop wait_for_callback_loop_;
  79. absl::optional<TupleOfNonReferenceArgs> result_;
  80. };
  81. template <class Value>
  82. class ValueCallbackReceiver : public TestCallbackReceiver<Value> {
  83. public:
  84. const Value& value() const {
  85. return std::get<0>(*TestCallbackReceiver<Value>::result());
  86. }
  87. };
  88. template <class Status, class Value>
  89. class StatusAndValueCallbackReceiver
  90. : public TestCallbackReceiver<Status, Value> {
  91. public:
  92. const Status& status() const {
  93. return std::get<0>(*TestCallbackReceiver<Status, Value>::result());
  94. }
  95. const Value& value() const {
  96. return std::get<1>(*TestCallbackReceiver<Status, Value>::result());
  97. }
  98. };
  99. template <class Status, class... Values>
  100. class StatusAndValuesCallbackReceiver
  101. : public TestCallbackReceiver<Status, Values...> {
  102. public:
  103. const Status& status() const {
  104. return std::get<0>(*TestCallbackReceiver<Status, Values...>::result());
  105. }
  106. template <size_t I>
  107. const std::tuple_element_t<I, std::tuple<Values...>>& value() const {
  108. return std::get<I + 1>(*TestCallbackReceiver<Status, Values...>::result());
  109. }
  110. };
  111. } // namespace test
  112. } // namespace device
  113. #endif // DEVICE_FIDO_TEST_CALLBACK_RECEIVER_H_