clang-tools  10.0.0
SerializationTests.cpp
Go to the documentation of this file.
1 //===-- SerializationTests.cpp - Binary and YAML serialization unit tests -===//
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 "Headers.h"
10 #include "index/Index.h"
11 #include "index/Serialization.h"
12 #include "clang/Tooling/CompilationDatabase.h"
13 #include "llvm/Support/ScopedPrinter.h"
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
16 
17 using ::testing::_;
18 using ::testing::AllOf;
19 using ::testing::Pair;
20 using ::testing::UnorderedElementsAre;
21 using ::testing::UnorderedElementsAreArray;
22 
23 namespace clang {
24 namespace clangd {
25 namespace {
26 
27 const char *YAML = R"(
28 ---
29 !Symbol
30 ID: 057557CEBF6E6B2D
31 Name: 'Foo1'
32 Scope: 'clang::'
33 SymInfo:
34  Kind: Function
35  Lang: Cpp
36 CanonicalDeclaration:
37  FileURI: file:///path/foo.h
38  Start:
39  Line: 1
40  Column: 0
41  End:
42  Line: 1
43  Column: 1
44 Origin: 128
45 Flags: 129
46 Documentation: 'Foo doc'
47 ReturnType: 'int'
48 IncludeHeaders:
49  - Header: 'include1'
50  References: 7
51  - Header: 'include2'
52  References: 3
53 ...
54 ---
55 !Symbol
56 ID: 057557CEBF6E6B2E
57 Name: 'Foo2'
58 Scope: 'clang::'
59 SymInfo:
60  Kind: Function
61  Lang: Cpp
62 CanonicalDeclaration:
63  FileURI: file:///path/bar.h
64  Start:
65  Line: 1
66  Column: 0
67  End:
68  Line: 1
69  Column: 1
70 Flags: 2
71 Signature: '-sig'
72 CompletionSnippetSuffix: '-snippet'
73 ...
74 !Refs
75 ID: 057557CEBF6E6B2D
76 References:
77  - Kind: 4
78  Location:
79  FileURI: file:///path/foo.cc
80  Start:
81  Line: 5
82  Column: 3
83  End:
84  Line: 5
85  Column: 8
86 ...
87 --- !Relations
88 Subject:
89  ID: 6481EE7AF2841756
90 Predicate: 0
91 Object:
92  ID: 6512AEC512EA3A2D
93 ...
94 )";
95 
96 MATCHER_P(ID, I, "") { return arg.ID == cantFail(SymbolID::fromStr(I)); }
97 MATCHER_P(QName, Name, "") { return (arg.Scope + arg.Name).str() == Name; }
98 MATCHER_P2(IncludeHeaderWithRef, IncludeHeader, References, "") {
99  return (arg.IncludeHeader == IncludeHeader) && (arg.References == References);
100 }
101 
102 TEST(SerializationTest, NoCrashOnEmptyYAML) {
103  EXPECT_TRUE(bool(readIndexFile("")));
104 }
105 
106 TEST(SerializationTest, YAMLConversions) {
107  auto In = readIndexFile(YAML);
108  EXPECT_TRUE(bool(In)) << In.takeError();
109 
110  auto ParsedYAML = readIndexFile(YAML);
111  ASSERT_TRUE(bool(ParsedYAML)) << ParsedYAML.takeError();
112  ASSERT_TRUE(bool(ParsedYAML->Symbols));
113  EXPECT_THAT(
114  *ParsedYAML->Symbols,
115  UnorderedElementsAre(ID("057557CEBF6E6B2D"), ID("057557CEBF6E6B2E")));
116 
117  auto Sym1 = *ParsedYAML->Symbols->find(
118  cantFail(SymbolID::fromStr("057557CEBF6E6B2D")));
119  auto Sym2 = *ParsedYAML->Symbols->find(
120  cantFail(SymbolID::fromStr("057557CEBF6E6B2E")));
121 
122  EXPECT_THAT(Sym1, QName("clang::Foo1"));
123  EXPECT_EQ(Sym1.Signature, "");
124  EXPECT_EQ(Sym1.Documentation, "Foo doc");
125  EXPECT_EQ(Sym1.ReturnType, "int");
126  EXPECT_EQ(StringRef(Sym1.CanonicalDeclaration.FileURI), "file:///path/foo.h");
127  EXPECT_EQ(Sym1.Origin, static_cast<SymbolOrigin>(1 << 7));
128  EXPECT_EQ(static_cast<uint8_t>(Sym1.Flags), 129);
129  EXPECT_TRUE(Sym1.Flags & Symbol::IndexedForCodeCompletion);
130  EXPECT_FALSE(Sym1.Flags & Symbol::Deprecated);
131  EXPECT_THAT(Sym1.IncludeHeaders,
132  UnorderedElementsAre(IncludeHeaderWithRef("include1", 7u),
133  IncludeHeaderWithRef("include2", 3u)));
134 
135  EXPECT_THAT(Sym2, QName("clang::Foo2"));
136  EXPECT_EQ(Sym2.Signature, "-sig");
137  EXPECT_EQ(Sym2.ReturnType, "");
138  EXPECT_EQ(llvm::StringRef(Sym2.CanonicalDeclaration.FileURI),
139  "file:///path/bar.h");
140  EXPECT_FALSE(Sym2.Flags & Symbol::IndexedForCodeCompletion);
141  EXPECT_TRUE(Sym2.Flags & Symbol::Deprecated);
142 
143  ASSERT_TRUE(bool(ParsedYAML->Refs));
144  EXPECT_THAT(
145  *ParsedYAML->Refs,
146  UnorderedElementsAre(Pair(cantFail(SymbolID::fromStr("057557CEBF6E6B2D")),
147  ::testing::SizeIs(1))));
148  auto Ref1 = ParsedYAML->Refs->begin()->second.front();
149  EXPECT_EQ(Ref1.Kind, RefKind::Reference);
150  EXPECT_EQ(StringRef(Ref1.Location.FileURI), "file:///path/foo.cc");
151 
152  SymbolID Base = cantFail(SymbolID::fromStr("6481EE7AF2841756"));
153  SymbolID Derived = cantFail(SymbolID::fromStr("6512AEC512EA3A2D"));
154  ASSERT_TRUE(bool(ParsedYAML->Relations));
155  EXPECT_THAT(
156  *ParsedYAML->Relations,
157  UnorderedElementsAre(Relation{Base, RelationKind::BaseOf, Derived}));
158 }
159 
160 std::vector<std::string> YAMLFromSymbols(const SymbolSlab &Slab) {
161  std::vector<std::string> Result;
162  for (const auto &Sym : Slab)
163  Result.push_back(toYAML(Sym));
164  return Result;
165 }
166 std::vector<std::string> YAMLFromRefs(const RefSlab &Slab) {
167  std::vector<std::string> Result;
168  for (const auto &Refs : Slab)
169  Result.push_back(toYAML(Refs));
170  return Result;
171 }
172 
173 std::vector<std::string> YAMLFromRelations(const RelationSlab &Slab) {
174  std::vector<std::string> Result;
175  for (const auto &Rel : Slab)
176  Result.push_back(toYAML(Rel));
177  return Result;
178 }
179 
180 TEST(SerializationTest, BinaryConversions) {
181  auto In = readIndexFile(YAML);
182  EXPECT_TRUE(bool(In)) << In.takeError();
183 
184  // Write to binary format, and parse again.
185  IndexFileOut Out(*In);
186  Out.Format = IndexFileFormat::RIFF;
187  std::string Serialized = llvm::to_string(Out);
188 
189  auto In2 = readIndexFile(Serialized);
190  ASSERT_TRUE(bool(In2)) << In.takeError();
191  ASSERT_TRUE(In2->Symbols);
192  ASSERT_TRUE(In2->Refs);
193  ASSERT_TRUE(In2->Relations);
194 
195  // Assert the YAML serializations match, for nice comparisons and diffs.
196  EXPECT_THAT(YAMLFromSymbols(*In2->Symbols),
197  UnorderedElementsAreArray(YAMLFromSymbols(*In->Symbols)));
198  EXPECT_THAT(YAMLFromRefs(*In2->Refs),
199  UnorderedElementsAreArray(YAMLFromRefs(*In->Refs)));
200  EXPECT_THAT(YAMLFromRelations(*In2->Relations),
201  UnorderedElementsAreArray(YAMLFromRelations(*In->Relations)));
202 }
203 
204 TEST(SerializationTest, SrcsTest) {
205  auto In = readIndexFile(YAML);
206  EXPECT_TRUE(bool(In)) << In.takeError();
207 
208  std::string TestContent("TestContent");
209  IncludeGraphNode IGN;
210  IGN.Digest = digest(TestContent);
211  IGN.DirectIncludes = {"inc1", "inc2"};
212  IGN.URI = "URI";
215  IncludeGraph Sources;
216  Sources[IGN.URI] = IGN;
217  // Write to binary format, and parse again.
218  IndexFileOut Out(*In);
219  Out.Format = IndexFileFormat::RIFF;
220  Out.Sources = &Sources;
221  {
222  std::string Serialized = llvm::to_string(Out);
223 
224  auto In = readIndexFile(Serialized);
225  ASSERT_TRUE(bool(In)) << In.takeError();
226  ASSERT_TRUE(In->Symbols);
227  ASSERT_TRUE(In->Refs);
228  ASSERT_TRUE(In->Sources);
229  ASSERT_TRUE(In->Sources->count(IGN.URI));
230  // Assert the YAML serializations match, for nice comparisons and diffs.
231  EXPECT_THAT(YAMLFromSymbols(*In->Symbols),
232  UnorderedElementsAreArray(YAMLFromSymbols(*In->Symbols)));
233  EXPECT_THAT(YAMLFromRefs(*In->Refs),
234  UnorderedElementsAreArray(YAMLFromRefs(*In->Refs)));
235  auto IGNDeserialized = In->Sources->lookup(IGN.URI);
236  EXPECT_EQ(IGNDeserialized.Digest, IGN.Digest);
237  EXPECT_EQ(IGNDeserialized.DirectIncludes, IGN.DirectIncludes);
238  EXPECT_EQ(IGNDeserialized.URI, IGN.URI);
239  EXPECT_EQ(IGNDeserialized.Flags, IGN.Flags);
240  }
241 }
242 
243 TEST(SerializationTest, CmdlTest) {
244  auto In = readIndexFile(YAML);
245  EXPECT_TRUE(bool(In)) << In.takeError();
246 
247  tooling::CompileCommand Cmd;
248  Cmd.Directory = "testdir";
249  Cmd.CommandLine.push_back("cmd1");
250  Cmd.CommandLine.push_back("cmd2");
251  Cmd.Filename = "ignored";
252  Cmd.Heuristic = "ignored";
253  Cmd.Output = "ignored";
254 
255  IndexFileOut Out(*In);
256  Out.Format = IndexFileFormat::RIFF;
257  Out.Cmd = &Cmd;
258  {
259  std::string Serialized = llvm::to_string(Out);
260 
261  auto In = readIndexFile(Serialized);
262  ASSERT_TRUE(bool(In)) << In.takeError();
263  ASSERT_TRUE(In->Cmd);
264 
265  const tooling::CompileCommand &SerializedCmd = In->Cmd.getValue();
266  EXPECT_EQ(SerializedCmd.CommandLine, Cmd.CommandLine);
267  EXPECT_EQ(SerializedCmd.Directory, Cmd.Directory);
268  EXPECT_NE(SerializedCmd.Filename, Cmd.Filename);
269  EXPECT_NE(SerializedCmd.Heuristic, Cmd.Heuristic);
270  EXPECT_NE(SerializedCmd.Output, Cmd.Output);
271  }
272 }
273 } // namespace
274 } // namespace clangd
275 } // namespace clang
MATCHER_P(Named, N, "")
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Definition: SymbolID.cpp:35
llvm::Expected< IndexFileIn > readIndexFile(llvm::StringRef Data)
std::string toYAML(const Symbol &)
llvm::StringMap< IncludeGraphNode > IncludeGraph
Definition: Headers.h:82
std::string QName
Whether or not this symbol is meant to be used for the code completion.
Definition: Symbol.h:119
TEST(BackgroundQueueTest, Priority)
static constexpr llvm::StringLiteral Name
FileDigest digest(llvm::StringRef Content)
Definition: SourceCode.cpp:675
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
unsigned References
std::string IncludeHeader
Indicates if the symbol is deprecated.
Definition: Symbol.h:121
RefSlab Refs
std::unique_ptr< GlobalCompilationDatabase > Base
std::array< uint8_t, 20 > SymbolID