blob: 9a5ca4863d97d6196642947d400f2e3a438f3952 [file] [log] [blame]
//===-- HeadersTests.cpp - Include headers unit tests -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Headers.h"
#include "TestFS.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace clang {
namespace clangd {
namespace {
class HeadersTest : public ::testing::Test {
public:
HeadersTest() {
CDB.ExtraClangFlags = {SearchDirArg.c_str()};
FS.Files[MainFile] = "";
}
protected:
// Calculates the include path, or returns "" on error.
std::string calculate(PathRef Original, PathRef Preferred = "",
bool ExpectError = false) {
if (Preferred.empty())
Preferred = Original;
auto VFS = FS.getFileSystem();
auto Cmd = CDB.getCompileCommand(MainFile);
assert(static_cast<bool>(Cmd));
VFS->setCurrentWorkingDirectory(Cmd->Directory);
auto ToHeaderFile = [](llvm::StringRef Header) {
return HeaderFile{Header,
/*Verbatim=*/!llvm::sys::path::is_absolute(Header)};
};
auto Path = calculateIncludePath(MainFile, FS.Files[MainFile],
ToHeaderFile(Original),
ToHeaderFile(Preferred), *Cmd, VFS);
if (!Path) {
llvm::consumeError(Path.takeError());
EXPECT_TRUE(ExpectError);
return std::string();
} else {
EXPECT_FALSE(ExpectError);
}
return std::move(*Path);
}
MockFSProvider FS;
MockCompilationDatabase CDB;
std::string MainFile = testPath("main.cpp");
std::string Subdir = testPath("sub");
std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
};
TEST_F(HeadersTest, InsertInclude) {
std::string Path = testPath("sub/bar.h");
FS.Files[Path] = "";
EXPECT_EQ(calculate(Path), "\"bar.h\"");
}
TEST_F(HeadersTest, DontInsertDuplicateSameName) {
FS.Files[MainFile] = R"cpp(
#include "bar.h"
)cpp";
std::string BarHeader = testPath("sub/bar.h");
FS.Files[BarHeader] = "";
EXPECT_EQ(calculate(BarHeader), "");
}
TEST_F(HeadersTest, DontInsertDuplicateDifferentName) {
std::string BarHeader = testPath("sub/bar.h");
FS.Files[BarHeader] = "";
FS.Files[MainFile] = R"cpp(
#include "sub/bar.h" // not shortest
)cpp";
EXPECT_EQ(calculate("\"sub/bar.h\""), ""); // Duplicate rewritten.
EXPECT_EQ(calculate(BarHeader), ""); // Duplicate resolved.
EXPECT_EQ(calculate(BarHeader, "\"BAR.h\""), ""); // Do not insert preferred.
}
TEST_F(HeadersTest, DontInsertDuplicatePreferred) {
std::string BarHeader = testPath("sub/bar.h");
FS.Files[BarHeader] = "";
FS.Files[MainFile] = R"cpp(
#include "sub/bar.h" // not shortest
)cpp";
// Duplicate written.
EXPECT_EQ(calculate("\"original.h\"", "\"sub/bar.h\""), "");
// Duplicate resolved.
EXPECT_EQ(calculate("\"original.h\"", BarHeader), "");
}
TEST_F(HeadersTest, StillInsertIfTrasitivelyIncluded) {
std::string BazHeader = testPath("sub/baz.h");
FS.Files[BazHeader] = "";
std::string BarHeader = testPath("sub/bar.h");
FS.Files[BarHeader] = R"cpp(
#include "baz.h"
)cpp";
FS.Files[MainFile] = R"cpp(
#include "bar.h"
)cpp";
EXPECT_EQ(calculate(BazHeader), "\"baz.h\"");
}
TEST_F(HeadersTest, DoNotInsertIfInSameFile) {
MainFile = testPath("main.h");
FS.Files[MainFile] = "";
EXPECT_EQ(calculate(MainFile), "");
}
TEST_F(HeadersTest, PreferredHeader) {
FS.Files[MainFile] = "";
std::string BarHeader = testPath("sub/bar.h");
FS.Files[BarHeader] = "";
EXPECT_EQ(calculate(BarHeader, "<bar>"), "<bar>");
std::string BazHeader = testPath("sub/baz.h");
FS.Files[BazHeader] = "";
EXPECT_EQ(calculate(BarHeader, BazHeader), "\"baz.h\"");
}
} // namespace
} // namespace clangd
} // namespace clang