Mercurial > hg > CbC > CbC_llvm
view clang-tools-extra/clangd/unittests/LSPBinderTests.cpp @ 221:79ff65ed7e25
LLVM12 Original
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 15 Jun 2021 19:15:29 +0900 |
parents | |
children | c4bab56944e8 |
line wrap: on
line source
//===-- LSPBinderTests.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "LSPBinder.h" #include "llvm/Testing/Support/Error.h" #include "gmock/gmock.h" #include "gtest/gtest.h" namespace clang { namespace clangd { namespace { using testing::ElementsAre; using testing::HasSubstr; using testing::IsEmpty; using testing::UnorderedElementsAre; // JSON-serializable type for testing. struct Foo { int X; friend bool operator==(Foo A, Foo B) { return A.X == B.X; } }; bool fromJSON(const llvm::json::Value &V, Foo &F, llvm::json::Path P) { return fromJSON(V, F.X, P.field("X")); } llvm::json::Value toJSON(const Foo &F) { return F.X; } // Creates a Callback that writes its received value into an Optional<Expected>. template <typename T> llvm::unique_function<void(llvm::Expected<T>)> capture(llvm::Optional<llvm::Expected<T>> &Out) { Out.reset(); return [&Out](llvm::Expected<T> V) { Out.emplace(std::move(V)); }; } struct OutgoingRecorder : public LSPBinder::RawOutgoing { llvm::StringMap<std::vector<llvm::json::Value>> Received; void callMethod(llvm::StringRef Method, llvm::json::Value Params, Callback<llvm::json::Value> Reply) override { Received[Method].push_back(Params); if (Method == "fail") return Reply(error("Params={0}", Params)); Reply(Params); // echo back the request } void notify(llvm::StringRef Method, llvm::json::Value Params) override { Received[Method].push_back(std::move(Params)); } std::vector<llvm::json::Value> take(llvm::StringRef Method) { std::vector<llvm::json::Value> Result = Received.lookup(Method); Received.erase(Method); return Result; } }; TEST(LSPBinderTest, IncomingCalls) { LSPBinder::RawHandlers RawHandlers; OutgoingRecorder RawOutgoing; LSPBinder Binder{RawHandlers, RawOutgoing}; struct Handler { void plusOne(const Foo &Params, Callback<Foo> Reply) { Reply(Foo{Params.X + 1}); } void fail(const Foo &Params, Callback<Foo> Reply) { Reply(error("X={0}", Params.X)); } void notify(const Foo &Params) { LastNotify = Params.X; ++NotifyCount; } int LastNotify = -1; int NotifyCount = 0; }; Handler H; Binder.method("plusOne", &H, &Handler::plusOne); Binder.method("fail", &H, &Handler::fail); Binder.notification("notify", &H, &Handler::notify); Binder.command("cmdPlusOne", &H, &Handler::plusOne); ASSERT_THAT(RawHandlers.MethodHandlers.keys(), UnorderedElementsAre("plusOne", "fail")); ASSERT_THAT(RawHandlers.NotificationHandlers.keys(), UnorderedElementsAre("notify")); ASSERT_THAT(RawHandlers.CommandHandlers.keys(), UnorderedElementsAre("cmdPlusOne")); llvm::Optional<llvm::Expected<llvm::json::Value>> Reply; auto &RawPlusOne = RawHandlers.MethodHandlers["plusOne"]; RawPlusOne(1, capture(Reply)); ASSERT_TRUE(Reply.hasValue()); EXPECT_THAT_EXPECTED(Reply.getValue(), llvm::HasValue(2)); RawPlusOne("foo", capture(Reply)); ASSERT_TRUE(Reply.hasValue()); EXPECT_THAT_EXPECTED( Reply.getValue(), llvm::FailedWithMessage( HasSubstr("failed to decode plusOne request: expected integer"))); auto &RawFail = RawHandlers.MethodHandlers["fail"]; RawFail(2, capture(Reply)); ASSERT_TRUE(Reply.hasValue()); EXPECT_THAT_EXPECTED(Reply.getValue(), llvm::FailedWithMessage("X=2")); auto &RawNotify = RawHandlers.NotificationHandlers["notify"]; RawNotify(42); EXPECT_EQ(H.LastNotify, 42); EXPECT_EQ(H.NotifyCount, 1); RawNotify("hi"); // invalid, will be logged EXPECT_EQ(H.LastNotify, 42); EXPECT_EQ(H.NotifyCount, 1); auto &RawCmdPlusOne = RawHandlers.CommandHandlers["cmdPlusOne"]; RawCmdPlusOne(1, capture(Reply)); ASSERT_TRUE(Reply.hasValue()); EXPECT_THAT_EXPECTED(Reply.getValue(), llvm::HasValue(2)); // None of this generated any outgoing traffic. EXPECT_THAT(RawOutgoing.Received, IsEmpty()); } TEST(LSPBinderTest, OutgoingCalls) { LSPBinder::RawHandlers RawHandlers; OutgoingRecorder RawOutgoing; LSPBinder Binder{RawHandlers, RawOutgoing}; LSPBinder::OutgoingMethod<Foo, Foo> Echo; Echo = Binder.outgoingMethod("echo"); LSPBinder::OutgoingMethod<Foo, std::string> WrongSignature; WrongSignature = Binder.outgoingMethod("wrongSignature"); LSPBinder::OutgoingMethod<Foo, Foo> Fail; Fail = Binder.outgoingMethod("fail"); llvm::Optional<llvm::Expected<Foo>> Reply; Echo(Foo{2}, capture(Reply)); EXPECT_THAT(RawOutgoing.take("echo"), ElementsAre(llvm::json::Value(2))); ASSERT_TRUE(Reply.hasValue()); EXPECT_THAT_EXPECTED(Reply.getValue(), llvm::HasValue(Foo{2})); // JSON response is integer, can't be parsed as string. llvm::Optional<llvm::Expected<std::string>> WrongTypeReply; WrongSignature(Foo{2}, capture(WrongTypeReply)); EXPECT_THAT(RawOutgoing.take("wrongSignature"), ElementsAre(llvm::json::Value(2))); ASSERT_TRUE(Reply.hasValue()); EXPECT_THAT_EXPECTED(WrongTypeReply.getValue(), llvm::FailedWithMessage( HasSubstr("failed to decode wrongSignature reply"))); Fail(Foo{2}, capture(Reply)); EXPECT_THAT(RawOutgoing.take("fail"), ElementsAre(llvm::json::Value(2))); ASSERT_TRUE(Reply.hasValue()); EXPECT_THAT_EXPECTED(Reply.getValue(), llvm::FailedWithMessage("Params=2")); } } // namespace } // namespace clangd } // namespace clang