clang-tools  10.0.0git
PathMappingTests.cpp
Go to the documentation of this file.
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 //===----------------------------------------------------------------------===//
8 
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;
20 }
21 
22 bool failedParse(llvm::StringRef RawMappings) {
23  llvm::Expected<PathMappings> Mappings = parsePathMappings(RawMappings);
24  if (!Mappings) {
25  consumeError(Mappings.takeError());
26  return true;
27  }
28  return false;
29 }
30 
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")));
46 }
47 
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  // Aboslute 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")));
59 }
60 
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"));
72 }
73 
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")));
82 }
83 
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;
93 }
94 
95 TEST(DoPathMappingTests, PreservesOriginal) {
96  // Preserves original path when no mapping
97  EXPECT_TRUE(mapsProperly("file:///home", "file:///home", "",
99 }
100 
101 TEST(DoPathMappingTests, UsesFirstMatch) {
102  EXPECT_TRUE(mapsProperly("file:///home/foo.cpp", "file:///workarea1/foo.cpp",
103  "/home=/workarea1,/home=/workarea2",
105 }
106 
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",
112 }
113 
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",
119 }
120 
121 TEST(DoPathMappingTests, OnlyMapFileUris) {
122  EXPECT_TRUE(mapsProperly("test:///home/foo.cpp", "test:///home/foo.cpp",
123  "/home=/workarea",
125 }
126 
127 TEST(DoPathMappingTests, RespectsCaseSensitivity) {
128  EXPECT_TRUE(mapsProperly("file:///HOME/foo.cpp", "file:///HOME/foo.cpp",
129  "/home=/workarea",
131 }
132 
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)",
138 }
139 
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));
145 }
146 
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;
156  EXPECT_EQ(*Params, ExpectedParams);
157 }
158 
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));
172  EXPECT_EQ(*Params, *ExpectedParams);
173 }
174 
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));
192  EXPECT_EQ(*Params, *ExpectedParams);
193 }
194 
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": "..."}
200  }
201  })");
202  auto ExpectedParams = llvm::json::parse(R"({
203  "changes": {
204  "file:///workarea/foo.cpp": {"newText": "..."},
205  "file:///workarea/src/bar.cpp": {"newText": "..."}
206  }
207  })");
208  auto Mappings = parsePathMappings("/home=/workarea");
209  ASSERT_TRUE(bool(Params) && bool(ExpectedParams) && bool(Mappings));
211  EXPECT_EQ(*Params, *ExpectedParams);
212 }
213 
214 } // namespace
215 } // namespace clangd
216 } // namespace clang
std::vector< PathMapping > PathMappings
Definition: PathMapping.h:38
void applyPathMappings(llvm::json::Value &V, PathMapping::Direction Dir, const PathMappings &Mappings)
Applies the Mappings to all the file:// URIs in Params.
Definition: PathMapping.cpp:49
TEST(BackgroundQueueTest, Priority)
llvm::Expected< PathMappings > parsePathMappings(llvm::StringRef RawPathMappings)
Parse the command line RawPathMappings (e.g.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::vector< const char * > Expected
llvm::Optional< std::string > doPathMapping(llvm::StringRef S, PathMapping::Direction Dir, const PathMappings &Mappings)
Returns a modified S with the first matching path in Mappings substituted, if applicable.
Definition: PathMapping.cpp:21