1 | //===--- MarshallingTests.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 "../TestTU.h" |
10 | #include "Index.pb.h" |
11 | #include "TestFS.h" |
12 | #include "index/Index.h" |
13 | #include "index/Ref.h" |
14 | #include "index/Relation.h" |
15 | #include "index/Serialization.h" |
16 | #include "index/Symbol.h" |
17 | #include "index/SymbolID.h" |
18 | #include "index/SymbolLocation.h" |
19 | #include "index/SymbolOrigin.h" |
20 | #include "index/remote/marshalling/Marshalling.h" |
21 | #include "clang/Index/IndexSymbol.h" |
22 | #include "llvm/ADT/SmallString.h" |
23 | #include "llvm/ADT/StringRef.h" |
24 | #include "llvm/ADT/Twine.h" |
25 | #include "llvm/Support/Error.h" |
26 | #include "llvm/Support/Path.h" |
27 | #include "llvm/Support/StringSaver.h" |
28 | #include "gmock/gmock.h" |
29 | #include "gtest/gtest.h" |
30 | #include <cstring> |
31 | |
32 | namespace clang { |
33 | namespace clangd { |
34 | namespace remote { |
35 | namespace { |
36 | |
37 | using llvm::sys::path::convert_to_slash; |
38 | |
39 | const char *testPathURI(llvm::StringRef Path, |
40 | llvm::UniqueStringSaver &Strings) { |
41 | auto URI = URI::createFile(AbsolutePath: testPath(File: Path)); |
42 | return Strings.save(S: URI.toString()).begin(); |
43 | } |
44 | |
45 | clangd::Symbol createSymbol(llvm::StringRef PathPrefix, |
46 | llvm::UniqueStringSaver &Strings) { |
47 | clangd::Symbol Sym; |
48 | Sym.ID = llvm::cantFail(ValOrErr: SymbolID::fromStr("057557CEBF6E6B2D" )); |
49 | |
50 | index::SymbolInfo Info; |
51 | Info.Kind = index::SymbolKind::Function; |
52 | Info.SubKind = index::SymbolSubKind::AccessorGetter; |
53 | Info.Lang = index::SymbolLanguage::CXX; |
54 | Info.Properties = static_cast<index::SymbolPropertySet>( |
55 | index::SymbolProperty::TemplateSpecialization); |
56 | Sym.SymInfo = Info; |
57 | |
58 | Sym.Name = Strings.save(S: "Foo" ); |
59 | Sym.Scope = Strings.save(S: "llvm::foo::bar::" ); |
60 | |
61 | clangd::SymbolLocation Location; |
62 | Location.Start.setLine(1); |
63 | Location.Start.setColumn(15); |
64 | Location.End.setLine(3); |
65 | Location.End.setColumn(121); |
66 | Location.FileURI = testPathURI(Path: PathPrefix.str() + "Definition.cpp" , Strings); |
67 | Sym.Definition = Location; |
68 | |
69 | Location.Start.setLine(42); |
70 | Location.Start.setColumn(31); |
71 | Location.End.setLine(20); |
72 | Location.End.setColumn(400); |
73 | Location.FileURI = testPathURI(Path: PathPrefix.str() + "Declaration.h" , Strings); |
74 | Sym.CanonicalDeclaration = Location; |
75 | |
76 | Sym.References = 9000; |
77 | Sym.Origin = clangd::SymbolOrigin::Static; |
78 | Sym.Signature = Strings.save(S: "(int X, char Y, Type T)" ); |
79 | Sym.TemplateSpecializationArgs = Strings.save(S: "<int, char, bool, Type>" ); |
80 | Sym.CompletionSnippetSuffix = |
81 | Strings.save(S: "({1: int X}, {2: char Y}, {3: Type T})" ); |
82 | Sym.Documentation = Strings.save(S: "This is my amazing Foo constructor!" ); |
83 | Sym.ReturnType = Strings.save(S: "Foo" ); |
84 | |
85 | Sym.Flags = clangd::Symbol::SymbolFlag::IndexedForCodeCompletion; |
86 | |
87 | return Sym; |
88 | } |
89 | |
90 | TEST(RemoteMarshallingTest, URITranslation) { |
91 | llvm::BumpPtrAllocator Arena; |
92 | llvm::UniqueStringSaver Strings(Arena); |
93 | Marshaller ProtobufMarshaller( |
94 | testPath(File: "remote/machine/projects/llvm-project/" ), |
95 | testPath(File: "home/my-projects/llvm-project/" )); |
96 | clangd::Ref Original; |
97 | Original.Location.FileURI = |
98 | testPathURI(Path: "remote/machine/projects/llvm-project/clang-tools-extra/" |
99 | "clangd/unittests/remote/MarshallingTests.cpp" , |
100 | Strings); |
101 | auto Serialized = ProtobufMarshaller.toProtobuf(From: Original); |
102 | ASSERT_TRUE(bool(Serialized)); |
103 | EXPECT_EQ(Serialized->location().file_path(), |
104 | "clang-tools-extra/clangd/unittests/remote/MarshallingTests.cpp" ); |
105 | auto Deserialized = ProtobufMarshaller.fromProtobuf(Message: *Serialized); |
106 | ASSERT_TRUE(bool(Deserialized)); |
107 | EXPECT_STREQ(Deserialized->Location.FileURI, |
108 | testPathURI("home/my-projects/llvm-project/clang-tools-extra/" |
109 | "clangd/unittests/remote/MarshallingTests.cpp" , |
110 | Strings)); |
111 | |
112 | // Can't have empty paths. |
113 | *Serialized->mutable_location()->mutable_file_path() = std::string(); |
114 | Deserialized = ProtobufMarshaller.fromProtobuf(Message: *Serialized); |
115 | EXPECT_FALSE(bool(Deserialized)); |
116 | llvm::consumeError(Err: Deserialized.takeError()); |
117 | |
118 | clangd::Ref WithInvalidURI; |
119 | // Invalid URI results in serialization failure. |
120 | WithInvalidURI.Location.FileURI = "This is not a URI" ; |
121 | auto DeserializedRef = ProtobufMarshaller.toProtobuf(From: WithInvalidURI); |
122 | EXPECT_FALSE(bool(DeserializedRef)); |
123 | llvm::consumeError(Err: DeserializedRef.takeError()); |
124 | |
125 | // Can not use URIs with scheme different from "file". |
126 | auto UnittestURI = |
127 | URI::create(AbsolutePath: testPath(File: "project/lib/HelloWorld.cpp" ), Scheme: "unittest" ); |
128 | ASSERT_TRUE(bool(UnittestURI)); |
129 | WithInvalidURI.Location.FileURI = |
130 | Strings.save(S: UnittestURI->toString()).begin(); |
131 | auto DeserializedSymbol = ProtobufMarshaller.toProtobuf(From: WithInvalidURI); |
132 | EXPECT_FALSE(bool(DeserializedSymbol)); |
133 | llvm::consumeError(Err: DeserializedSymbol.takeError()); |
134 | |
135 | // Paths transmitted over the wire can not be absolute, they have to be |
136 | // relative. |
137 | Ref WithAbsolutePath; |
138 | *WithAbsolutePath.mutable_location()->mutable_file_path() = |
139 | "/usr/local/user/home/HelloWorld.cpp" ; |
140 | Deserialized = ProtobufMarshaller.fromProtobuf(Message: WithAbsolutePath); |
141 | EXPECT_FALSE(bool(Deserialized)); |
142 | llvm::consumeError(Err: Deserialized.takeError()); |
143 | } |
144 | |
145 | TEST(RemoteMarshallingTest, SymbolSerialization) { |
146 | llvm::BumpPtrAllocator Arena; |
147 | llvm::UniqueStringSaver Strings(Arena); |
148 | |
149 | clangd::Symbol Sym = createSymbol(PathPrefix: "home/" , Strings); |
150 | Marshaller ProtobufMarshaller(testPath(File: "home/" ), testPath(File: "home/" )); |
151 | |
152 | // Check that symbols are exactly the same if the path to indexed project is |
153 | // the same on indexing machine and the client. |
154 | auto Serialized = ProtobufMarshaller.toProtobuf(From: Sym); |
155 | ASSERT_TRUE(bool(Serialized)); |
156 | auto Deserialized = ProtobufMarshaller.fromProtobuf(Message: *Serialized); |
157 | ASSERT_TRUE(bool(Deserialized)); |
158 | // Origin is overwritten when deserializing. |
159 | Sym.Origin = SymbolOrigin::Remote; |
160 | EXPECT_EQ(toYAML(Sym), toYAML(*Deserialized)); |
161 | // Serialized paths are relative and have UNIX slashes. |
162 | EXPECT_EQ(convert_to_slash(Serialized->definition().file_path(), |
163 | llvm::sys::path::Style::posix), |
164 | Serialized->definition().file_path()); |
165 | EXPECT_TRUE( |
166 | llvm::sys::path::is_relative(Serialized->definition().file_path())); |
167 | |
168 | // Missing definition is OK. |
169 | Sym.Definition = clangd::SymbolLocation(); |
170 | Serialized = ProtobufMarshaller.toProtobuf(From: Sym); |
171 | ASSERT_TRUE(bool(Serialized)); |
172 | ASSERT_TRUE(bool(ProtobufMarshaller.fromProtobuf(*Serialized))); |
173 | |
174 | // Relative path is absolute. |
175 | *Serialized->mutable_canonical_declaration()->mutable_file_path() = |
176 | convert_to_slash(path: "/path/to/Declaration.h" ); |
177 | Deserialized = ProtobufMarshaller.fromProtobuf(Message: *Serialized); |
178 | EXPECT_FALSE(bool(Deserialized)); |
179 | llvm::consumeError(Err: Deserialized.takeError()); |
180 | |
181 | // Fail with an invalid URI. |
182 | Sym.Definition.FileURI = "Not A URI" ; |
183 | Serialized = ProtobufMarshaller.toProtobuf(From: Sym); |
184 | EXPECT_FALSE(bool(Serialized)); |
185 | llvm::consumeError(Err: Serialized.takeError()); |
186 | |
187 | // Schemes other than "file" can not be used. |
188 | auto UnittestURI = URI::create(AbsolutePath: testPath(File: "home/SomePath.h" ), Scheme: "unittest" ); |
189 | ASSERT_TRUE(bool(UnittestURI)); |
190 | Sym.Definition.FileURI = Strings.save(S: UnittestURI->toString()).begin(); |
191 | Serialized = ProtobufMarshaller.toProtobuf(From: Sym); |
192 | EXPECT_FALSE(bool(Serialized)); |
193 | llvm::consumeError(Err: Serialized.takeError()); |
194 | |
195 | // Passing root that is not prefix of the original file path. |
196 | Sym.Definition.FileURI = testPathURI(Path: "home/File.h" , Strings); |
197 | // Check that the symbol is valid and passing the correct path works. |
198 | Serialized = ProtobufMarshaller.toProtobuf(From: Sym); |
199 | ASSERT_TRUE(bool(Serialized)); |
200 | Deserialized = ProtobufMarshaller.fromProtobuf(Message: *Serialized); |
201 | ASSERT_TRUE(bool(Deserialized)); |
202 | EXPECT_STREQ(Deserialized->Definition.FileURI, |
203 | testPathURI("home/File.h" , Strings)); |
204 | // Fail with a wrong root. |
205 | Marshaller WrongMarshaller(testPath(File: "nothome/" ), testPath(File: "home/" )); |
206 | Serialized = WrongMarshaller.toProtobuf(From: Sym); |
207 | EXPECT_FALSE(Serialized); |
208 | llvm::consumeError(Err: Serialized.takeError()); |
209 | } |
210 | |
211 | TEST(RemoteMarshallingTest, RefSerialization) { |
212 | clangd::Ref Ref; |
213 | Ref.Kind = clangd::RefKind::Spelled | clangd::RefKind::Declaration; |
214 | |
215 | llvm::BumpPtrAllocator Arena; |
216 | llvm::UniqueStringSaver Strings(Arena); |
217 | |
218 | clangd::SymbolLocation Location; |
219 | Location.Start.setLine(124); |
220 | Location.Start.setColumn(21); |
221 | Location.End.setLine(3213); |
222 | Location.End.setColumn(541); |
223 | Location.FileURI = testPathURI( |
224 | Path: "llvm-project/llvm/clang-tools-extra/clangd/Protocol.h" , Strings); |
225 | Ref.Location = Location; |
226 | |
227 | Marshaller ProtobufMarshaller(testPath(File: "llvm-project/" ), |
228 | testPath(File: "llvm-project/" )); |
229 | |
230 | auto Serialized = ProtobufMarshaller.toProtobuf(From: Ref); |
231 | ASSERT_TRUE(bool(Serialized)); |
232 | auto Deserialized = ProtobufMarshaller.fromProtobuf(Message: *Serialized); |
233 | ASSERT_TRUE(bool(Deserialized)); |
234 | EXPECT_EQ(toYAML(Ref), toYAML(*Deserialized)); |
235 | } |
236 | |
237 | TEST(RemoteMarshallingTest, IncludeHeaderURIs) { |
238 | llvm::BumpPtrAllocator Arena; |
239 | llvm::UniqueStringSaver Strings(Arena); |
240 | |
241 | clangd::Symbol Sym = createSymbol(PathPrefix: "remote/" , Strings); |
242 | |
243 | clangd::Symbol::IncludeHeaderWithReferences ; |
244 | // Add only valid headers. |
245 | Header.IncludeHeader = |
246 | Strings.save(S: URI::createFile(AbsolutePath: testPath(File: "project/Header.h" )).toString()); |
247 | Header.References = 21; |
248 | Sym.IncludeHeaders.push_back(Elt: Header); |
249 | Header.IncludeHeader = Strings.save(S: "<iostream>" ); |
250 | Header.References = 100; |
251 | Sym.IncludeHeaders.push_back(Elt: Header); |
252 | Header.IncludeHeader = Strings.save(S: "\"cstdio\"" ); |
253 | Header.References = 200; |
254 | Sym.IncludeHeaders.push_back(Elt: Header); |
255 | |
256 | Marshaller ProtobufMarshaller(testPath(File: "" ), testPath(File: "" )); |
257 | |
258 | auto Serialized = ProtobufMarshaller.toProtobuf(From: Sym); |
259 | ASSERT_TRUE(bool(Serialized)); |
260 | EXPECT_EQ(static_cast<size_t>(Serialized->headers_size()), |
261 | Sym.IncludeHeaders.size()); |
262 | auto Deserialized = ProtobufMarshaller.fromProtobuf(Message: *Serialized); |
263 | ASSERT_TRUE(bool(Deserialized)); |
264 | Sym.Origin = SymbolOrigin::Remote; |
265 | EXPECT_EQ(toYAML(Sym), toYAML(*Deserialized)); |
266 | |
267 | // This is an absolute path to a header: can not be transmitted over the wire. |
268 | Header.IncludeHeader = Strings.save(S: testPath(File: "project/include/Common.h" )); |
269 | Header.References = 42; |
270 | Sym.IncludeHeaders.push_back(Elt: Header); |
271 | Serialized = ProtobufMarshaller.toProtobuf(From: Sym); |
272 | EXPECT_FALSE(bool(Serialized)); |
273 | llvm::consumeError(Err: Serialized.takeError()); |
274 | |
275 | // Remove last invalid header. |
276 | Sym.IncludeHeaders.pop_back(); |
277 | // This is not a valid header: can not be transmitted over the wire; |
278 | Header.IncludeHeader = Strings.save(S: "NotAHeader" ); |
279 | Header.References = 5; |
280 | Sym.IncludeHeaders.push_back(Elt: Header); |
281 | Serialized = ProtobufMarshaller.toProtobuf(From: Sym); |
282 | EXPECT_FALSE(bool(Serialized)); |
283 | llvm::consumeError(Err: Serialized.takeError()); |
284 | |
285 | // Try putting an invalid header into already serialized symbol. |
286 | Sym.IncludeHeaders.pop_back(); |
287 | Serialized = ProtobufMarshaller.toProtobuf(From: Sym); |
288 | ASSERT_TRUE(bool(Serialized)); |
289 | HeaderWithReferences ; |
290 | InvalidHeader.set_header(convert_to_slash(path: "/absolute/path/Header.h" )); |
291 | InvalidHeader.set_references(9000); |
292 | *Serialized->add_headers() = InvalidHeader; |
293 | Deserialized = ProtobufMarshaller.fromProtobuf(Message: *Serialized); |
294 | EXPECT_FALSE(bool(Deserialized)); |
295 | llvm::consumeError(Err: Deserialized.takeError()); |
296 | } |
297 | |
298 | TEST(RemoteMarshallingTest, LookupRequestSerialization) { |
299 | clangd::LookupRequest Request; |
300 | Request.IDs.insert(V: llvm::cantFail(ValOrErr: SymbolID::fromStr("0000000000000001" ))); |
301 | Request.IDs.insert(V: llvm::cantFail(ValOrErr: SymbolID::fromStr("0000000000000002" ))); |
302 | |
303 | Marshaller ProtobufMarshaller(testPath(File: "remote/" ), testPath(File: "local/" )); |
304 | |
305 | auto Serialized = ProtobufMarshaller.toProtobuf(From: Request); |
306 | EXPECT_EQ(static_cast<unsigned>(Serialized.ids_size()), Request.IDs.size()); |
307 | auto Deserialized = ProtobufMarshaller.fromProtobuf(Message: &Serialized); |
308 | ASSERT_TRUE(bool(Deserialized)); |
309 | EXPECT_EQ(Deserialized->IDs, Request.IDs); |
310 | } |
311 | |
312 | TEST(RemoteMarshallingTest, LookupRequestFailingSerialization) { |
313 | clangd::LookupRequest Request; |
314 | Marshaller ProtobufMarshaller(testPath(File: "remote/" ), testPath(File: "local/" )); |
315 | auto Serialized = ProtobufMarshaller.toProtobuf(From: Request); |
316 | Serialized.add_ids("Invalid Symbol ID" ); |
317 | auto Deserialized = ProtobufMarshaller.fromProtobuf(Message: &Serialized); |
318 | EXPECT_FALSE(bool(Deserialized)); |
319 | llvm::consumeError(Err: Deserialized.takeError()); |
320 | } |
321 | |
322 | TEST(RemoteMarshallingTest, FuzzyFindRequestSerialization) { |
323 | clangd::FuzzyFindRequest Request; |
324 | Request.ProximityPaths = {testPath(File: "local/Header.h" ), |
325 | testPath(File: "local/subdir/OtherHeader.h" ), |
326 | testPath(File: "remote/File.h" ), "Not a Path." }; |
327 | Marshaller ProtobufMarshaller(testPath(File: "remote/" ), testPath(File: "local/" )); |
328 | auto Serialized = ProtobufMarshaller.toProtobuf(From: Request); |
329 | EXPECT_EQ(Serialized.proximity_paths_size(), 2); |
330 | auto Deserialized = ProtobufMarshaller.fromProtobuf(Message: &Serialized); |
331 | ASSERT_TRUE(bool(Deserialized)); |
332 | EXPECT_THAT(Deserialized->ProximityPaths, |
333 | testing::ElementsAre(testPath("remote/Header.h" ), |
334 | testPath("remote/subdir/OtherHeader.h" ))); |
335 | } |
336 | |
337 | TEST(RemoteMarshallingTest, RefsRequestSerialization) { |
338 | clangd::RefsRequest Request; |
339 | Request.IDs.insert(V: llvm::cantFail(ValOrErr: SymbolID::fromStr("0000000000000001" ))); |
340 | Request.IDs.insert(V: llvm::cantFail(ValOrErr: SymbolID::fromStr("0000000000000002" ))); |
341 | |
342 | Request.Limit = 9000; |
343 | Request.Filter = RefKind::Spelled | RefKind::Declaration; |
344 | |
345 | Marshaller ProtobufMarshaller(testPath(File: "remote/" ), testPath(File: "local/" )); |
346 | |
347 | auto Serialized = ProtobufMarshaller.toProtobuf(From: Request); |
348 | EXPECT_EQ(static_cast<unsigned>(Serialized.ids_size()), Request.IDs.size()); |
349 | EXPECT_EQ(Serialized.limit(), Request.Limit); |
350 | auto Deserialized = ProtobufMarshaller.fromProtobuf(Message: &Serialized); |
351 | ASSERT_TRUE(bool(Deserialized)); |
352 | EXPECT_EQ(Deserialized->IDs, Request.IDs); |
353 | ASSERT_TRUE(Deserialized->Limit); |
354 | EXPECT_EQ(*Deserialized->Limit, Request.Limit); |
355 | EXPECT_EQ(Deserialized->Filter, Request.Filter); |
356 | } |
357 | |
358 | TEST(RemoteMarshallingTest, RefsRequestFailingSerialization) { |
359 | clangd::RefsRequest Request; |
360 | Marshaller ProtobufMarshaller(testPath(File: "remote/" ), testPath(File: "local/" )); |
361 | auto Serialized = ProtobufMarshaller.toProtobuf(From: Request); |
362 | Serialized.add_ids("Invalid Symbol ID" ); |
363 | auto Deserialized = ProtobufMarshaller.fromProtobuf(Message: &Serialized); |
364 | EXPECT_FALSE(bool(Deserialized)); |
365 | llvm::consumeError(Err: Deserialized.takeError()); |
366 | } |
367 | |
368 | TEST(RemoteMarshallingTest, RelationsRequestSerialization) { |
369 | clangd::RelationsRequest Request; |
370 | Request.Subjects.insert( |
371 | V: llvm::cantFail(ValOrErr: SymbolID::fromStr("0000000000000001" ))); |
372 | Request.Subjects.insert( |
373 | V: llvm::cantFail(ValOrErr: SymbolID::fromStr("0000000000000002" ))); |
374 | |
375 | Request.Limit = 9000; |
376 | Request.Predicate = RelationKind::BaseOf; |
377 | |
378 | Marshaller ProtobufMarshaller(testPath(File: "remote/" ), testPath(File: "local/" )); |
379 | |
380 | auto Serialized = ProtobufMarshaller.toProtobuf(From: Request); |
381 | EXPECT_EQ(static_cast<unsigned>(Serialized.subjects_size()), |
382 | Request.Subjects.size()); |
383 | EXPECT_EQ(Serialized.limit(), Request.Limit); |
384 | EXPECT_EQ(static_cast<RelationKind>(Serialized.predicate()), |
385 | Request.Predicate); |
386 | auto Deserialized = ProtobufMarshaller.fromProtobuf(Message: &Serialized); |
387 | ASSERT_TRUE(bool(Deserialized)); |
388 | EXPECT_EQ(Deserialized->Subjects, Request.Subjects); |
389 | ASSERT_TRUE(Deserialized->Limit); |
390 | EXPECT_EQ(*Deserialized->Limit, Request.Limit); |
391 | EXPECT_EQ(Deserialized->Predicate, Request.Predicate); |
392 | } |
393 | |
394 | TEST(RemoteMarshallingTest, RelationsRequestFailingSerialization) { |
395 | RelationsRequest Serialized; |
396 | Serialized.add_subjects("ZZZZZZZZZZZZZZZZ" ); |
397 | Marshaller ProtobufMarshaller(testPath(File: "remote/" ), testPath(File: "local/" )); |
398 | auto Deserialized = ProtobufMarshaller.fromProtobuf(Message: &Serialized); |
399 | EXPECT_FALSE(bool(Deserialized)); |
400 | llvm::consumeError(Err: Deserialized.takeError()); |
401 | } |
402 | |
403 | TEST(RemoteMarshallingTest, RelationsSerializion) { |
404 | llvm::BumpPtrAllocator Arena; |
405 | llvm::UniqueStringSaver Strings(Arena); |
406 | |
407 | clangd::Symbol Sym = createSymbol(PathPrefix: "remote/" , Strings); |
408 | SymbolID ID = llvm::cantFail(ValOrErr: SymbolID::fromStr("0000000000000002" )); |
409 | Marshaller ProtobufMarshaller(testPath(File: "remote/" ), testPath(File: "local/" )); |
410 | auto Serialized = ProtobufMarshaller.toProtobuf(Subject: ID, Object: Sym); |
411 | ASSERT_TRUE(bool(Serialized)); |
412 | auto Deserialized = ProtobufMarshaller.fromProtobuf(Message: *Serialized); |
413 | ASSERT_TRUE(bool(Deserialized)); |
414 | EXPECT_THAT(Deserialized->first, ID); |
415 | EXPECT_THAT(Deserialized->second.ID, Sym.ID); |
416 | } |
417 | |
418 | TEST(RemoteMarshallingTest, RelativePathToURITranslation) { |
419 | Marshaller ProtobufMarshaller(/*RemoteIndexRoot=*/"" , |
420 | /*LocalIndexRoot=*/testPath(File: "home/project/" )); |
421 | auto URIString = ProtobufMarshaller.relativePathToURI(RelativePath: "lib/File.cpp" ); |
422 | ASSERT_TRUE(bool(URIString)); |
423 | // RelativePath can not be absolute. |
424 | URIString = ProtobufMarshaller.relativePathToURI(RelativePath: "/lib/File.cpp" ); |
425 | EXPECT_FALSE(bool(URIString)); |
426 | llvm::consumeError(Err: URIString.takeError()); |
427 | // RelativePath can not be empty. |
428 | URIString = ProtobufMarshaller.relativePathToURI(RelativePath: std::string()); |
429 | EXPECT_FALSE(bool(URIString)); |
430 | llvm::consumeError(Err: URIString.takeError()); |
431 | } |
432 | |
433 | TEST(RemoteMarshallingTest, URIToRelativePathTranslation) { |
434 | llvm::BumpPtrAllocator Arena; |
435 | llvm::UniqueStringSaver Strings(Arena); |
436 | Marshaller ProtobufMarshaller(/*RemoteIndexRoot=*/testPath(File: "remote/project/" ), |
437 | /*LocalIndexRoot=*/"" ); |
438 | auto RelativePath = ProtobufMarshaller.uriToRelativePath( |
439 | URI: testPathURI(Path: "remote/project/lib/File.cpp" , Strings)); |
440 | ASSERT_TRUE(bool(RelativePath)); |
441 | // RemoteIndexRoot has to be a prefix of the file path. |
442 | Marshaller WrongMarshaller( |
443 | /*RemoteIndexRoot=*/testPath(File: "remote/other/project/" ), |
444 | /*LocalIndexRoot=*/"" ); |
445 | RelativePath = WrongMarshaller.uriToRelativePath( |
446 | URI: testPathURI(Path: "remote/project/lib/File.cpp" , Strings)); |
447 | EXPECT_FALSE(bool(RelativePath)); |
448 | llvm::consumeError(Err: RelativePath.takeError()); |
449 | } |
450 | |
451 | } // namespace |
452 | } // namespace remote |
453 | } // namespace clangd |
454 | } // namespace clang |
455 | |