brintos

brintos / llvm-project-archived public Read only

0
0
Text · 26.1 KiB · e90ab8e Raw
817 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Host/JSONTransport.h"10#include "TestingSupport/Host/JSONTransportTestUtilities.h"11#include "TestingSupport/Host/PipeTestUtilities.h"12#include "TestingSupport/SubsystemRAII.h"13#include "lldb/Host/File.h"14#include "lldb/Host/MainLoop.h"15#include "lldb/Host/MainLoopBase.h"16#include "lldb/Utility/Log.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/Support/Error.h"19#include "llvm/Support/ErrorHandling.h"20#include "llvm/Support/FormatVariadic.h"21#include "llvm/Support/JSON.h"22#include "llvm/Support/raw_ostream.h"23#include "llvm/Testing/Support/Error.h"24#include "gmock/gmock.h"25#include "gtest/gtest.h"26#include <chrono>27#include <cstddef>28#include <memory>29#include <optional>30#include <string>31#include <system_error>32 33using namespace llvm;34using namespace lldb_private;35using namespace lldb_private::transport;36using testing::_;37using testing::HasSubstr;38using testing::InSequence;39using testing::Ref;40 41namespace llvm::json {42static bool fromJSON(const Value &V, Value &T, Path P) {43  T = V;44  return true;45}46} // namespace llvm::json47 48namespace {49 50namespace test_protocol {51 52struct Request {53  int id = 0;54  std::string name;55  std::optional<json::Value> params;56};57json::Value toJSON(const Request &T) {58  return json::Object{{"name", T.name}, {"id", T.id}, {"params", T.params}};59}60bool fromJSON(const json::Value &V, Request &T, json::Path P) {61  json::ObjectMapper O(V, P);62  return O && O.map("name", T.name) && O.map("id", T.id) &&63         O.map("params", T.params);64}65bool operator==(const Request &a, const Request &b) {66  return a.name == b.name && a.id == b.id && a.params == b.params;67}68inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Request &V) {69  OS << toJSON(V);70  return OS;71}72void PrintTo(const Request &message, std::ostream *os) {73  std::string O;74  llvm::raw_string_ostream OS(O);75  OS << message;76  *os << O;77}78 79struct Response {80  int id = 0;81  int errorCode = 0;82  std::optional<json::Value> result;83};84json::Value toJSON(const Response &T) {85  return json::Object{86      {"id", T.id}, {"errorCode", T.errorCode}, {"result", T.result}};87}88bool fromJSON(const json::Value &V, Response &T, json::Path P) {89  json::ObjectMapper O(V, P);90  return O && O.map("id", T.id) && O.mapOptional("errorCode", T.errorCode) &&91         O.map("result", T.result);92}93bool operator==(const Response &a, const Response &b) {94  return a.id == b.id && a.errorCode == b.errorCode && a.result == b.result;95}96inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Response &V) {97  OS << toJSON(V);98  return OS;99}100void PrintTo(const Response &message, std::ostream *os) {101  std::string O;102  llvm::raw_string_ostream OS(O);103  OS << message;104  *os << O;105}106 107struct Event {108  std::string name;109  std::optional<json::Value> params;110};111json::Value toJSON(const Event &T) {112  return json::Object{{"name", T.name}, {"params", T.params}};113}114bool fromJSON(const json::Value &V, Event &T, json::Path P) {115  json::ObjectMapper O(V, P);116  return O && O.map("name", T.name) && O.map("params", T.params);117}118bool operator==(const Event &a, const Event &b) { return a.name == b.name; }119inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Event &V) {120  OS << toJSON(V);121  return OS;122}123void PrintTo(const Event &message, std::ostream *os) {124  std::string O;125  llvm::raw_string_ostream OS(O);126  OS << message;127  *os << O;128}129 130using Message = std::variant<Request, Response, Event>;131json::Value toJSON(const Message &msg) {132  return std::visit([](const auto &msg) { return toJSON(msg); }, msg);133}134bool fromJSON(const json::Value &V, Message &msg, json::Path P) {135  const json::Object *O = V.getAsObject();136  if (!O) {137    P.report("expected object");138    return false;139  }140 141  if (O->find("id") == O->end()) {142    Event E;143    if (!fromJSON(V, E, P))144      return false;145 146    msg = std::move(E);147    return true;148  }149 150  if (O->get("name")) {151    Request R;152    if (!fromJSON(V, R, P))153      return false;154 155    msg = std::move(R);156    return true;157  }158 159  Response R;160  if (!fromJSON(V, R, P))161    return false;162 163  msg = std::move(R);164  return true;165}166 167struct MyFnParams {168  int a = 0;169  int b = 0;170};171json::Value toJSON(const MyFnParams &T) {172  return json::Object{{"a", T.a}, {"b", T.b}};173}174bool fromJSON(const json::Value &V, MyFnParams &T, json::Path P) {175  json::ObjectMapper O(V, P);176  return O && O.map("a", T.a) && O.map("b", T.b);177}178 179struct MyFnResult {180  int c = 0;181};182json::Value toJSON(const MyFnResult &T) { return json::Object{{"c", T.c}}; }183bool fromJSON(const json::Value &V, MyFnResult &T, json::Path P) {184  json::ObjectMapper O(V, P);185  return O && O.map("c", T.c);186}187 188struct ProtoDesc {189  using Id = int;190  using Req = Request;191  using Resp = Response;192  using Evt = Event;193 194  static inline Id InitialId() { return 0; }195  static inline Req Make(Id id, llvm::StringRef method,196                         std::optional<llvm::json::Value> params) {197    return Req{id, method.str(), params};198  }199  static inline Evt Make(llvm::StringRef method,200                         std::optional<llvm::json::Value> params) {201    return Evt{method.str(), params};202  }203  static inline Resp Make(Req req, llvm::Error error) {204    Resp resp;205    resp.id = req.id;206    llvm::handleAllErrors(207        std::move(error), [&](const llvm::ErrorInfoBase &err) {208          std::error_code cerr = err.convertToErrorCode();209          resp.errorCode =210              cerr == llvm::inconvertibleErrorCode() ? 1 : cerr.value();211          resp.result = err.message();212        });213    return resp;214  }215  static inline Resp Make(Req req, std::optional<llvm::json::Value> result) {216    return Resp{req.id, 0, std::move(result)};217  }218  static inline Id KeyFor(Resp r) { return r.id; }219  static inline std::string KeyFor(Req r) { return r.name; }220  static inline std::string KeyFor(Evt e) { return e.name; }221  static inline std::optional<llvm::json::Value> Extract(Req r) {222    return r.params;223  }224  static inline llvm::Expected<llvm::json::Value> Extract(Resp r) {225    if (r.errorCode != 0)226      return llvm::createStringError(227          std::error_code(r.errorCode, std::generic_category()),228          r.result && r.result->getAsString() ? *r.result->getAsString()229                                              : "no-message");230    return r.result;231  }232  static inline std::optional<llvm::json::Value> Extract(Evt e) {233    return e.params;234  }235};236 237using Transport = TestTransport<ProtoDesc>;238using Binder = lldb_private::transport::Binder<ProtoDesc>;239using MessageHandler = MockMessageHandler<ProtoDesc>;240 241} // namespace test_protocol242 243template <typename T> class JSONTransportTest : public PipePairTest {244protected:245  SubsystemRAII<FileSystem> subsystems;246 247  test_protocol::MessageHandler message_handler;248  std::unique_ptr<T> transport;249  MainLoop loop;250 251  void SetUp() override {252    PipePairTest::SetUp();253    transport = std::make_unique<T>(254        std::make_shared<NativeFile>(input.GetReadFileDescriptor(),255                                     File::eOpenOptionReadOnly,256                                     NativeFile::Unowned),257        std::make_shared<NativeFile>(output.GetWriteFileDescriptor(),258                                     File::eOpenOptionWriteOnly,259                                     NativeFile::Unowned));260  }261 262  /// Run the transport MainLoop and return any messages received.263  Error264  Run(bool close_input = true,265      std::chrono::milliseconds timeout = std::chrono::milliseconds(5000)) {266    if (close_input) {267      input.CloseWriteFileDescriptor();268      EXPECT_CALL(message_handler, OnClosed()).WillOnce([this]() {269        loop.RequestTermination();270      });271    }272    bool addition_succeeded = loop.AddCallback(273        [](MainLoopBase &loop) {274          loop.RequestTermination();275          FAIL() << "timeout";276        },277        timeout);278    EXPECT_TRUE(addition_succeeded);279    auto handle = transport->RegisterMessageHandler(loop, message_handler);280    if (!handle)281      return handle.takeError();282 283    return loop.Run().takeError();284  }285 286  template <typename... Ts> void Write(Ts... args) {287    std::string message;288    for (const auto &arg : {args...})289      message += Encode(arg);290    EXPECT_THAT_EXPECTED(input.Write(message.data(), message.size()),291                         Succeeded());292  }293 294  virtual std::string Encode(const json::Value &) = 0;295};296 297class TestHTTPDelimitedJSONTransport final298    : public HTTPDelimitedJSONTransport<test_protocol::ProtoDesc> {299public:300  using HTTPDelimitedJSONTransport::HTTPDelimitedJSONTransport;301 302  void Log(llvm::StringRef message) override {303    log_messages.emplace_back(message);304  }305 306  std::vector<std::string> log_messages;307};308 309class HTTPDelimitedJSONTransportTest310    : public JSONTransportTest<TestHTTPDelimitedJSONTransport> {311public:312  using JSONTransportTest::JSONTransportTest;313 314  std::string Encode(const json::Value &V) override {315    std::string msg;316    raw_string_ostream OS(msg);317    OS << formatv("{0}", V);318    return formatv("Content-Length: {0}\r\nContent-type: "319                   "text/json\r\n\r\n{1}",320                   msg.size(), msg)321        .str();322  }323};324 325class TestJSONRPCTransport final326    : public JSONRPCTransport<test_protocol::ProtoDesc> {327public:328  using JSONRPCTransport::JSONRPCTransport;329 330  void Log(llvm::StringRef message) override {331    log_messages.emplace_back(message);332  }333 334  std::vector<std::string> log_messages;335};336 337class JSONRPCTransportTest : public JSONTransportTest<TestJSONRPCTransport> {338public:339  using JSONTransportTest::JSONTransportTest;340 341  std::string Encode(const json::Value &V) override {342    std::string msg;343    raw_string_ostream OS(msg);344    OS << formatv("{0}\n", V);345    return msg;346  }347};348 349class TransportBinderTest : public testing::Test {350protected:351  SubsystemRAII<FileSystem> subsystems;352 353  std::unique_ptr<test_protocol::Transport> to_remote;354  std::unique_ptr<test_protocol::Transport> from_remote;355  std::unique_ptr<test_protocol::Binder> binder;356  test_protocol::MessageHandler remote;357  MainLoop loop;358 359  void SetUp() override {360    std::tie(to_remote, from_remote) = test_protocol::Transport::createPair();361    binder = std::make_unique<test_protocol::Binder>(*to_remote);362 363    auto binder_handle = to_remote->RegisterMessageHandler(loop, remote);364    EXPECT_THAT_EXPECTED(binder_handle, Succeeded());365 366    auto remote_handle = from_remote->RegisterMessageHandler(loop, *binder);367    EXPECT_THAT_EXPECTED(remote_handle, Succeeded());368  }369 370  void Run() {371    bool addition_succeeded =372        loop.AddPendingCallback([](auto &loop) { loop.RequestTermination(); });373    EXPECT_TRUE(addition_succeeded);374    EXPECT_THAT_ERROR(loop.Run().takeError(), Succeeded());375  }376};377 378} // namespace379 380// Failing on Windows, see https://github.com/llvm/llvm-project/issues/153446.381#ifndef _WIN32382using namespace test_protocol;383 384TEST_F(HTTPDelimitedJSONTransportTest, MalformedRequests) {385  std::string malformed_header =386      "COnTent-LenGth: -1\r\nContent-Type: text/json\r\n\r\nnotjosn";387  ASSERT_THAT_EXPECTED(388      input.Write(malformed_header.data(), malformed_header.size()),389      Succeeded());390 391  EXPECT_CALL(message_handler, OnError(_)).WillOnce([](llvm::Error err) {392    ASSERT_THAT_ERROR(std::move(err),393                      FailedWithMessage("invalid content length: -1"));394  });395  ASSERT_THAT_ERROR(Run(), Succeeded());396}397 398TEST_F(HTTPDelimitedJSONTransportTest, Read) {399  Write(Request{6, "foo", std::nullopt});400  EXPECT_CALL(message_handler, Received(Request{6, "foo", std::nullopt}));401  ASSERT_THAT_ERROR(Run(), Succeeded());402}403 404TEST_F(HTTPDelimitedJSONTransportTest, ReadMultipleMessagesInSingleWrite) {405  InSequence seq;406  Write(407      Message{408          Request{6, "one", std::nullopt},409      },410      Message{411          test_protocol::Event{"two", std::nullopt},412      },413      Message{414          Response{2, 0, std::nullopt},415      });416  EXPECT_CALL(message_handler, Received(Request{6, "one", std::nullopt}));417  EXPECT_CALL(message_handler,418              Received(test_protocol::Event{"two", std::nullopt}));419  EXPECT_CALL(message_handler, Received(Response{2, 0, std::nullopt}));420  ASSERT_THAT_ERROR(Run(), Succeeded());421}422 423TEST_F(HTTPDelimitedJSONTransportTest, ReadAcrossMultipleChunks) {424  std::string long_str = std::string(425      HTTPDelimitedJSONTransport<test_protocol::ProtoDesc>::kReadBufferSize * 2,426      'x');427  Write(Request{5, long_str, std::nullopt});428  EXPECT_CALL(message_handler, Received(Request{5, long_str, std::nullopt}));429  ASSERT_THAT_ERROR(Run(), Succeeded());430}431 432TEST_F(HTTPDelimitedJSONTransportTest, ReadPartialMessage) {433  std::string message = Encode(Request{5, "foo", std::nullopt});434  auto split_at = message.size() / 2;435  std::string part1 = message.substr(0, split_at);436  std::string part2 = message.substr(split_at);437 438  EXPECT_CALL(message_handler, Received(Request{5, "foo", std::nullopt}));439 440  ASSERT_THAT_EXPECTED(input.Write(part1.data(), part1.size()), Succeeded());441  bool addition_succeeded = loop.AddPendingCallback(442      [](MainLoopBase &loop) { loop.RequestTermination(); });443  EXPECT_TRUE(addition_succeeded);444  ASSERT_THAT_ERROR(Run(/*close_stdin=*/false), Succeeded());445  ASSERT_THAT_EXPECTED(input.Write(part2.data(), part2.size()), Succeeded());446  input.CloseWriteFileDescriptor();447  ASSERT_THAT_ERROR(Run(), Succeeded());448}449 450TEST_F(HTTPDelimitedJSONTransportTest, ReadWithZeroByteWrites) {451  std::string message = Encode(Request{6, "foo", std::nullopt});452  auto split_at = message.size() / 2;453  std::string part1 = message.substr(0, split_at);454  std::string part2 = message.substr(split_at);455 456  EXPECT_CALL(message_handler, Received(Request{6, "foo", std::nullopt}));457 458  ASSERT_THAT_EXPECTED(input.Write(part1.data(), part1.size()), Succeeded());459 460  // Run the main loop once for the initial read.461  bool addition_succeeded = loop.AddPendingCallback(462      [](MainLoopBase &loop) { loop.RequestTermination(); });463  EXPECT_TRUE(addition_succeeded);464  ASSERT_THAT_ERROR(Run(/*close_stdin=*/false), Succeeded());465 466  // zero-byte write.467  ASSERT_THAT_EXPECTED(input.Write(part1.data(), 0),468                       Succeeded()); // zero-byte write.469  addition_succeeded = loop.AddPendingCallback(470      [](MainLoopBase &loop) { loop.RequestTermination(); });471  EXPECT_TRUE(addition_succeeded);472  ASSERT_THAT_ERROR(Run(/*close_stdin=*/false), Succeeded());473 474  // Write the remaining part of the message.475  ASSERT_THAT_EXPECTED(input.Write(part2.data(), part2.size()), Succeeded());476  ASSERT_THAT_ERROR(Run(), Succeeded());477}478 479TEST_F(HTTPDelimitedJSONTransportTest, ReadWithEOF) {480  ASSERT_THAT_ERROR(Run(), Succeeded());481}482 483TEST_F(HTTPDelimitedJSONTransportTest, ReaderWithUnhandledData) {484  std::string json = R"json({"str": "foo"})json";485  std::string message =486      formatv("Content-Length: {0}\r\nContent-type: text/json\r\n\r\n{1}",487              json.size(), json)488          .str();489 490  EXPECT_CALL(message_handler, OnError(_)).WillOnce([](llvm::Error err) {491    // The error should indicate that there are unhandled contents.492    ASSERT_THAT_ERROR(std::move(err),493                      Failed<TransportUnhandledContentsError>());494  });495 496  // Write an incomplete message and close the handle.497  ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size() - 1),498                       Succeeded());499  ASSERT_THAT_ERROR(Run(), Succeeded());500}501 502TEST_F(HTTPDelimitedJSONTransportTest, InvalidTransport) {503  transport =504      std::make_unique<TestHTTPDelimitedJSONTransport>(nullptr, nullptr);505  ASSERT_THAT_ERROR(Run(/*close_input=*/false),506                    FailedWithMessage("IO object is not valid."));507}508 509TEST_F(HTTPDelimitedJSONTransportTest, Write) {510  ASSERT_THAT_ERROR(transport->Send(Request{7, "foo", std::nullopt}),511                    Succeeded());512  ASSERT_THAT_ERROR(transport->Send(Response{5, 0, "bar"}), Succeeded());513  ASSERT_THAT_ERROR(transport->Send(test_protocol::Event{"baz", std::nullopt}),514                    Succeeded());515  output.CloseWriteFileDescriptor();516  char buf[1024];517  Expected<size_t> bytes_read =518      output.Read(buf, sizeof(buf), std::chrono::milliseconds(1));519  ASSERT_THAT_EXPECTED(bytes_read, Succeeded());520  ASSERT_EQ(StringRef(buf, *bytes_read),521            StringRef("Content-Length: 35\r\n\r\n"522                      R"({"id":7,"name":"foo","params":null})"523                      "Content-Length: 37\r\n\r\n"524                      R"({"errorCode":0,"id":5,"result":"bar"})"525                      "Content-Length: 28\r\n\r\n"526                      R"({"name":"baz","params":null})"));527}528 529TEST_F(JSONRPCTransportTest, MalformedRequests) {530  std::string malformed_header = "notjson\n";531  ASSERT_THAT_EXPECTED(532      input.Write(malformed_header.data(), malformed_header.size()),533      Succeeded());534  EXPECT_CALL(message_handler, OnError(_)).WillOnce([](llvm::Error err) {535    ASSERT_THAT_ERROR(std::move(err),536                      FailedWithMessage(HasSubstr("Invalid JSON value")));537  });538  ASSERT_THAT_ERROR(Run(), Succeeded());539}540 541TEST_F(JSONRPCTransportTest, Read) {542  Write(Message{Request{1, "foo", std::nullopt}});543  EXPECT_CALL(message_handler, Received(Request{1, "foo", std::nullopt}));544  ASSERT_THAT_ERROR(Run(), Succeeded());545}546 547TEST_F(JSONRPCTransportTest, ReadMultipleMessagesInSingleWrite) {548  InSequence seq;549  Write(Message{Request{1, "one", std::nullopt}},550        Message{test_protocol::Event{"two", std::nullopt}},551        Message{Response{3, 0, "three"}});552  EXPECT_CALL(message_handler, Received(Request{1, "one", std::nullopt}));553  EXPECT_CALL(message_handler,554              Received(test_protocol::Event{"two", std::nullopt}));555  EXPECT_CALL(message_handler, Received(Response{3, 0, "three"}));556  ASSERT_THAT_ERROR(Run(), Succeeded());557}558 559TEST_F(JSONRPCTransportTest, ReadAcrossMultipleChunks) {560  // Use a string longer than the chunk size to ensure we split the message561  // across the chunk boundary.562  std::string long_str = std::string(563      IOTransport<test_protocol::ProtoDesc>::kReadBufferSize * 2, 'x');564  Write(Request{42, long_str, std::nullopt});565  EXPECT_CALL(message_handler, Received(Request{42, long_str, std::nullopt}));566  ASSERT_THAT_ERROR(Run(), Succeeded());567}568 569TEST_F(JSONRPCTransportTest, ReadPartialMessage) {570  std::string message = R"({"id":42,"name":"foo","params":null})"571                        "\n";572  std::string part1 = message.substr(0, 7);573  std::string part2 = message.substr(7);574 575  EXPECT_CALL(message_handler, Received(Request{42, "foo", std::nullopt}));576 577  ASSERT_THAT_EXPECTED(input.Write(part1.data(), part1.size()), Succeeded());578  bool addition_succeeded = loop.AddPendingCallback(579      [](MainLoopBase &loop) { loop.RequestTermination(); });580  EXPECT_TRUE(addition_succeeded);581  ASSERT_THAT_ERROR(Run(/*close_input=*/false), Succeeded());582 583  ASSERT_THAT_EXPECTED(input.Write(part2.data(), part2.size()), Succeeded());584  input.CloseWriteFileDescriptor();585  ASSERT_THAT_ERROR(Run(), Succeeded());586}587 588TEST_F(JSONRPCTransportTest, ReadWithEOF) {589  ASSERT_THAT_ERROR(Run(), Succeeded());590}591 592TEST_F(JSONRPCTransportTest, ReaderWithUnhandledData) {593  std::string message = R"json({"req": "foo")json";594  // Write an incomplete message and close the handle.595  ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size() - 1),596                       Succeeded());597 598  EXPECT_CALL(message_handler, OnError(_)).WillOnce([](llvm::Error err) {599    ASSERT_THAT_ERROR(std::move(err),600                      Failed<TransportUnhandledContentsError>());601  });602  ASSERT_THAT_ERROR(Run(), Succeeded());603}604 605TEST_F(JSONRPCTransportTest, Write) {606  ASSERT_THAT_ERROR(transport->Send(Request{11, "foo", std::nullopt}),607                    Succeeded());608  ASSERT_THAT_ERROR(transport->Send(Response{14, 0, "bar"}), Succeeded());609  ASSERT_THAT_ERROR(transport->Send(test_protocol::Event{"baz", std::nullopt}),610                    Succeeded());611  output.CloseWriteFileDescriptor();612  char buf[1024];613  Expected<size_t> bytes_read =614      output.Read(buf, sizeof(buf), std::chrono::milliseconds(1));615  ASSERT_THAT_EXPECTED(bytes_read, Succeeded());616  ASSERT_EQ(StringRef(buf, *bytes_read),617            StringRef(R"({"id":11,"name":"foo","params":null})"618                      "\n"619                      R"({"errorCode":0,"id":14,"result":"bar"})"620                      "\n"621                      R"({"name":"baz","params":null})"622                      "\n"));623}624 625TEST_F(JSONRPCTransportTest, InvalidTransport) {626  transport = std::make_unique<TestJSONRPCTransport>(nullptr, nullptr);627  ASSERT_THAT_ERROR(Run(/*close_input=*/false),628                    FailedWithMessage("IO object is not valid."));629}630 631// Out-bound binding request handler.632TEST_F(TransportBinderTest, OutBoundRequests) {633  OutgoingRequest<MyFnResult, MyFnParams> addFn =634      binder->Bind<MyFnResult, MyFnParams>("add");635  bool replied = false;636  addFn(MyFnParams{1, 2}, [&](Expected<MyFnResult> result) {637    EXPECT_THAT_EXPECTED(result, Succeeded());638    EXPECT_EQ(result->c, 3);639    replied = true;640  });641  EXPECT_CALL(remote, Received(Request{1, "add", MyFnParams{1, 2}}));642  EXPECT_THAT_ERROR(from_remote->Send(Response{1, 0, toJSON(MyFnResult{3})}),643                    Succeeded());644  Run();645  EXPECT_TRUE(replied);646}647 648TEST_F(TransportBinderTest, OutBoundRequestsVoidParams) {649  OutgoingRequest<MyFnResult, void> voidParamFn =650      binder->Bind<MyFnResult, void>("voidParam");651  bool replied = false;652  voidParamFn([&](Expected<MyFnResult> result) {653    EXPECT_THAT_EXPECTED(result, Succeeded());654    EXPECT_EQ(result->c, 3);655    replied = true;656  });657  EXPECT_CALL(remote, Received(Request{1, "voidParam", std::nullopt}));658  EXPECT_THAT_ERROR(from_remote->Send(Response{1, 0, toJSON(MyFnResult{3})}),659                    Succeeded());660  Run();661  EXPECT_TRUE(replied);662}663 664TEST_F(TransportBinderTest, OutBoundRequestsVoidResult) {665  OutgoingRequest<void, MyFnParams> voidResultFn =666      binder->Bind<void, MyFnParams>("voidResult");667  bool replied = false;668  voidResultFn(MyFnParams{4, 5}, [&](llvm::Error error) {669    EXPECT_THAT_ERROR(std::move(error), Succeeded());670    replied = true;671  });672  EXPECT_CALL(remote, Received(Request{1, "voidResult", MyFnParams{4, 5}}));673  EXPECT_THAT_ERROR(from_remote->Send(Response{1, 0, std::nullopt}),674                    Succeeded());675  Run();676  EXPECT_TRUE(replied);677}678 679TEST_F(TransportBinderTest, OutBoundRequestsVoidParamsAndVoidResult) {680  OutgoingRequest<void, void> voidParamAndResultFn =681      binder->Bind<void, void>("voidParamAndResult");682  bool replied = false;683  voidParamAndResultFn([&](llvm::Error error) {684    EXPECT_THAT_ERROR(std::move(error), Succeeded());685    replied = true;686  });687  EXPECT_CALL(remote, Received(Request{1, "voidParamAndResult", std::nullopt}));688  EXPECT_THAT_ERROR(from_remote->Send(Response{1, 0, std::nullopt}),689                    Succeeded());690  Run();691  EXPECT_TRUE(replied);692}693 694// In-bound binding request handler.695TEST_F(TransportBinderTest, InBoundRequests) {696  bool called = false;697  binder->Bind<MyFnResult, MyFnParams>(698      "add",699      [&](const int captured_param,700          const MyFnParams &params) -> Expected<MyFnResult> {701        called = true;702        return MyFnResult{params.a + params.b + captured_param};703      },704      2);705  EXPECT_THAT_ERROR(from_remote->Send(Request{1, "add", MyFnParams{3, 4}}),706                    Succeeded());707 708  EXPECT_CALL(remote, Received(Response{1, 0, MyFnResult{9}}));709  Run();710  EXPECT_TRUE(called);711}712 713TEST_F(TransportBinderTest, InBoundRequestsVoidParams) {714  bool called = false;715  binder->Bind<MyFnResult, void>(716      "voidParam",717      [&](const int captured_param) -> Expected<MyFnResult> {718        called = true;719        return MyFnResult{captured_param};720      },721      2);722  EXPECT_THAT_ERROR(from_remote->Send(Request{2, "voidParam", std::nullopt}),723                    Succeeded());724  EXPECT_CALL(remote, Received(Response{2, 0, MyFnResult{2}}));725  Run();726  EXPECT_TRUE(called);727}728 729TEST_F(TransportBinderTest, InBoundRequestsVoidResult) {730  bool called = false;731  binder->Bind<void, MyFnParams>(732      "voidResult",733      [&](const int captured_param, const MyFnParams &params) -> llvm::Error {734        called = true;735        EXPECT_EQ(captured_param, 2);736        EXPECT_EQ(params.a, 3);737        EXPECT_EQ(params.b, 4);738        return llvm::Error::success();739      },740      2);741  EXPECT_THAT_ERROR(742      from_remote->Send(Request{3, "voidResult", MyFnParams{3, 4}}),743      Succeeded());744  EXPECT_CALL(remote, Received(Response{3, 0, std::nullopt}));745  Run();746  EXPECT_TRUE(called);747}748TEST_F(TransportBinderTest, InBoundRequestsVoidParamsAndResult) {749  bool called = false;750  binder->Bind<void, void>(751      "voidParamAndResult",752      [&](const int captured_param) -> llvm::Error {753        called = true;754        EXPECT_EQ(captured_param, 2);755        return llvm::Error::success();756      },757      2);758  EXPECT_THAT_ERROR(759      from_remote->Send(Request{4, "voidParamAndResult", std::nullopt}),760      Succeeded());761  EXPECT_CALL(remote, Received(Response{4, 0, std::nullopt}));762  Run();763  EXPECT_TRUE(called);764}765 766// Out-bound binding event handler.767TEST_F(TransportBinderTest, OutBoundEvents) {768  OutgoingEvent<MyFnParams> emitEvent = binder->Bind<MyFnParams>("evt");769  emitEvent(MyFnParams{1, 2});770  EXPECT_CALL(remote, Received(test_protocol::Event{"evt", MyFnParams{1, 2}}));771  Run();772}773 774TEST_F(TransportBinderTest, OutBoundEventsVoidParams) {775  OutgoingEvent<void> emitEvent = binder->Bind<void>("evt");776  emitEvent();777  EXPECT_CALL(remote, Received(test_protocol::Event{"evt", std::nullopt}));778  Run();779}780 781// In-bound binding event handler.782TEST_F(TransportBinderTest, InBoundEvents) {783  bool called = false;784  binder->Bind<MyFnParams>(785      "evt",786      [&](const int captured_arg, const MyFnParams &params) {787        EXPECT_EQ(captured_arg, 42);788        EXPECT_EQ(params.a, 3);789        EXPECT_EQ(params.b, 4);790        called = true;791      },792      42);793  EXPECT_THAT_ERROR(794      from_remote->Send(test_protocol::Event{"evt", MyFnParams{3, 4}}),795      Succeeded());796  Run();797  EXPECT_TRUE(called);798}799 800TEST_F(TransportBinderTest, InBoundEventsVoidParams) {801  bool called = false;802  binder->Bind<void>(803      "evt",804      [&](const int captured_arg) {805        EXPECT_EQ(captured_arg, 42);806        called = true;807      },808      42);809  EXPECT_THAT_ERROR(810      from_remote->Send(test_protocol::Event{"evt", std::nullopt}),811      Succeeded());812  Run();813  EXPECT_TRUE(called);814}815 816#endif817