13#include "clang/Tooling/CompilationDatabase.h"
14#include "llvm/ADT/StringExtras.h"
15#include "llvm/Config/llvm-config.h"
16#include "llvm/Support/Compression.h"
17#include "llvm/Support/Error.h"
18#include "llvm/Support/ScopedPrinter.h"
19#include "gmock/gmock.h"
20#include "gtest/gtest.h"
22#include <sys/resource.h>
25using ::testing::ElementsAre;
27using ::testing::UnorderedElementsAre;
28using ::testing::UnorderedElementsAreArray;
44 FileURI: file:///path/foo.h
52Documentation: 'Foo doc'
57 Directives: [ Include ]
60 Directives: [ Import ]
63 Directives: [ Include, Import ]
77 FileURI: file:///path/bar.h
86CompletionSnippetSuffix: '-snippet'
93 FileURI: file:///path/foo.cc
115URI: 'file:///path/source1.cpp'
117Digest: EED8F5EAF25C453C
119 - 'file:///path/inc1.h'
120 - 'file:///path/inc2.h'
126MATCHER_P3(IncludeHeaderWithRefAndDirectives, IncludeHeader,
References,
127 SupportedDirectives,
"") {
128 return (arg.IncludeHeader == IncludeHeader) &&
130 (arg.SupportedDirectives == SupportedDirectives);
137TEST(SerializationTest, NoCrashOnEmptyYAML) {
141TEST(SerializationTest, YAMLConversions) {
143 ASSERT_TRUE(
bool(ParsedYAML)) << ParsedYAML.takeError();
144 ASSERT_TRUE(
bool(ParsedYAML->Symbols));
146 *ParsedYAML->Symbols,
147 UnorderedElementsAre(
id(
"057557CEBF6E6B2D"),
id(
"057557CEBF6E6B2E")));
149 auto Sym1 = *ParsedYAML->Symbols->find(
151 auto Sym2 = *ParsedYAML->Symbols->find(
154 EXPECT_THAT(Sym1, qName(
"clang::Foo1"));
155 EXPECT_EQ(Sym1.Signature,
"");
156 EXPECT_EQ(Sym1.Documentation,
"Foo doc");
157 EXPECT_EQ(Sym1.ReturnType,
"int");
158 EXPECT_EQ(StringRef(Sym1.CanonicalDeclaration.FileURI),
"file:///path/foo.h");
160 EXPECT_EQ(
static_cast<uint8_t
>(Sym1.Flags), 129);
165 UnorderedElementsAre(
167 IncludeHeaderWithRefAndDirectives(
"include2", 3u,
Symbol::Import),
168 IncludeHeaderWithRefAndDirectives(
"include3", 2u,
172 EXPECT_THAT(Sym2, qName(
"clang::Foo2"));
173 EXPECT_EQ(Sym2.Signature,
"-sig");
174 EXPECT_EQ(Sym2.ReturnType,
"");
175 EXPECT_EQ(llvm::StringRef(Sym2.CanonicalDeclaration.FileURI),
176 "file:///path/bar.h");
180 ASSERT_TRUE(
bool(ParsedYAML->Refs));
184 ::testing::SizeIs(1))));
185 auto Ref1 = ParsedYAML->Refs->begin()->second.front();
187 EXPECT_EQ(StringRef(Ref1.Location.FileURI),
"file:///path/foo.cc");
191 ASSERT_TRUE(
bool(ParsedYAML->Relations));
193 *ParsedYAML->Relations,
196 ASSERT_TRUE(
bool(ParsedYAML->Cmd));
197 auto &Cmd = *ParsedYAML->Cmd;
198 ASSERT_EQ(Cmd.Directory,
"testdir");
199 EXPECT_THAT(Cmd.CommandLine, ElementsAre(
"cmd1",
"cmd2"));
201 ASSERT_TRUE(
bool(ParsedYAML->Sources));
202 const auto *URI =
"file:///path/source1.cpp";
203 ASSERT_TRUE(ParsedYAML->Sources->count(URI));
204 auto IGNDeserialized = ParsedYAML->Sources->lookup(URI);
205 EXPECT_EQ(llvm::toHex(IGNDeserialized.Digest),
"EED8F5EAF25C453C");
206 EXPECT_THAT(IGNDeserialized.DirectIncludes,
207 ElementsAre(
"file:///path/inc1.h",
"file:///path/inc2.h"));
208 EXPECT_EQ(IGNDeserialized.URI, URI);
212std::vector<std::string> yamlFromSymbols(
const SymbolSlab &Slab) {
213 std::vector<std::string> Result;
214 for (
const auto &Sym : Slab)
215 Result.push_back(
toYAML(Sym));
218std::vector<std::string> yamlFromRefs(
const RefSlab &Slab) {
219 std::vector<std::string> Result;
220 for (
const auto &Refs : Slab)
221 Result.push_back(
toYAML(Refs));
225std::vector<std::string> yamlFromRelations(
const RelationSlab &Slab) {
226 std::vector<std::string> Result;
227 for (
const auto &Rel : Slab)
228 Result.push_back(
toYAML(Rel));
232TEST(SerializationTest, BinaryConversions) {
234 EXPECT_TRUE(
bool(In)) << In.takeError();
237 IndexFileOut
Out(*In);
239 std::string Serialized = llvm::to_string(
Out);
242 ASSERT_TRUE(
bool(In2)) << In2.takeError();
243 ASSERT_TRUE(In2->Symbols);
244 ASSERT_TRUE(In2->Refs);
245 ASSERT_TRUE(In2->Relations);
248 EXPECT_THAT(yamlFromSymbols(*In2->Symbols),
249 UnorderedElementsAreArray(yamlFromSymbols(*In->Symbols)));
250 EXPECT_THAT(yamlFromRefs(*In2->Refs),
251 UnorderedElementsAreArray(yamlFromRefs(*In->Refs)));
252 EXPECT_THAT(yamlFromRelations(*In2->Relations),
253 UnorderedElementsAreArray(yamlFromRelations(*In->Relations)));
256TEST(SerializationTest, SrcsTest) {
258 EXPECT_TRUE(
bool(In)) << In.takeError();
260 std::string TestContent(
"TestContent");
261 IncludeGraphNode IGN;
262 IGN.Digest =
digest(TestContent);
263 IGN.DirectIncludes = {
"inc1",
"inc2"};
268 Sources[IGN.URI] = IGN;
270 IndexFileOut
Out(*In);
272 Out.Sources = &Sources;
274 std::string Serialized = llvm::to_string(
Out);
277 ASSERT_TRUE(
bool(In)) << In.takeError();
278 ASSERT_TRUE(In->Symbols);
279 ASSERT_TRUE(In->Refs);
280 ASSERT_TRUE(In->Sources);
281 ASSERT_TRUE(In->Sources->count(IGN.URI));
283 EXPECT_THAT(yamlFromSymbols(*In->Symbols),
284 UnorderedElementsAreArray(yamlFromSymbols(*In->Symbols)));
285 EXPECT_THAT(yamlFromRefs(*In->Refs),
286 UnorderedElementsAreArray(yamlFromRefs(*In->Refs)));
287 auto IGNDeserialized = In->Sources->lookup(IGN.URI);
288 EXPECT_EQ(IGNDeserialized.Digest, IGN.Digest);
289 EXPECT_EQ(IGNDeserialized.DirectIncludes, IGN.DirectIncludes);
290 EXPECT_EQ(IGNDeserialized.URI, IGN.URI);
291 EXPECT_EQ(IGNDeserialized.Flags, IGN.Flags);
295TEST(SerializationTest, CmdlTest) {
297 EXPECT_TRUE(
bool(In)) << In.takeError();
299 tooling::CompileCommand Cmd;
300 Cmd.Directory =
"testdir";
301 Cmd.CommandLine.push_back(
"cmd1");
302 Cmd.CommandLine.push_back(
"cmd2");
303 Cmd.Filename =
"ignored";
304 Cmd.Heuristic =
"ignored";
305 Cmd.Output =
"ignored";
307 IndexFileOut
Out(*In);
311 std::string Serialized = llvm::to_string(
Out);
314 ASSERT_TRUE(
bool(In)) << In.takeError();
315 ASSERT_TRUE(In->Cmd);
317 const tooling::CompileCommand &SerializedCmd = *In->Cmd;
318 EXPECT_EQ(SerializedCmd.CommandLine, Cmd.CommandLine);
319 EXPECT_EQ(SerializedCmd.Directory, Cmd.Directory);
320 EXPECT_NE(SerializedCmd.Filename, Cmd.Filename);
321 EXPECT_NE(SerializedCmd.Heuristic, Cmd.Heuristic);
322 EXPECT_NE(SerializedCmd.Output, Cmd.Output);
328#if LLVM_ON_UNIX && defined(RLIMIT_AS) && !LLVM_ADDRESS_SANITIZER_BUILD && \
329 !LLVM_MEMORY_SANITIZER_BUILD && !LLVM_THREAD_SANITIZER_BUILD
330class ScopedMemoryLimit {
331 struct rlimit OriginalLimit;
332 bool Succeeded =
false;
335 ScopedMemoryLimit(rlim_t Bytes) {
336 if (!getrlimit(RLIMIT_AS, &OriginalLimit)) {
337 struct rlimit NewLimit = OriginalLimit;
338 NewLimit.rlim_cur = Bytes;
339 Succeeded = !setrlimit(RLIMIT_AS, &NewLimit);
342 log(
"Failed to set rlimit");
345 ~ScopedMemoryLimit() {
347 setrlimit(RLIMIT_AS, &OriginalLimit);
351class ScopedMemoryLimit {
353 ScopedMemoryLimit(
unsigned Bytes) {
log(
"rlimit unsupported"); }
359TEST(SerializationTest, NoCrashOnBadArraySize) {
363 ASSERT_FALSE(!In) << In.takeError();
364 IndexFileOut
Out(*In);
366 std::string Serialized = llvm::to_string(
Out);
370 ASSERT_FALSE(!Parsed) << Parsed.takeError();
371 auto Srcs = llvm::find_if(Parsed->Chunks, [](riff::Chunk
C) {
372 return C.ID == riff::fourCC(
"srcs");
374 ASSERT_NE(Srcs, Parsed->Chunks.end());
385 std::string
FileDigest = llvm::fromHex(
"EED8F5EAF25C453C");
387 ASSERT_NE(
Pos, StringRef::npos) <<
"Couldn't locate file digest";
392 std::string CorruptSrcs =
393 (Srcs->Data.take_front(
Pos) + llvm::fromHex(
"ffffffff0f") +
394 "some_random_garbage")
396 Srcs->Data = CorruptSrcs;
399 ScopedMemoryLimit MemLimit(1000 * 1024 * 1024);
401 std::string CorruptFile = llvm::to_string(*Parsed);
403 ASSERT_TRUE(!CorruptParsed);
404 EXPECT_EQ(llvm::toString(CorruptParsed.takeError()),
405 "malformed or truncated include uri");
410TEST(SerializationTest, NoCrashOnBadStringTableSize) {
411 if (!llvm::compression::zlib::isAvailable()) {
412 log(
"skipping test, no zlib");
418 ASSERT_FALSE(!In) << In.takeError();
419 IndexFileOut
Out(*In);
421 std::string Serialized = llvm::to_string(
Out);
425 ASSERT_FALSE(!Parsed) << Parsed.takeError();
426 auto Stri = llvm::find_if(Parsed->Chunks, [](riff::Chunk
C) {
427 return C.ID == riff::fourCC(
"stri");
429 ASSERT_NE(Stri, Parsed->Chunks.end());
433 std::string CorruptStri =
434 (llvm::fromHex(
"ffffffff") + Stri->Data.drop_front(4)).str();
435 Stri->Data = CorruptStri;
436 std::string
FileDigest = llvm::fromHex(
"EED8F5EAF25C453C");
439 ScopedMemoryLimit MemLimit(1000 * 1024 * 1024);
441 std::string CorruptFile = llvm::to_string(*Parsed);
443 ASSERT_TRUE(!CorruptParsed);
444 EXPECT_THAT(llvm::toString(CorruptParsed.takeError()),
445 testing::HasSubstr(
"bytes is implausible"));
llvm::SmallString< 256U > Name
CompiledFragmentImpl & Out
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
llvm::Expected< File > readFile(llvm::StringRef Stream)
llvm::Expected< IndexFileIn > readIndexFile(llvm::StringRef Data, SymbolOrigin Origin)
FileDigest digest(llvm::StringRef Content)
std::array< uint8_t, 8 > FileDigest
TEST(BackgroundQueueTest, Priority)
llvm::StringMap< IncludeGraphNode > IncludeGraph
void log(const char *Fmt, Ts &&... Vals)
std::string toYAML(const Symbol &)
std::array< uint8_t, 20 > SymbolID
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
@ IndexedForCodeCompletion
Whether or not this symbol is meant to be used for the code completion.
@ Deprecated
Indicates if the symbol is deprecated.
@ Include
#include "header.h"
@ Import
#import "header.h"