chromium/chrome/browser/webshare/win/fake_iasync_operation_with_progress.h

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_WEBSHARE_WIN_FAKE_IASYNC_OPERATION_WITH_PROGRESS_H_
#define CHROME_BROWSER_WEBSHARE_WIN_FAKE_IASYNC_OPERATION_WITH_PROGRESS_H_

#include <wrl/client.h>

#include "base/notreached.h"
#include "base/win/winrt_foundation_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace webshare {

namespace internal {

// Templates used to allow easy reference to the correct types.
// See base/win/winrt_foundation_helpers.h for explanation.
template <typename TResult, typename TProgress>
using AsyncOperationWithProgressComplex = typename ABI::Windows::Foundation::
    IAsyncOperationWithProgress<TResult, TProgress>::TResult_complex;

template <typename TResult, typename TProgress>
using AsyncOperationWithProgressAbi = base::win::internal::AbiType<
    AsyncOperationWithProgressComplex<TResult, TProgress>>;

template <typename TResult, typename TProgress>
using AsyncOperationWithProgressOptionalStorage =
    base::win::internal::OptionalStorageType<
        AsyncOperationWithProgressComplex<TResult, TProgress>>;

template <typename TResult, typename TProgress>
using AsyncOperationWithProgressStorage = base::win::internal::StorageType<
    AsyncOperationWithProgressComplex<TResult, TProgress>>;

}  // namespace internal

// Provides an implementation of IAsyncOperationWithProgress for use in GTests.
template <typename TResult, typename TProgress>
class FakeIAsyncOperationWithProgress final
    : public Microsoft::WRL::RuntimeClass<
          Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRtClassicComMix>,
          ABI::Windows::Foundation::IAsyncOperationWithProgress<TResult,
                                                                TProgress>,
          ABI::Windows::Foundation::IAsyncInfo> {
 public:
  FakeIAsyncOperationWithProgress() = default;
  FakeIAsyncOperationWithProgress(const FakeIAsyncOperationWithProgress&) =
      delete;
  FakeIAsyncOperationWithProgress& operator=(
      const FakeIAsyncOperationWithProgress&) = delete;

  // ABI::Windows::Foundation::IAsyncOperationWithProgress:
  IFACEMETHODIMP put_Progress(
      ABI::Windows::Foundation::IAsyncOperationProgressHandler<TResult,
                                                               TProgress>*
          handler) final {
    NOTREACHED_IN_MIGRATION();
    return E_NOTIMPL;
  }
  IFACEMETHODIMP get_Progress(
      ABI::Windows::Foundation::IAsyncOperationProgressHandler<TResult,
                                                               TProgress>**
          handler) final {
    NOTREACHED_IN_MIGRATION();
    return E_NOTIMPL;
  }
  IFACEMETHODIMP put_Completed(
      ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<
          TResult,
          TProgress>* handler) final {
    EXPECT_EQ(nullptr, handler_)
        << "put_Completed called on IAsyncOperation with a CompletedHandler "
           "already defined.";
    handler_ = handler;
    return S_OK;
  }
  IFACEMETHODIMP get_Completed(
      ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<
          TResult,
          TProgress>** handler) final {
    NOTREACHED_IN_MIGRATION();
    return E_NOTIMPL;
  }
  IFACEMETHODIMP GetResults(
      internal::AsyncOperationWithProgressAbi<TResult, TProgress>* results)
      final {
    if (!is_complete_) {
      ADD_FAILURE()
          << "GetResults called on incomplete IAsyncOperationWithProgress.";
      return E_PENDING;
    }
    if (status_ != AsyncStatus::Completed)
      return E_UNEXPECTED;
    return base::win::internal::CopyTo(results_, results);
  }

  // ABI::Windows::Foundation::IAsyncInfo:
  IFACEMETHODIMP get_Id(uint32_t* id) final {
    NOTREACHED_IN_MIGRATION();
    return E_NOTIMPL;
  }
  IFACEMETHODIMP get_Status(AsyncStatus* status) final {
    *status = status_;
    return S_OK;
  }
  IFACEMETHODIMP get_ErrorCode(HRESULT* error_code) final {
    *error_code = error_code_;
    return S_OK;
  }
  IFACEMETHODIMP Cancel() final {
    NOTREACHED_IN_MIGRATION();
    return E_NOTIMPL;
  }
  IFACEMETHODIMP Close() final {
    NOTREACHED_IN_MIGRATION();
    return E_NOTIMPL;
  }

  // Completes the operation with |error_code|.
  //
  // The get_ErrorCode API will be set to return |error_code|, the remainder of
  // the APIs will be set to represent an error state, and the CompletedHandler
  // (if defined) will be run.
  void CompleteWithError(HRESULT error_code) {
    error_code_ = error_code;
    status_ = AsyncStatus::Error;
    InvokeCompletedHandler();
  }

  // Completes the operation with |results|.
  //
  // The GetResults API will be set to return |results|, the remainder of the
  // APIs will be set to represent a successfully completed state, and the
  // CompletedHandler (if defined) will be run.
  void CompleteWithResults(
      internal::AsyncOperationWithProgressStorage<TResult, TProgress> results) {
    error_code_ = S_OK;
    results_ = std::move(results);
    status_ = AsyncStatus::Completed;
    InvokeCompletedHandler();
  }

 private:
  void InvokeCompletedHandler() {
    ASSERT_FALSE(is_complete_)
        << "Attempted to invoke completion on an already "
           "completed IAsyncOperationWithProgress.";
    is_complete_ = true;
    if (handler_)
      handler_->Invoke(this, status_);
  }

  HRESULT error_code_ = S_OK;
  Microsoft::WRL::ComPtr<
      ABI::Windows::Foundation::
          IAsyncOperationWithProgressCompletedHandler<TResult, TProgress>>
      handler_;
  bool is_complete_ = false;
  internal::AsyncOperationWithProgressOptionalStorage<TResult, TProgress>
      results_;
  AsyncStatus status_ = AsyncStatus::Started;
};

}  // namespace webshare

#endif  // CHROME_BROWSER_WEBSHARE_WIN_FAKE_IASYNC_OPERATION_WITH_PROGRESS_H_