| 
 | 1 | +//===-- TransportTest.cpp -------------------------------------------------===//  | 
 | 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-exception  | 
 | 6 | +//  | 
 | 7 | +//===----------------------------------------------------------------------===//  | 
 | 8 | + | 
 | 9 | +#include "Transport.h"  | 
 | 10 | +#include "Protocol/ProtocolBase.h"  | 
 | 11 | +#include "lldb/Host/File.h"  | 
 | 12 | +#include "lldb/Host/Pipe.h"  | 
 | 13 | +#include "llvm/ADT/StringRef.h"  | 
 | 14 | +#include "llvm/Support/FormatVariadic.h"  | 
 | 15 | +#include "llvm/Testing/Support/Error.h"  | 
 | 16 | +#include "gtest/gtest.h"  | 
 | 17 | +#include <chrono>  | 
 | 18 | +#include <memory>  | 
 | 19 | +#include <optional>  | 
 | 20 | + | 
 | 21 | +using namespace llvm;  | 
 | 22 | +using namespace lldb;  | 
 | 23 | +using namespace lldb_dap;  | 
 | 24 | +using namespace lldb_dap::protocol;  | 
 | 25 | +using lldb_private::File;  | 
 | 26 | +using lldb_private::NativeFile;  | 
 | 27 | +using lldb_private::Pipe;  | 
 | 28 | + | 
 | 29 | +class TransportTest : public testing::Test {  | 
 | 30 | +protected:  | 
 | 31 | +  Pipe input;  | 
 | 32 | +  Pipe output;  | 
 | 33 | +  std::unique_ptr<Transport> transport;  | 
 | 34 | + | 
 | 35 | +  void SetUp() override {  | 
 | 36 | +    ASSERT_THAT_ERROR(input.CreateNew(false).ToError(), Succeeded());  | 
 | 37 | +    ASSERT_THAT_ERROR(output.CreateNew(false).ToError(), Succeeded());  | 
 | 38 | +    transport = std::make_unique<Transport>(  | 
 | 39 | +        "stdio", nullptr,  | 
 | 40 | +        std::make_shared<NativeFile>(input.GetReadFileDescriptor(),  | 
 | 41 | +                                     File::eOpenOptionReadOnly,  | 
 | 42 | +                                     NativeFile::Unowned),  | 
 | 43 | +        std::make_shared<NativeFile>(output.GetWriteFileDescriptor(),  | 
 | 44 | +                                     File::eOpenOptionWriteOnly,  | 
 | 45 | +                                     NativeFile::Unowned));  | 
 | 46 | +  }  | 
 | 47 | + | 
 | 48 | +  void Write(StringRef json) {  | 
 | 49 | +    std::string message =  | 
 | 50 | +        formatv("Content-Length: {0}\r\n\r\n{1}", json.size(), json).str();  | 
 | 51 | +    ASSERT_THAT_EXPECTED(input.Write(message.data(), message.size()),  | 
 | 52 | +                         Succeeded());  | 
 | 53 | +  }  | 
 | 54 | +};  | 
 | 55 | + | 
 | 56 | +TEST_F(TransportTest, MalformedRequests) {  | 
 | 57 | +  std::string malformed_header = "COnTent-LenGth: -1{}\r\n\r\nnotjosn";  | 
 | 58 | +  ASSERT_THAT_EXPECTED(  | 
 | 59 | +      input.Write(malformed_header.data(), malformed_header.size()),  | 
 | 60 | +      Succeeded());  | 
 | 61 | +  ASSERT_THAT_EXPECTED(  | 
 | 62 | +      transport->Read(std::chrono::milliseconds(1)),  | 
 | 63 | +      FailedWithMessage(  | 
 | 64 | +          "expected 'Content-Length: ' and got 'COnTent-LenGth: '"));  | 
 | 65 | +}  | 
 | 66 | + | 
 | 67 | +TEST_F(TransportTest, Read) {  | 
 | 68 | +  Write(R"json({"seq": 1, "type": "request", "command": "abc"})json");  | 
 | 69 | +  ASSERT_THAT_EXPECTED(  | 
 | 70 | +      transport->Read(std::chrono::milliseconds(1)),  | 
 | 71 | +      HasValue(testing::VariantWith<Request>(testing::FieldsAre(  | 
 | 72 | +          /*seq=*/1, /*command=*/"abc", /*arguments=*/std::nullopt))));  | 
 | 73 | +}  | 
 | 74 | + | 
 | 75 | +TEST_F(TransportTest, ReadWithTimeout) {  | 
 | 76 | +  ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)),  | 
 | 77 | +                       Failed<TimeoutError>());  | 
 | 78 | +}  | 
 | 79 | + | 
 | 80 | +TEST_F(TransportTest, ReadWithEOF) {  | 
 | 81 | +  input.CloseWriteFileDescriptor();  | 
 | 82 | +  ASSERT_THAT_EXPECTED(transport->Read(std::chrono::milliseconds(1)),  | 
 | 83 | +                       Failed<EndOfFileError>());  | 
 | 84 | +}  | 
 | 85 | + | 
 | 86 | +TEST_F(TransportTest, Write) {  | 
 | 87 | +  ASSERT_THAT_ERROR(transport->Write(Event{"my-event", std::nullopt}),  | 
 | 88 | +                    Succeeded());  | 
 | 89 | +  output.CloseWriteFileDescriptor();  | 
 | 90 | +  char buf[1024];  | 
 | 91 | +  Expected<size_t> bytes_read =  | 
 | 92 | +      output.Read(buf, sizeof(buf), std::chrono::milliseconds(1));  | 
 | 93 | +  ASSERT_THAT_EXPECTED(bytes_read, Succeeded());  | 
 | 94 | +  ASSERT_EQ(  | 
 | 95 | +      StringRef(buf, *bytes_read),  | 
 | 96 | +      StringRef("Content-Length: 43\r\n\r\n"  | 
 | 97 | +                R"json({"event":"my-event","seq":0,"type":"event"})json"));  | 
 | 98 | +}  | 
0 commit comments