1f4a2713aSLionel Sambuc //===- unittest/Tooling/CompilationDatabaseTest.cpp -----------------------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc
10f4a2713aSLionel Sambuc #include "clang/AST/ASTConsumer.h"
11f4a2713aSLionel Sambuc #include "clang/AST/DeclCXX.h"
12f4a2713aSLionel Sambuc #include "clang/AST/DeclGroup.h"
13f4a2713aSLionel Sambuc #include "clang/Frontend/FrontendAction.h"
14f4a2713aSLionel Sambuc #include "clang/Tooling/FileMatchTrie.h"
15f4a2713aSLionel Sambuc #include "clang/Tooling/JSONCompilationDatabase.h"
16f4a2713aSLionel Sambuc #include "clang/Tooling/Tooling.h"
17f4a2713aSLionel Sambuc #include "llvm/Support/Path.h"
18f4a2713aSLionel Sambuc #include "gtest/gtest.h"
19f4a2713aSLionel Sambuc
20f4a2713aSLionel Sambuc namespace clang {
21f4a2713aSLionel Sambuc namespace tooling {
22f4a2713aSLionel Sambuc
expectFailure(StringRef JSONDatabase,StringRef Explanation)23f4a2713aSLionel Sambuc static void expectFailure(StringRef JSONDatabase, StringRef Explanation) {
24f4a2713aSLionel Sambuc std::string ErrorMessage;
25*0a6a1f1dSLionel Sambuc EXPECT_EQ(nullptr, JSONCompilationDatabase::loadFromBuffer(JSONDatabase,
26f4a2713aSLionel Sambuc ErrorMessage))
27*0a6a1f1dSLionel Sambuc << "Expected an error because of: " << Explanation.str();
28f4a2713aSLionel Sambuc }
29f4a2713aSLionel Sambuc
TEST(JSONCompilationDatabase,ErrsOnInvalidFormat)30f4a2713aSLionel Sambuc TEST(JSONCompilationDatabase, ErrsOnInvalidFormat) {
31f4a2713aSLionel Sambuc expectFailure("", "Empty database");
32f4a2713aSLionel Sambuc expectFailure("{", "Invalid JSON");
33f4a2713aSLionel Sambuc expectFailure("[[]]", "Array instead of object");
34f4a2713aSLionel Sambuc expectFailure("[{\"a\":[]}]", "Array instead of value");
35f4a2713aSLionel Sambuc expectFailure("[{\"a\":\"b\"}]", "Unknown key");
36f4a2713aSLionel Sambuc expectFailure("[{[]:\"\"}]", "Incorrectly typed entry");
37f4a2713aSLionel Sambuc expectFailure("[{}]", "Empty entry");
38f4a2713aSLionel Sambuc expectFailure("[{\"directory\":\"\",\"command\":\"\"}]", "Missing file");
39f4a2713aSLionel Sambuc expectFailure("[{\"directory\":\"\",\"file\":\"\"}]", "Missing command");
40f4a2713aSLionel Sambuc expectFailure("[{\"command\":\"\",\"file\":\"\"}]", "Missing directory");
41f4a2713aSLionel Sambuc }
42f4a2713aSLionel Sambuc
getAllFiles(StringRef JSONDatabase,std::string & ErrorMessage)43f4a2713aSLionel Sambuc static std::vector<std::string> getAllFiles(StringRef JSONDatabase,
44f4a2713aSLionel Sambuc std::string &ErrorMessage) {
45*0a6a1f1dSLionel Sambuc std::unique_ptr<CompilationDatabase> Database(
46f4a2713aSLionel Sambuc JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
47f4a2713aSLionel Sambuc if (!Database) {
48f4a2713aSLionel Sambuc ADD_FAILURE() << ErrorMessage;
49f4a2713aSLionel Sambuc return std::vector<std::string>();
50f4a2713aSLionel Sambuc }
51f4a2713aSLionel Sambuc return Database->getAllFiles();
52f4a2713aSLionel Sambuc }
53f4a2713aSLionel Sambuc
getAllCompileCommands(StringRef JSONDatabase,std::string & ErrorMessage)54f4a2713aSLionel Sambuc static std::vector<CompileCommand> getAllCompileCommands(StringRef JSONDatabase,
55f4a2713aSLionel Sambuc std::string &ErrorMessage) {
56*0a6a1f1dSLionel Sambuc std::unique_ptr<CompilationDatabase> Database(
57f4a2713aSLionel Sambuc JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
58f4a2713aSLionel Sambuc if (!Database) {
59f4a2713aSLionel Sambuc ADD_FAILURE() << ErrorMessage;
60f4a2713aSLionel Sambuc return std::vector<CompileCommand>();
61f4a2713aSLionel Sambuc }
62f4a2713aSLionel Sambuc return Database->getAllCompileCommands();
63f4a2713aSLionel Sambuc }
64f4a2713aSLionel Sambuc
TEST(JSONCompilationDatabase,GetAllFiles)65f4a2713aSLionel Sambuc TEST(JSONCompilationDatabase, GetAllFiles) {
66f4a2713aSLionel Sambuc std::string ErrorMessage;
67f4a2713aSLionel Sambuc EXPECT_EQ(std::vector<std::string>(),
68f4a2713aSLionel Sambuc getAllFiles("[]", ErrorMessage)) << ErrorMessage;
69f4a2713aSLionel Sambuc
70f4a2713aSLionel Sambuc std::vector<std::string> expected_files;
71f4a2713aSLionel Sambuc SmallString<16> PathStorage;
72f4a2713aSLionel Sambuc llvm::sys::path::native("//net/dir/file1", PathStorage);
73f4a2713aSLionel Sambuc expected_files.push_back(PathStorage.str());
74f4a2713aSLionel Sambuc llvm::sys::path::native("//net/dir/file2", PathStorage);
75f4a2713aSLionel Sambuc expected_files.push_back(PathStorage.str());
76f4a2713aSLionel Sambuc EXPECT_EQ(expected_files, getAllFiles(
77f4a2713aSLionel Sambuc "[{\"directory\":\"//net/dir\","
78f4a2713aSLionel Sambuc "\"command\":\"command\","
79f4a2713aSLionel Sambuc "\"file\":\"file1\"},"
80f4a2713aSLionel Sambuc " {\"directory\":\"//net/dir\","
81f4a2713aSLionel Sambuc "\"command\":\"command\","
82f4a2713aSLionel Sambuc "\"file\":\"file2\"}]",
83f4a2713aSLionel Sambuc ErrorMessage)) << ErrorMessage;
84f4a2713aSLionel Sambuc }
85f4a2713aSLionel Sambuc
TEST(JSONCompilationDatabase,GetAllCompileCommands)86f4a2713aSLionel Sambuc TEST(JSONCompilationDatabase, GetAllCompileCommands) {
87f4a2713aSLionel Sambuc std::string ErrorMessage;
88f4a2713aSLionel Sambuc EXPECT_EQ(0u,
89f4a2713aSLionel Sambuc getAllCompileCommands("[]", ErrorMessage).size()) << ErrorMessage;
90f4a2713aSLionel Sambuc
91f4a2713aSLionel Sambuc StringRef Directory1("//net/dir1");
92f4a2713aSLionel Sambuc StringRef FileName1("file1");
93f4a2713aSLionel Sambuc StringRef Command1("command1");
94f4a2713aSLionel Sambuc StringRef Directory2("//net/dir2");
95f4a2713aSLionel Sambuc StringRef FileName2("file1");
96f4a2713aSLionel Sambuc StringRef Command2("command1");
97f4a2713aSLionel Sambuc
98f4a2713aSLionel Sambuc std::vector<CompileCommand> Commands = getAllCompileCommands(
99f4a2713aSLionel Sambuc ("[{\"directory\":\"" + Directory1 + "\"," +
100f4a2713aSLionel Sambuc "\"command\":\"" + Command1 + "\","
101f4a2713aSLionel Sambuc "\"file\":\"" + FileName1 + "\"},"
102f4a2713aSLionel Sambuc " {\"directory\":\"" + Directory2 + "\"," +
103f4a2713aSLionel Sambuc "\"command\":\"" + Command2 + "\","
104f4a2713aSLionel Sambuc "\"file\":\"" + FileName2 + "\"}]").str(),
105f4a2713aSLionel Sambuc ErrorMessage);
106f4a2713aSLionel Sambuc EXPECT_EQ(2U, Commands.size()) << ErrorMessage;
107f4a2713aSLionel Sambuc EXPECT_EQ(Directory1, Commands[0].Directory) << ErrorMessage;
108f4a2713aSLionel Sambuc ASSERT_EQ(1u, Commands[0].CommandLine.size());
109f4a2713aSLionel Sambuc EXPECT_EQ(Command1, Commands[0].CommandLine[0]) << ErrorMessage;
110f4a2713aSLionel Sambuc EXPECT_EQ(Directory2, Commands[1].Directory) << ErrorMessage;
111f4a2713aSLionel Sambuc ASSERT_EQ(1u, Commands[1].CommandLine.size());
112f4a2713aSLionel Sambuc EXPECT_EQ(Command2, Commands[1].CommandLine[0]) << ErrorMessage;
113f4a2713aSLionel Sambuc }
114f4a2713aSLionel Sambuc
findCompileArgsInJsonDatabase(StringRef FileName,StringRef JSONDatabase,std::string & ErrorMessage)115f4a2713aSLionel Sambuc static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName,
116f4a2713aSLionel Sambuc StringRef JSONDatabase,
117f4a2713aSLionel Sambuc std::string &ErrorMessage) {
118*0a6a1f1dSLionel Sambuc std::unique_ptr<CompilationDatabase> Database(
119f4a2713aSLionel Sambuc JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
120f4a2713aSLionel Sambuc if (!Database)
121f4a2713aSLionel Sambuc return CompileCommand();
122f4a2713aSLionel Sambuc std::vector<CompileCommand> Commands = Database->getCompileCommands(FileName);
123f4a2713aSLionel Sambuc EXPECT_LE(Commands.size(), 1u);
124f4a2713aSLionel Sambuc if (Commands.empty())
125f4a2713aSLionel Sambuc return CompileCommand();
126f4a2713aSLionel Sambuc return Commands[0];
127f4a2713aSLionel Sambuc }
128f4a2713aSLionel Sambuc
129f4a2713aSLionel Sambuc struct FakeComparator : public PathComparator {
~FakeComparatorclang::tooling::FakeComparator130f4a2713aSLionel Sambuc virtual ~FakeComparator() {}
equivalentclang::tooling::FakeComparator131f4a2713aSLionel Sambuc virtual bool equivalent(StringRef FileA, StringRef FileB) const {
132f4a2713aSLionel Sambuc return FileA.equals_lower(FileB);
133f4a2713aSLionel Sambuc }
134f4a2713aSLionel Sambuc };
135f4a2713aSLionel Sambuc
136f4a2713aSLionel Sambuc class FileMatchTrieTest : public ::testing::Test {
137f4a2713aSLionel Sambuc protected:
FileMatchTrieTest()138f4a2713aSLionel Sambuc FileMatchTrieTest() : Trie(new FakeComparator()) {}
139f4a2713aSLionel Sambuc
find(StringRef Path)140f4a2713aSLionel Sambuc StringRef find(StringRef Path) {
141f4a2713aSLionel Sambuc llvm::raw_string_ostream ES(Error);
142f4a2713aSLionel Sambuc return Trie.findEquivalent(Path, ES);
143f4a2713aSLionel Sambuc }
144f4a2713aSLionel Sambuc
145f4a2713aSLionel Sambuc FileMatchTrie Trie;
146f4a2713aSLionel Sambuc std::string Error;
147f4a2713aSLionel Sambuc };
148f4a2713aSLionel Sambuc
TEST_F(FileMatchTrieTest,InsertingRelativePath)149f4a2713aSLionel Sambuc TEST_F(FileMatchTrieTest, InsertingRelativePath) {
150f4a2713aSLionel Sambuc Trie.insert("//net/path/file.cc");
151f4a2713aSLionel Sambuc Trie.insert("file.cc");
152f4a2713aSLionel Sambuc EXPECT_EQ("//net/path/file.cc", find("//net/path/file.cc"));
153f4a2713aSLionel Sambuc }
154f4a2713aSLionel Sambuc
TEST_F(FileMatchTrieTest,MatchingRelativePath)155f4a2713aSLionel Sambuc TEST_F(FileMatchTrieTest, MatchingRelativePath) {
156f4a2713aSLionel Sambuc EXPECT_EQ("", find("file.cc"));
157f4a2713aSLionel Sambuc }
158f4a2713aSLionel Sambuc
TEST_F(FileMatchTrieTest,ReturnsBestResults)159f4a2713aSLionel Sambuc TEST_F(FileMatchTrieTest, ReturnsBestResults) {
160f4a2713aSLionel Sambuc Trie.insert("//net/d/c/b.cc");
161f4a2713aSLionel Sambuc Trie.insert("//net/d/b/b.cc");
162f4a2713aSLionel Sambuc EXPECT_EQ("//net/d/b/b.cc", find("//net/d/b/b.cc"));
163f4a2713aSLionel Sambuc }
164f4a2713aSLionel Sambuc
TEST_F(FileMatchTrieTest,HandlesSymlinks)165f4a2713aSLionel Sambuc TEST_F(FileMatchTrieTest, HandlesSymlinks) {
166f4a2713aSLionel Sambuc Trie.insert("//net/AA/file.cc");
167f4a2713aSLionel Sambuc EXPECT_EQ("//net/AA/file.cc", find("//net/aa/file.cc"));
168f4a2713aSLionel Sambuc }
169f4a2713aSLionel Sambuc
TEST_F(FileMatchTrieTest,ReportsSymlinkAmbiguity)170f4a2713aSLionel Sambuc TEST_F(FileMatchTrieTest, ReportsSymlinkAmbiguity) {
171f4a2713aSLionel Sambuc Trie.insert("//net/Aa/file.cc");
172f4a2713aSLionel Sambuc Trie.insert("//net/aA/file.cc");
173f4a2713aSLionel Sambuc EXPECT_TRUE(find("//net/aa/file.cc").empty());
174f4a2713aSLionel Sambuc EXPECT_EQ("Path is ambiguous", Error);
175f4a2713aSLionel Sambuc }
176f4a2713aSLionel Sambuc
TEST_F(FileMatchTrieTest,LongerMatchingSuffixPreferred)177f4a2713aSLionel Sambuc TEST_F(FileMatchTrieTest, LongerMatchingSuffixPreferred) {
178f4a2713aSLionel Sambuc Trie.insert("//net/src/Aa/file.cc");
179f4a2713aSLionel Sambuc Trie.insert("//net/src/aA/file.cc");
180f4a2713aSLionel Sambuc Trie.insert("//net/SRC/aa/file.cc");
181f4a2713aSLionel Sambuc EXPECT_EQ("//net/SRC/aa/file.cc", find("//net/src/aa/file.cc"));
182f4a2713aSLionel Sambuc }
183f4a2713aSLionel Sambuc
TEST_F(FileMatchTrieTest,EmptyTrie)184f4a2713aSLionel Sambuc TEST_F(FileMatchTrieTest, EmptyTrie) {
185f4a2713aSLionel Sambuc EXPECT_TRUE(find("//net/some/path").empty());
186f4a2713aSLionel Sambuc }
187f4a2713aSLionel Sambuc
TEST_F(FileMatchTrieTest,NoResult)188f4a2713aSLionel Sambuc TEST_F(FileMatchTrieTest, NoResult) {
189f4a2713aSLionel Sambuc Trie.insert("//net/somepath/otherfile.cc");
190f4a2713aSLionel Sambuc Trie.insert("//net/otherpath/somefile.cc");
191f4a2713aSLionel Sambuc EXPECT_EQ("", find("//net/somepath/somefile.cc"));
192f4a2713aSLionel Sambuc }
193f4a2713aSLionel Sambuc
TEST_F(FileMatchTrieTest,RootElementDifferent)194f4a2713aSLionel Sambuc TEST_F(FileMatchTrieTest, RootElementDifferent) {
195f4a2713aSLionel Sambuc Trie.insert("//net/path/file.cc");
196f4a2713aSLionel Sambuc Trie.insert("//net/otherpath/file.cc");
197f4a2713aSLionel Sambuc EXPECT_EQ("//net/path/file.cc", find("//net/path/file.cc"));
198f4a2713aSLionel Sambuc }
199f4a2713aSLionel Sambuc
TEST_F(FileMatchTrieTest,CannotResolveRelativePath)200f4a2713aSLionel Sambuc TEST_F(FileMatchTrieTest, CannotResolveRelativePath) {
201f4a2713aSLionel Sambuc EXPECT_EQ("", find("relative-path.cc"));
202f4a2713aSLionel Sambuc EXPECT_EQ("Cannot resolve relative paths", Error);
203f4a2713aSLionel Sambuc }
204f4a2713aSLionel Sambuc
TEST(findCompileArgsInJsonDatabase,FindsNothingIfEmpty)205f4a2713aSLionel Sambuc TEST(findCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
206f4a2713aSLionel Sambuc std::string ErrorMessage;
207f4a2713aSLionel Sambuc CompileCommand NotFound = findCompileArgsInJsonDatabase(
208f4a2713aSLionel Sambuc "a-file.cpp", "", ErrorMessage);
209f4a2713aSLionel Sambuc EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
210f4a2713aSLionel Sambuc EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
211f4a2713aSLionel Sambuc }
212f4a2713aSLionel Sambuc
TEST(findCompileArgsInJsonDatabase,ReadsSingleEntry)213f4a2713aSLionel Sambuc TEST(findCompileArgsInJsonDatabase, ReadsSingleEntry) {
214f4a2713aSLionel Sambuc StringRef Directory("//net/some/directory");
215f4a2713aSLionel Sambuc StringRef FileName("//net/path/to/a-file.cpp");
216f4a2713aSLionel Sambuc StringRef Command("//net/path/to/compiler and some arguments");
217f4a2713aSLionel Sambuc std::string ErrorMessage;
218f4a2713aSLionel Sambuc CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
219f4a2713aSLionel Sambuc FileName,
220f4a2713aSLionel Sambuc ("[{\"directory\":\"" + Directory + "\"," +
221f4a2713aSLionel Sambuc "\"command\":\"" + Command + "\","
222f4a2713aSLionel Sambuc "\"file\":\"" + FileName + "\"}]").str(),
223f4a2713aSLionel Sambuc ErrorMessage);
224f4a2713aSLionel Sambuc EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
225f4a2713aSLionel Sambuc ASSERT_EQ(4u, FoundCommand.CommandLine.size()) << ErrorMessage;
226f4a2713aSLionel Sambuc EXPECT_EQ("//net/path/to/compiler",
227f4a2713aSLionel Sambuc FoundCommand.CommandLine[0]) << ErrorMessage;
228f4a2713aSLionel Sambuc EXPECT_EQ("and", FoundCommand.CommandLine[1]) << ErrorMessage;
229f4a2713aSLionel Sambuc EXPECT_EQ("some", FoundCommand.CommandLine[2]) << ErrorMessage;
230f4a2713aSLionel Sambuc EXPECT_EQ("arguments", FoundCommand.CommandLine[3]) << ErrorMessage;
231f4a2713aSLionel Sambuc
232f4a2713aSLionel Sambuc CompileCommand NotFound = findCompileArgsInJsonDatabase(
233f4a2713aSLionel Sambuc "a-file.cpp",
234f4a2713aSLionel Sambuc ("[{\"directory\":\"" + Directory + "\"," +
235f4a2713aSLionel Sambuc "\"command\":\"" + Command + "\","
236f4a2713aSLionel Sambuc "\"file\":\"" + FileName + "\"}]").str(),
237f4a2713aSLionel Sambuc ErrorMessage);
238f4a2713aSLionel Sambuc EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
239f4a2713aSLionel Sambuc EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
240f4a2713aSLionel Sambuc }
241f4a2713aSLionel Sambuc
TEST(findCompileArgsInJsonDatabase,ReadsCompileCommandLinesWithSpaces)242f4a2713aSLionel Sambuc TEST(findCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) {
243f4a2713aSLionel Sambuc StringRef Directory("//net/some/directory");
244f4a2713aSLionel Sambuc StringRef FileName("//net/path/to/a-file.cpp");
245f4a2713aSLionel Sambuc StringRef Command("\\\"//net/path to compiler\\\" \\\"and an argument\\\"");
246f4a2713aSLionel Sambuc std::string ErrorMessage;
247f4a2713aSLionel Sambuc CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
248f4a2713aSLionel Sambuc FileName,
249f4a2713aSLionel Sambuc ("[{\"directory\":\"" + Directory + "\"," +
250f4a2713aSLionel Sambuc "\"command\":\"" + Command + "\","
251f4a2713aSLionel Sambuc "\"file\":\"" + FileName + "\"}]").str(),
252f4a2713aSLionel Sambuc ErrorMessage);
253f4a2713aSLionel Sambuc ASSERT_EQ(2u, FoundCommand.CommandLine.size());
254f4a2713aSLionel Sambuc EXPECT_EQ("//net/path to compiler",
255f4a2713aSLionel Sambuc FoundCommand.CommandLine[0]) << ErrorMessage;
256f4a2713aSLionel Sambuc EXPECT_EQ("and an argument", FoundCommand.CommandLine[1]) << ErrorMessage;
257f4a2713aSLionel Sambuc }
258f4a2713aSLionel Sambuc
TEST(findCompileArgsInJsonDatabase,ReadsDirectoryWithSpaces)259f4a2713aSLionel Sambuc TEST(findCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
260f4a2713aSLionel Sambuc StringRef Directory("//net/some directory / with spaces");
261f4a2713aSLionel Sambuc StringRef FileName("//net/path/to/a-file.cpp");
262f4a2713aSLionel Sambuc StringRef Command("a command");
263f4a2713aSLionel Sambuc std::string ErrorMessage;
264f4a2713aSLionel Sambuc CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
265f4a2713aSLionel Sambuc FileName,
266f4a2713aSLionel Sambuc ("[{\"directory\":\"" + Directory + "\"," +
267f4a2713aSLionel Sambuc "\"command\":\"" + Command + "\","
268f4a2713aSLionel Sambuc "\"file\":\"" + FileName + "\"}]").str(),
269f4a2713aSLionel Sambuc ErrorMessage);
270f4a2713aSLionel Sambuc EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
271f4a2713aSLionel Sambuc }
272f4a2713aSLionel Sambuc
TEST(findCompileArgsInJsonDatabase,FindsEntry)273f4a2713aSLionel Sambuc TEST(findCompileArgsInJsonDatabase, FindsEntry) {
274f4a2713aSLionel Sambuc StringRef Directory("//net/directory");
275f4a2713aSLionel Sambuc StringRef FileName("file");
276f4a2713aSLionel Sambuc StringRef Command("command");
277f4a2713aSLionel Sambuc std::string JsonDatabase = "[";
278f4a2713aSLionel Sambuc for (int I = 0; I < 10; ++I) {
279f4a2713aSLionel Sambuc if (I > 0) JsonDatabase += ",";
280f4a2713aSLionel Sambuc JsonDatabase +=
281f4a2713aSLionel Sambuc ("{\"directory\":\"" + Directory + Twine(I) + "\"," +
282f4a2713aSLionel Sambuc "\"command\":\"" + Command + Twine(I) + "\","
283f4a2713aSLionel Sambuc "\"file\":\"" + FileName + Twine(I) + "\"}").str();
284f4a2713aSLionel Sambuc }
285f4a2713aSLionel Sambuc JsonDatabase += "]";
286f4a2713aSLionel Sambuc std::string ErrorMessage;
287f4a2713aSLionel Sambuc CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
288f4a2713aSLionel Sambuc "//net/directory4/file4", JsonDatabase, ErrorMessage);
289f4a2713aSLionel Sambuc EXPECT_EQ("//net/directory4", FoundCommand.Directory) << ErrorMessage;
290f4a2713aSLionel Sambuc ASSERT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage;
291f4a2713aSLionel Sambuc EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
292f4a2713aSLionel Sambuc }
293f4a2713aSLionel Sambuc
unescapeJsonCommandLine(StringRef Command)294f4a2713aSLionel Sambuc static std::vector<std::string> unescapeJsonCommandLine(StringRef Command) {
295f4a2713aSLionel Sambuc std::string JsonDatabase =
296f4a2713aSLionel Sambuc ("[{\"directory\":\"//net/root\", \"file\":\"test\", \"command\": \"" +
297f4a2713aSLionel Sambuc Command + "\"}]").str();
298f4a2713aSLionel Sambuc std::string ErrorMessage;
299f4a2713aSLionel Sambuc CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
300f4a2713aSLionel Sambuc "//net/root/test", JsonDatabase, ErrorMessage);
301f4a2713aSLionel Sambuc EXPECT_TRUE(ErrorMessage.empty()) << ErrorMessage;
302f4a2713aSLionel Sambuc return FoundCommand.CommandLine;
303f4a2713aSLionel Sambuc }
304f4a2713aSLionel Sambuc
TEST(unescapeJsonCommandLine,ReturnsEmptyArrayOnEmptyString)305f4a2713aSLionel Sambuc TEST(unescapeJsonCommandLine, ReturnsEmptyArrayOnEmptyString) {
306f4a2713aSLionel Sambuc std::vector<std::string> Result = unescapeJsonCommandLine("");
307f4a2713aSLionel Sambuc EXPECT_TRUE(Result.empty());
308f4a2713aSLionel Sambuc }
309f4a2713aSLionel Sambuc
TEST(unescapeJsonCommandLine,SplitsOnSpaces)310f4a2713aSLionel Sambuc TEST(unescapeJsonCommandLine, SplitsOnSpaces) {
311f4a2713aSLionel Sambuc std::vector<std::string> Result = unescapeJsonCommandLine("a b c");
312f4a2713aSLionel Sambuc ASSERT_EQ(3ul, Result.size());
313f4a2713aSLionel Sambuc EXPECT_EQ("a", Result[0]);
314f4a2713aSLionel Sambuc EXPECT_EQ("b", Result[1]);
315f4a2713aSLionel Sambuc EXPECT_EQ("c", Result[2]);
316f4a2713aSLionel Sambuc }
317f4a2713aSLionel Sambuc
TEST(unescapeJsonCommandLine,MungesMultipleSpaces)318f4a2713aSLionel Sambuc TEST(unescapeJsonCommandLine, MungesMultipleSpaces) {
319f4a2713aSLionel Sambuc std::vector<std::string> Result = unescapeJsonCommandLine(" a b ");
320f4a2713aSLionel Sambuc ASSERT_EQ(2ul, Result.size());
321f4a2713aSLionel Sambuc EXPECT_EQ("a", Result[0]);
322f4a2713aSLionel Sambuc EXPECT_EQ("b", Result[1]);
323f4a2713aSLionel Sambuc }
324f4a2713aSLionel Sambuc
TEST(unescapeJsonCommandLine,UnescapesBackslashCharacters)325f4a2713aSLionel Sambuc TEST(unescapeJsonCommandLine, UnescapesBackslashCharacters) {
326f4a2713aSLionel Sambuc std::vector<std::string> Backslash = unescapeJsonCommandLine("a\\\\\\\\");
327f4a2713aSLionel Sambuc ASSERT_EQ(1ul, Backslash.size());
328f4a2713aSLionel Sambuc EXPECT_EQ("a\\", Backslash[0]);
329f4a2713aSLionel Sambuc std::vector<std::string> Quote = unescapeJsonCommandLine("a\\\\\\\"");
330f4a2713aSLionel Sambuc ASSERT_EQ(1ul, Quote.size());
331f4a2713aSLionel Sambuc EXPECT_EQ("a\"", Quote[0]);
332f4a2713aSLionel Sambuc }
333f4a2713aSLionel Sambuc
TEST(unescapeJsonCommandLine,DoesNotMungeSpacesBetweenQuotes)334f4a2713aSLionel Sambuc TEST(unescapeJsonCommandLine, DoesNotMungeSpacesBetweenQuotes) {
335f4a2713aSLionel Sambuc std::vector<std::string> Result = unescapeJsonCommandLine("\\\" a b \\\"");
336f4a2713aSLionel Sambuc ASSERT_EQ(1ul, Result.size());
337f4a2713aSLionel Sambuc EXPECT_EQ(" a b ", Result[0]);
338f4a2713aSLionel Sambuc }
339f4a2713aSLionel Sambuc
TEST(unescapeJsonCommandLine,AllowsMultipleQuotedArguments)340f4a2713aSLionel Sambuc TEST(unescapeJsonCommandLine, AllowsMultipleQuotedArguments) {
341f4a2713aSLionel Sambuc std::vector<std::string> Result = unescapeJsonCommandLine(
342f4a2713aSLionel Sambuc " \\\" a \\\" \\\" b \\\" ");
343f4a2713aSLionel Sambuc ASSERT_EQ(2ul, Result.size());
344f4a2713aSLionel Sambuc EXPECT_EQ(" a ", Result[0]);
345f4a2713aSLionel Sambuc EXPECT_EQ(" b ", Result[1]);
346f4a2713aSLionel Sambuc }
347f4a2713aSLionel Sambuc
TEST(unescapeJsonCommandLine,AllowsEmptyArgumentsInQuotes)348f4a2713aSLionel Sambuc TEST(unescapeJsonCommandLine, AllowsEmptyArgumentsInQuotes) {
349f4a2713aSLionel Sambuc std::vector<std::string> Result = unescapeJsonCommandLine(
350f4a2713aSLionel Sambuc "\\\"\\\"\\\"\\\"");
351f4a2713aSLionel Sambuc ASSERT_EQ(1ul, Result.size());
352f4a2713aSLionel Sambuc EXPECT_TRUE(Result[0].empty()) << Result[0];
353f4a2713aSLionel Sambuc }
354f4a2713aSLionel Sambuc
TEST(unescapeJsonCommandLine,ParsesEscapedQuotesInQuotedStrings)355f4a2713aSLionel Sambuc TEST(unescapeJsonCommandLine, ParsesEscapedQuotesInQuotedStrings) {
356f4a2713aSLionel Sambuc std::vector<std::string> Result = unescapeJsonCommandLine(
357f4a2713aSLionel Sambuc "\\\"\\\\\\\"\\\"");
358f4a2713aSLionel Sambuc ASSERT_EQ(1ul, Result.size());
359f4a2713aSLionel Sambuc EXPECT_EQ("\"", Result[0]);
360f4a2713aSLionel Sambuc }
361f4a2713aSLionel Sambuc
TEST(unescapeJsonCommandLine,ParsesMultipleArgumentsWithEscapedCharacters)362f4a2713aSLionel Sambuc TEST(unescapeJsonCommandLine, ParsesMultipleArgumentsWithEscapedCharacters) {
363f4a2713aSLionel Sambuc std::vector<std::string> Result = unescapeJsonCommandLine(
364f4a2713aSLionel Sambuc " \\\\\\\" \\\"a \\\\\\\" b \\\" \\\"and\\\\\\\\c\\\" \\\\\\\"");
365f4a2713aSLionel Sambuc ASSERT_EQ(4ul, Result.size());
366f4a2713aSLionel Sambuc EXPECT_EQ("\"", Result[0]);
367f4a2713aSLionel Sambuc EXPECT_EQ("a \" b ", Result[1]);
368f4a2713aSLionel Sambuc EXPECT_EQ("and\\c", Result[2]);
369f4a2713aSLionel Sambuc EXPECT_EQ("\"", Result[3]);
370f4a2713aSLionel Sambuc }
371f4a2713aSLionel Sambuc
TEST(unescapeJsonCommandLine,ParsesStringsWithoutSpacesIntoSingleArgument)372f4a2713aSLionel Sambuc TEST(unescapeJsonCommandLine, ParsesStringsWithoutSpacesIntoSingleArgument) {
373f4a2713aSLionel Sambuc std::vector<std::string> QuotedNoSpaces = unescapeJsonCommandLine(
374f4a2713aSLionel Sambuc "\\\"a\\\"\\\"b\\\"");
375f4a2713aSLionel Sambuc ASSERT_EQ(1ul, QuotedNoSpaces.size());
376f4a2713aSLionel Sambuc EXPECT_EQ("ab", QuotedNoSpaces[0]);
377f4a2713aSLionel Sambuc
378f4a2713aSLionel Sambuc std::vector<std::string> MixedNoSpaces = unescapeJsonCommandLine(
379f4a2713aSLionel Sambuc "\\\"a\\\"bcd\\\"ef\\\"\\\"\\\"\\\"g\\\"");
380f4a2713aSLionel Sambuc ASSERT_EQ(1ul, MixedNoSpaces.size());
381f4a2713aSLionel Sambuc EXPECT_EQ("abcdefg", MixedNoSpaces[0]);
382f4a2713aSLionel Sambuc }
383f4a2713aSLionel Sambuc
TEST(unescapeJsonCommandLine,ParsesQuotedStringWithoutClosingQuote)384f4a2713aSLionel Sambuc TEST(unescapeJsonCommandLine, ParsesQuotedStringWithoutClosingQuote) {
385f4a2713aSLionel Sambuc std::vector<std::string> Unclosed = unescapeJsonCommandLine("\\\"abc");
386f4a2713aSLionel Sambuc ASSERT_EQ(1ul, Unclosed.size());
387f4a2713aSLionel Sambuc EXPECT_EQ("abc", Unclosed[0]);
388f4a2713aSLionel Sambuc
389f4a2713aSLionel Sambuc std::vector<std::string> Empty = unescapeJsonCommandLine("\\\"");
390f4a2713aSLionel Sambuc ASSERT_EQ(1ul, Empty.size());
391f4a2713aSLionel Sambuc EXPECT_EQ("", Empty[0]);
392f4a2713aSLionel Sambuc }
393f4a2713aSLionel Sambuc
TEST(unescapeJsonCommandLine,ParsesSingleQuotedString)394f4a2713aSLionel Sambuc TEST(unescapeJsonCommandLine, ParsesSingleQuotedString) {
395f4a2713aSLionel Sambuc std::vector<std::string> Args = unescapeJsonCommandLine("a'\\\\b \\\"c\\\"'");
396f4a2713aSLionel Sambuc ASSERT_EQ(1ul, Args.size());
397f4a2713aSLionel Sambuc EXPECT_EQ("a\\b \"c\"", Args[0]);
398f4a2713aSLionel Sambuc }
399f4a2713aSLionel Sambuc
TEST(FixedCompilationDatabase,ReturnsFixedCommandLine)400f4a2713aSLionel Sambuc TEST(FixedCompilationDatabase, ReturnsFixedCommandLine) {
401f4a2713aSLionel Sambuc std::vector<std::string> CommandLine;
402f4a2713aSLionel Sambuc CommandLine.push_back("one");
403f4a2713aSLionel Sambuc CommandLine.push_back("two");
404f4a2713aSLionel Sambuc FixedCompilationDatabase Database(".", CommandLine);
405f4a2713aSLionel Sambuc std::vector<CompileCommand> Result =
406f4a2713aSLionel Sambuc Database.getCompileCommands("source");
407f4a2713aSLionel Sambuc ASSERT_EQ(1ul, Result.size());
408f4a2713aSLionel Sambuc std::vector<std::string> ExpectedCommandLine(1, "clang-tool");
409f4a2713aSLionel Sambuc ExpectedCommandLine.insert(ExpectedCommandLine.end(),
410f4a2713aSLionel Sambuc CommandLine.begin(), CommandLine.end());
411f4a2713aSLionel Sambuc ExpectedCommandLine.push_back("source");
412f4a2713aSLionel Sambuc EXPECT_EQ(".", Result[0].Directory);
413f4a2713aSLionel Sambuc EXPECT_EQ(ExpectedCommandLine, Result[0].CommandLine);
414f4a2713aSLionel Sambuc }
415f4a2713aSLionel Sambuc
TEST(FixedCompilationDatabase,GetAllFiles)416f4a2713aSLionel Sambuc TEST(FixedCompilationDatabase, GetAllFiles) {
417f4a2713aSLionel Sambuc std::vector<std::string> CommandLine;
418f4a2713aSLionel Sambuc CommandLine.push_back("one");
419f4a2713aSLionel Sambuc CommandLine.push_back("two");
420f4a2713aSLionel Sambuc FixedCompilationDatabase Database(".", CommandLine);
421f4a2713aSLionel Sambuc
422f4a2713aSLionel Sambuc EXPECT_EQ(0ul, Database.getAllFiles().size());
423f4a2713aSLionel Sambuc }
424f4a2713aSLionel Sambuc
TEST(FixedCompilationDatabase,GetAllCompileCommands)425f4a2713aSLionel Sambuc TEST(FixedCompilationDatabase, GetAllCompileCommands) {
426f4a2713aSLionel Sambuc std::vector<std::string> CommandLine;
427f4a2713aSLionel Sambuc CommandLine.push_back("one");
428f4a2713aSLionel Sambuc CommandLine.push_back("two");
429f4a2713aSLionel Sambuc FixedCompilationDatabase Database(".", CommandLine);
430f4a2713aSLionel Sambuc
431f4a2713aSLionel Sambuc EXPECT_EQ(0ul, Database.getAllCompileCommands().size());
432f4a2713aSLionel Sambuc }
433f4a2713aSLionel Sambuc
TEST(ParseFixedCompilationDatabase,ReturnsNullOnEmptyArgumentList)434f4a2713aSLionel Sambuc TEST(ParseFixedCompilationDatabase, ReturnsNullOnEmptyArgumentList) {
435f4a2713aSLionel Sambuc int Argc = 0;
436*0a6a1f1dSLionel Sambuc std::unique_ptr<FixedCompilationDatabase> Database(
437*0a6a1f1dSLionel Sambuc FixedCompilationDatabase::loadFromCommandLine(Argc, nullptr));
438f4a2713aSLionel Sambuc EXPECT_FALSE(Database);
439f4a2713aSLionel Sambuc EXPECT_EQ(0, Argc);
440f4a2713aSLionel Sambuc }
441f4a2713aSLionel Sambuc
TEST(ParseFixedCompilationDatabase,ReturnsNullWithoutDoubleDash)442f4a2713aSLionel Sambuc TEST(ParseFixedCompilationDatabase, ReturnsNullWithoutDoubleDash) {
443f4a2713aSLionel Sambuc int Argc = 2;
444f4a2713aSLionel Sambuc const char *Argv[] = { "1", "2" };
445*0a6a1f1dSLionel Sambuc std::unique_ptr<FixedCompilationDatabase> Database(
446f4a2713aSLionel Sambuc FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
447f4a2713aSLionel Sambuc EXPECT_FALSE(Database);
448f4a2713aSLionel Sambuc EXPECT_EQ(2, Argc);
449f4a2713aSLionel Sambuc }
450f4a2713aSLionel Sambuc
TEST(ParseFixedCompilationDatabase,ReturnsArgumentsAfterDoubleDash)451f4a2713aSLionel Sambuc TEST(ParseFixedCompilationDatabase, ReturnsArgumentsAfterDoubleDash) {
452f4a2713aSLionel Sambuc int Argc = 5;
453f4a2713aSLionel Sambuc const char *Argv[] = {
454f4a2713aSLionel Sambuc "1", "2", "--\0no-constant-folding", "-DDEF3", "-DDEF4"
455f4a2713aSLionel Sambuc };
456*0a6a1f1dSLionel Sambuc std::unique_ptr<FixedCompilationDatabase> Database(
457f4a2713aSLionel Sambuc FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
458*0a6a1f1dSLionel Sambuc ASSERT_TRUE((bool)Database);
459f4a2713aSLionel Sambuc std::vector<CompileCommand> Result =
460f4a2713aSLionel Sambuc Database->getCompileCommands("source");
461f4a2713aSLionel Sambuc ASSERT_EQ(1ul, Result.size());
462f4a2713aSLionel Sambuc ASSERT_EQ(".", Result[0].Directory);
463f4a2713aSLionel Sambuc std::vector<std::string> CommandLine;
464f4a2713aSLionel Sambuc CommandLine.push_back("clang-tool");
465f4a2713aSLionel Sambuc CommandLine.push_back("-DDEF3");
466f4a2713aSLionel Sambuc CommandLine.push_back("-DDEF4");
467f4a2713aSLionel Sambuc CommandLine.push_back("source");
468f4a2713aSLionel Sambuc ASSERT_EQ(CommandLine, Result[0].CommandLine);
469f4a2713aSLionel Sambuc EXPECT_EQ(2, Argc);
470f4a2713aSLionel Sambuc }
471f4a2713aSLionel Sambuc
TEST(ParseFixedCompilationDatabase,ReturnsEmptyCommandLine)472f4a2713aSLionel Sambuc TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) {
473f4a2713aSLionel Sambuc int Argc = 3;
474f4a2713aSLionel Sambuc const char *Argv[] = { "1", "2", "--\0no-constant-folding" };
475*0a6a1f1dSLionel Sambuc std::unique_ptr<FixedCompilationDatabase> Database(
476f4a2713aSLionel Sambuc FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
477*0a6a1f1dSLionel Sambuc ASSERT_TRUE((bool)Database);
478f4a2713aSLionel Sambuc std::vector<CompileCommand> Result =
479f4a2713aSLionel Sambuc Database->getCompileCommands("source");
480f4a2713aSLionel Sambuc ASSERT_EQ(1ul, Result.size());
481f4a2713aSLionel Sambuc ASSERT_EQ(".", Result[0].Directory);
482f4a2713aSLionel Sambuc std::vector<std::string> CommandLine;
483f4a2713aSLionel Sambuc CommandLine.push_back("clang-tool");
484f4a2713aSLionel Sambuc CommandLine.push_back("source");
485f4a2713aSLionel Sambuc ASSERT_EQ(CommandLine, Result[0].CommandLine);
486f4a2713aSLionel Sambuc EXPECT_EQ(2, Argc);
487f4a2713aSLionel Sambuc }
488f4a2713aSLionel Sambuc
TEST(ParseFixedCompilationDatabase,HandlesPositionalArgs)489f4a2713aSLionel Sambuc TEST(ParseFixedCompilationDatabase, HandlesPositionalArgs) {
490f4a2713aSLionel Sambuc const char *Argv[] = {"1", "2", "--", "-c", "somefile.cpp", "-DDEF3"};
491f4a2713aSLionel Sambuc int Argc = sizeof(Argv) / sizeof(char*);
492*0a6a1f1dSLionel Sambuc std::unique_ptr<FixedCompilationDatabase> Database(
493f4a2713aSLionel Sambuc FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
494*0a6a1f1dSLionel Sambuc ASSERT_TRUE((bool)Database);
495f4a2713aSLionel Sambuc std::vector<CompileCommand> Result =
496f4a2713aSLionel Sambuc Database->getCompileCommands("source");
497f4a2713aSLionel Sambuc ASSERT_EQ(1ul, Result.size());
498f4a2713aSLionel Sambuc ASSERT_EQ(".", Result[0].Directory);
499f4a2713aSLionel Sambuc std::vector<std::string> Expected;
500f4a2713aSLionel Sambuc Expected.push_back("clang-tool");
501f4a2713aSLionel Sambuc Expected.push_back("-c");
502f4a2713aSLionel Sambuc Expected.push_back("-DDEF3");
503f4a2713aSLionel Sambuc Expected.push_back("source");
504f4a2713aSLionel Sambuc ASSERT_EQ(Expected, Result[0].CommandLine);
505f4a2713aSLionel Sambuc EXPECT_EQ(2, Argc);
506f4a2713aSLionel Sambuc }
507f4a2713aSLionel Sambuc
TEST(ParseFixedCompilationDatabase,HandlesArgv0)508f4a2713aSLionel Sambuc TEST(ParseFixedCompilationDatabase, HandlesArgv0) {
509f4a2713aSLionel Sambuc const char *Argv[] = {"1", "2", "--", "mytool", "somefile.cpp"};
510f4a2713aSLionel Sambuc int Argc = sizeof(Argv) / sizeof(char*);
511*0a6a1f1dSLionel Sambuc std::unique_ptr<FixedCompilationDatabase> Database(
512f4a2713aSLionel Sambuc FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
513*0a6a1f1dSLionel Sambuc ASSERT_TRUE((bool)Database);
514f4a2713aSLionel Sambuc std::vector<CompileCommand> Result =
515f4a2713aSLionel Sambuc Database->getCompileCommands("source");
516f4a2713aSLionel Sambuc ASSERT_EQ(1ul, Result.size());
517f4a2713aSLionel Sambuc ASSERT_EQ(".", Result[0].Directory);
518f4a2713aSLionel Sambuc std::vector<std::string> Expected;
519f4a2713aSLionel Sambuc Expected.push_back("clang-tool");
520f4a2713aSLionel Sambuc Expected.push_back("source");
521f4a2713aSLionel Sambuc ASSERT_EQ(Expected, Result[0].CommandLine);
522f4a2713aSLionel Sambuc EXPECT_EQ(2, Argc);
523f4a2713aSLionel Sambuc }
524f4a2713aSLionel Sambuc
525f4a2713aSLionel Sambuc } // end namespace tooling
526f4a2713aSLionel Sambuc } // end namespace clang
527