[docs] Add LICENSE.txt to the root of the mono-repo
[llvm-project.git] / clang-tools-extra / clangd / unittests / PathMappingTests.cpp
blob2da38de102767ae55b5ea2eb1d647d224a3ab2a9
1 //===-- PathMappingTests.cpp ------------------------*- C++ -*-----------===//
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 //===----------------------------------------------------------------------===//
9 #include "PathMapping.h"
10 #include "llvm/Support/JSON.h"
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
13 #include <string>
14 namespace clang {
15 namespace clangd {
16 namespace {
17 using ::testing::ElementsAre;
18 MATCHER_P2(Mapping, ClientPath, ServerPath, "") {
19 return arg.ClientPath == ClientPath && arg.ServerPath == ServerPath;
22 bool failedParse(llvm::StringRef RawMappings) {
23 llvm::Expected<PathMappings> Mappings = parsePathMappings(RawMappings);
24 if (!Mappings) {
25 consumeError(Mappings.takeError());
26 return true;
28 return false;
31 TEST(ParsePathMappingTests, WindowsPath) {
32 // Relative path to C drive
33 EXPECT_TRUE(failedParse(R"(C:a=/root)"));
34 EXPECT_TRUE(failedParse(R"(\C:a=/root)"));
35 // Relative path to current drive.
36 EXPECT_TRUE(failedParse(R"(\a=/root)"));
37 // Absolute paths
38 llvm::Expected<PathMappings> ParsedMappings =
39 parsePathMappings(R"(C:\a=/root)");
40 ASSERT_TRUE(bool(ParsedMappings));
41 EXPECT_THAT(*ParsedMappings, ElementsAre(Mapping("/C:/a", "/root")));
42 // Absolute UNC path
43 ParsedMappings = parsePathMappings(R"(\\Server\C$=/root)");
44 ASSERT_TRUE(bool(ParsedMappings));
45 EXPECT_THAT(*ParsedMappings, ElementsAre(Mapping("//Server/C$", "/root")));
48 TEST(ParsePathMappingTests, UnixPath) {
49 // Relative unix path
50 EXPECT_TRUE(failedParse("a/b=/root"));
51 // Absolute unix path
52 llvm::Expected<PathMappings> ParsedMappings = parsePathMappings("/A/b=/root");
53 ASSERT_TRUE(bool(ParsedMappings));
54 EXPECT_THAT(*ParsedMappings, ElementsAre(Mapping("/A/b", "/root")));
55 // Absolute unix path w/ backslash
56 ParsedMappings = parsePathMappings(R"(/a/b\\ar=/root)");
57 ASSERT_TRUE(bool(ParsedMappings));
58 EXPECT_THAT(*ParsedMappings, ElementsAre(Mapping(R"(/a/b\\ar)", "/root")));
61 TEST(ParsePathMappingTests, ImproperFormat) {
62 // uneven mappings
63 EXPECT_TRUE(failedParse("/home/myuser1="));
64 // mappings need to be absolute
65 EXPECT_TRUE(failedParse("home/project=/workarea/project"));
66 // duplicate delimiter
67 EXPECT_TRUE(failedParse("/home==/workarea"));
68 // no delimiter
69 EXPECT_TRUE(failedParse("/home"));
70 // improper delimiter
71 EXPECT_TRUE(failedParse("/home,/workarea"));
74 TEST(ParsePathMappingTests, ParsesMultiple) {
75 std::string RawPathMappings =
76 "/home/project=/workarea/project,/home/project/.includes=/opt/include";
77 auto Parsed = parsePathMappings(RawPathMappings);
78 ASSERT_TRUE(bool(Parsed));
79 EXPECT_THAT(*Parsed,
80 ElementsAre(Mapping("/home/project", "/workarea/project"),
81 Mapping("/home/project/.includes", "/opt/include")));
84 bool mapsProperly(llvm::StringRef Orig, llvm::StringRef Expected,
85 llvm::StringRef RawMappings, PathMapping::Direction Dir) {
86 llvm::Expected<PathMappings> Mappings = parsePathMappings(RawMappings);
87 if (!Mappings)
88 return false;
89 llvm::Optional<std::string> MappedPath = doPathMapping(Orig, Dir, *Mappings);
90 std::string Actual = MappedPath ? *MappedPath : Orig.str();
91 EXPECT_STREQ(Expected.str().c_str(), Actual.c_str());
92 return Expected == Actual;
95 TEST(DoPathMappingTests, PreservesOriginal) {
96 // Preserves original path when no mapping
97 EXPECT_TRUE(mapsProperly("file:///home", "file:///home", "",
98 PathMapping::Direction::ClientToServer));
101 TEST(DoPathMappingTests, UsesFirstMatch) {
102 EXPECT_TRUE(mapsProperly("file:///home/foo.cpp", "file:///workarea1/foo.cpp",
103 "/home=/workarea1,/home=/workarea2",
104 PathMapping::Direction::ClientToServer));
107 TEST(DoPathMappingTests, IgnoresSubstrings) {
108 // Doesn't map substrings that aren't a proper path prefix
109 EXPECT_TRUE(mapsProperly("file://home/foo-bar.cpp", "file://home/foo-bar.cpp",
110 "/home/foo=/home/bar",
111 PathMapping::Direction::ClientToServer));
114 TEST(DoPathMappingTests, MapsOutgoingPaths) {
115 // When IsIncoming is false (i.e.a response), map the other way
116 EXPECT_TRUE(mapsProperly("file:///workarea/foo.cpp", "file:///home/foo.cpp",
117 "/home=/workarea",
118 PathMapping::Direction::ServerToClient));
121 TEST(DoPathMappingTests, OnlyMapFileUris) {
122 EXPECT_TRUE(mapsProperly("test:///home/foo.cpp", "test:///home/foo.cpp",
123 "/home=/workarea",
124 PathMapping::Direction::ClientToServer));
127 TEST(DoPathMappingTests, RespectsCaseSensitivity) {
128 EXPECT_TRUE(mapsProperly("file:///HOME/foo.cpp", "file:///HOME/foo.cpp",
129 "/home=/workarea",
130 PathMapping::Direction::ClientToServer));
133 TEST(DoPathMappingTests, MapsWindowsPaths) {
134 // Maps windows properly
135 EXPECT_TRUE(mapsProperly("file:///C:/home/foo.cpp",
136 "file:///C:/workarea/foo.cpp", R"(C:\home=C:\workarea)",
137 PathMapping::Direction::ClientToServer));
140 TEST(DoPathMappingTests, MapsWindowsUnixInterop) {
141 // Path mappings with a windows-style client path and unix-style server path
142 EXPECT_TRUE(mapsProperly(
143 "file:///C:/home/foo.cpp", "file:///workarea/foo.cpp",
144 R"(C:\home=/workarea)", PathMapping::Direction::ClientToServer));
147 TEST(ApplyPathMappingTests, PreservesOriginalParams) {
148 auto Params = llvm::json::parse(R"({
149 "textDocument": {"uri": "file:///home/foo.cpp"},
150 "position": {"line": 0, "character": 0}
151 })");
152 ASSERT_TRUE(bool(Params));
153 llvm::json::Value ExpectedParams = *Params;
154 PathMappings Mappings;
155 applyPathMappings(*Params, PathMapping::Direction::ClientToServer, Mappings);
156 EXPECT_EQ(*Params, ExpectedParams);
159 TEST(ApplyPathMappingTests, MapsAllMatchingPaths) {
160 // Handles nested objects and array values
161 auto Params = llvm::json::parse(R"({
162 "rootUri": {"uri": "file:///home/foo.cpp"},
163 "workspaceFolders": ["file:///home/src", "file:///tmp"]
164 })");
165 auto ExpectedParams = llvm::json::parse(R"({
166 "rootUri": {"uri": "file:///workarea/foo.cpp"},
167 "workspaceFolders": ["file:///workarea/src", "file:///tmp"]
168 })");
169 auto Mappings = parsePathMappings("/home=/workarea");
170 ASSERT_TRUE(bool(Params) && bool(ExpectedParams) && bool(Mappings));
171 applyPathMappings(*Params, PathMapping::Direction::ClientToServer, *Mappings);
172 EXPECT_EQ(*Params, *ExpectedParams);
175 TEST(ApplyPathMappingTests, MapsOutbound) {
176 auto Params = llvm::json::parse(R"({
177 "id": 1,
178 "result": [
179 {"uri": "file:///opt/include/foo.h"},
180 {"uri": "file:///workarea/src/foo.cpp"}]
181 })");
182 auto ExpectedParams = llvm::json::parse(R"({
183 "id": 1,
184 "result": [
185 {"uri": "file:///home/.includes/foo.h"},
186 {"uri": "file:///home/src/foo.cpp"}]
187 })");
188 auto Mappings =
189 parsePathMappings("/home=/workarea,/home/.includes=/opt/include");
190 ASSERT_TRUE(bool(Params) && bool(ExpectedParams) && bool(Mappings));
191 applyPathMappings(*Params, PathMapping::Direction::ServerToClient, *Mappings);
192 EXPECT_EQ(*Params, *ExpectedParams);
195 TEST(ApplyPathMappingTests, MapsKeys) {
196 auto Params = llvm::json::parse(R"({
197 "changes": {
198 "file:///home/foo.cpp": {"newText": "..."},
199 "file:///home/src/bar.cpp": {"newText": "..."}
201 })");
202 auto ExpectedParams = llvm::json::parse(R"({
203 "changes": {
204 "file:///workarea/foo.cpp": {"newText": "..."},
205 "file:///workarea/src/bar.cpp": {"newText": "..."}
207 })");
208 auto Mappings = parsePathMappings("/home=/workarea");
209 ASSERT_TRUE(bool(Params) && bool(ExpectedParams) && bool(Mappings));
210 applyPathMappings(*Params, PathMapping::Direction::ClientToServer, *Mappings);
211 EXPECT_EQ(*Params, *ExpectedParams);
214 } // namespace
215 } // namespace clangd
216 } // namespace clang