text: // Copyright 2019 The Dawn Authors
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  #ifndef SRC_DAWN_TESTS_UNITTESTS_WIRE_WIRETEST_H_
  #define SRC_DAWN_TESTS_UNITTESTS_WIRE_WIRETEST_H_
  
  #include <memory>
  
  #include "dawn/mock_webgpu.h"
  #include "gtest/gtest.h"
  
  // Definition of a "Lambda predicate matcher" for GMock to allow checking deep structures
  // are passed correctly by the wire.
  
  // Helper templates to extract the argument type of a lambda.
  template <typename T>
  struct MatcherMethodArgument;
  
  template <typename Lambda, typename Arg>
  struct MatcherMethodArgument<bool (Lambda::*)(Arg) const> {
      using Type = Arg;
  };
  
  template <typename Lambda>
  using MatcherLambdaArgument = typename MatcherMethodArgument<decltype(&Lambda::operator())>::Type;
  
  // The matcher itself, unfortunately it isn't able to return detailed information like other
  // matchers do.
  template <typename Lambda, typename Arg>
  class LambdaMatcherImpl : public testing::MatcherInterface<Arg> {
    public:
      explicit LambdaMatcherImpl(Lambda lambda) : mLambda(lambda) {
      }
  
      void DescribeTo(std::ostream* os) const override {
          *os << "with a custom matcher";
      }
  
      bool MatchAndExplain(Arg value, testing::MatchResultListener* listener) const override {
          if (!mLambda(value)) {
              *listener << "which doesn't satisfy the custom predicate";
              return false;
          }
          return true;
      }
  
    private:
      Lambda mLambda;
  };
  
  // Use the MatchesLambda as follows:
  //
  //   EXPECT_CALL(foo, Bar(MatchesLambda([](ArgType arg) -> bool {
  //       return CheckPredicateOnArg(arg);
  //   })));
  template <typename Lambda>
  inline testing::Matcher<MatcherLambdaArgument<Lambda>> MatchesLambda(Lambda lambda) {
      return MakeMatcher(new LambdaMatcherImpl<Lambda, MatcherLambdaArgument<Lambda>>(lambda));
  }
  
  class StringMessageMatcher : public testing::MatcherInterface<const char*> {
    public:
      StringMessageMatcher() {
      }
  
      bool MatchAndExplain(const char* message,
                           testing::MatchResultListener* listener) const override {
          if (message == nullptr) {
              *listener << "missing error message";
              return false;
          }
          if (std::strlen(message) <= 1) {
              *listener << "message is truncated";
              return false;
          }
          return true;
      }
  
      void DescribeTo(std::ostream* os) const override {
          *os << "valid error message";
      }
  
      void DescribeNegationTo(std::ostream* os) const override {
          *os << "invalid error message";
      }
  };
  
  inline testing::Matcher<const char*> ValidStringMessage() {
      return MakeMatcher(new StringMessageMatcher());
  }
  
  namespace dawn::wire {
      class WireClient;
      class WireServer;
      namespace client {
          class MemoryTransferService;
      }  // namespace client
      namespace server {
          class MemoryTransferService;
      }  // namespace server
  }  // namespace dawn::wire
  
  namespace utils {
      class TerribleCommandBuffer;
  }
  
  class WireTest : public testing::Test {
    protected:
      WireTest();
      ~WireTest() override;
  
      void SetUp() override;
      void TearDown() override;
  
      void FlushClient(bool success = true);
      void FlushServer(bool success = true);
  
      void DefaultApiDeviceWasReleased();
  
      testing::StrictMock<MockProcTable> api;
      WGPUDevice apiDevice;
      WGPUQueue apiQueue;
      WGPUDevice device;
      WGPUQueue queue;
  
      dawn::wire::WireServer* GetWireServer();
      dawn::wire::WireClient* GetWireClient();
  
      void DeleteServer();
      void DeleteClient();
  
    private:
      void SetupIgnoredCallExpectations();
  
      virtual dawn::wire::client::MemoryTransferService* GetClientMemoryTransferService();
      virtual dawn::wire::server::MemoryTransferService* GetServerMemoryTransferService();
  
      std::unique_ptr<dawn::wire::WireServer> mWireServer;
      std::unique_ptr<dawn::wire::WireClient> mWireClient;
      std::unique_ptr<utils::TerribleCommandBuffer> mS2cBuf;
      std::unique_ptr<utils::TerribleCommandBuffer> mC2sBuf;
  };
  
  #endif  // SRC_DAWN_TESTS_UNITTESTS_WIRE_WIRETEST_H_
  