]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - unittests/Tooling/CompilationDatabaseTest.cpp
Vendor import of clang trunk r154661:
[FreeBSD/FreeBSD.git] / unittests / Tooling / CompilationDatabaseTest.cpp
1 //===- unittest/Tooling/CompilationDatabaseTest.cpp -----------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "clang/AST/ASTConsumer.h"
11 #include "clang/AST/DeclCXX.h"
12 #include "clang/AST/DeclGroup.h"
13 #include "clang/Frontend/FrontendAction.h"
14 #include "clang/Tooling/CompilationDatabase.h"
15 #include "clang/Tooling/Tooling.h"
16 #include "gtest/gtest.h"
17
18 namespace clang {
19 namespace tooling {
20
21 static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName,
22                                                     StringRef JSONDatabase,
23                                                     std::string &ErrorMessage) {
24   llvm::OwningPtr<CompilationDatabase> Database(
25       JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
26   if (!Database)
27     return CompileCommand();
28   std::vector<CompileCommand> Commands = Database->getCompileCommands(FileName);
29   EXPECT_LE(Commands.size(), 1u);
30   if (Commands.empty())
31     return CompileCommand();
32   return Commands[0];
33 }
34
35 TEST(findCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
36   std::string ErrorMessage;
37   CompileCommand NotFound = findCompileArgsInJsonDatabase(
38     "a-file.cpp", "", ErrorMessage);
39   EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
40   EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
41 }
42
43 TEST(findCompileArgsInJsonDatabase, ReadsSingleEntry) {
44   StringRef Directory("/some/directory");
45   StringRef FileName("/path/to/a-file.cpp");
46   StringRef Command("/path/to/compiler and some arguments");
47   std::string ErrorMessage;
48   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
49     FileName,
50     ("[{\"directory\":\"" + Directory + "\"," +
51        "\"command\":\"" + Command + "\","
52        "\"file\":\"" + FileName + "\"}]").str(),
53     ErrorMessage);
54   EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
55   ASSERT_EQ(4u, FoundCommand.CommandLine.size()) << ErrorMessage;
56   EXPECT_EQ("/path/to/compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
57   EXPECT_EQ("and", FoundCommand.CommandLine[1]) << ErrorMessage;
58   EXPECT_EQ("some", FoundCommand.CommandLine[2]) << ErrorMessage;
59   EXPECT_EQ("arguments", FoundCommand.CommandLine[3]) << ErrorMessage;
60
61   CompileCommand NotFound = findCompileArgsInJsonDatabase(
62     "a-file.cpp",
63     ("[{\"directory\":\"" + Directory + "\"," +
64        "\"command\":\"" + Command + "\","
65        "\"file\":\"" + FileName + "\"}]").str(),
66     ErrorMessage);
67   EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
68   EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
69 }
70
71 TEST(findCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) {
72   StringRef Directory("/some/directory");
73   StringRef FileName("/path/to/a-file.cpp");
74   StringRef Command("\\\"/path to compiler\\\" \\\"and an argument\\\"");
75   std::string ErrorMessage;
76   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
77     FileName,
78     ("[{\"directory\":\"" + Directory + "\"," +
79        "\"command\":\"" + Command + "\","
80        "\"file\":\"" + FileName + "\"}]").str(),
81     ErrorMessage);
82   ASSERT_EQ(2u, FoundCommand.CommandLine.size());
83   EXPECT_EQ("/path to compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
84   EXPECT_EQ("and an argument", FoundCommand.CommandLine[1]) << ErrorMessage;
85 }
86
87 TEST(findCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
88   StringRef Directory("/some directory / with spaces");
89   StringRef FileName("/path/to/a-file.cpp");
90   StringRef Command("a command");
91   std::string ErrorMessage;
92   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
93     FileName,
94     ("[{\"directory\":\"" + Directory + "\"," +
95        "\"command\":\"" + Command + "\","
96        "\"file\":\"" + FileName + "\"}]").str(),
97     ErrorMessage);
98   EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
99 }
100
101 TEST(findCompileArgsInJsonDatabase, FindsEntry) {
102   StringRef Directory("directory");
103   StringRef FileName("file");
104   StringRef Command("command");
105   std::string JsonDatabase = "[";
106   for (int I = 0; I < 10; ++I) {
107     if (I > 0) JsonDatabase += ",";
108     JsonDatabase +=
109       ("{\"directory\":\"" + Directory + Twine(I) + "\"," +
110         "\"command\":\"" + Command + Twine(I) + "\","
111         "\"file\":\"" + FileName + Twine(I) + "\"}").str();
112   }
113   JsonDatabase += "]";
114   std::string ErrorMessage;
115   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
116     "file4", JsonDatabase, ErrorMessage);
117   EXPECT_EQ("directory4", FoundCommand.Directory) << ErrorMessage;
118   ASSERT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage;
119   EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
120 }
121
122 static std::vector<std::string> unescapeJsonCommandLine(StringRef Command) {
123   std::string JsonDatabase =
124     ("[{\"directory\":\"\", \"file\":\"test\", \"command\": \"" +
125      Command + "\"}]").str();
126   std::string ErrorMessage;
127   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
128     "test", JsonDatabase, ErrorMessage);
129   EXPECT_TRUE(ErrorMessage.empty()) << ErrorMessage;
130   return FoundCommand.CommandLine;
131 }
132
133 TEST(unescapeJsonCommandLine, ReturnsEmptyArrayOnEmptyString) {
134   std::vector<std::string> Result = unescapeJsonCommandLine("");
135   EXPECT_TRUE(Result.empty());
136 }
137
138 TEST(unescapeJsonCommandLine, SplitsOnSpaces) {
139   std::vector<std::string> Result = unescapeJsonCommandLine("a b c");
140   ASSERT_EQ(3ul, Result.size());
141   EXPECT_EQ("a", Result[0]);
142   EXPECT_EQ("b", Result[1]);
143   EXPECT_EQ("c", Result[2]);
144 }
145
146 TEST(unescapeJsonCommandLine, MungesMultipleSpaces) {
147   std::vector<std::string> Result = unescapeJsonCommandLine("   a   b   ");
148   ASSERT_EQ(2ul, Result.size());
149   EXPECT_EQ("a", Result[0]);
150   EXPECT_EQ("b", Result[1]);
151 }
152
153 TEST(unescapeJsonCommandLine, UnescapesBackslashCharacters) {
154   std::vector<std::string> Backslash = unescapeJsonCommandLine("a\\\\\\\\");
155   ASSERT_EQ(1ul, Backslash.size());
156   EXPECT_EQ("a\\", Backslash[0]);
157   std::vector<std::string> Quote = unescapeJsonCommandLine("a\\\\\\\"");
158   ASSERT_EQ(1ul, Quote.size());
159   EXPECT_EQ("a\"", Quote[0]);
160 }
161
162 TEST(unescapeJsonCommandLine, DoesNotMungeSpacesBetweenQuotes) {
163   std::vector<std::string> Result = unescapeJsonCommandLine("\\\"  a  b  \\\"");
164   ASSERT_EQ(1ul, Result.size());
165   EXPECT_EQ("  a  b  ", Result[0]);
166 }
167
168 TEST(unescapeJsonCommandLine, AllowsMultipleQuotedArguments) {
169   std::vector<std::string> Result = unescapeJsonCommandLine(
170       "  \\\" a \\\"  \\\" b \\\"  ");
171   ASSERT_EQ(2ul, Result.size());
172   EXPECT_EQ(" a ", Result[0]);
173   EXPECT_EQ(" b ", Result[1]);
174 }
175
176 TEST(unescapeJsonCommandLine, AllowsEmptyArgumentsInQuotes) {
177   std::vector<std::string> Result = unescapeJsonCommandLine(
178       "\\\"\\\"\\\"\\\"");
179   ASSERT_EQ(1ul, Result.size());
180   EXPECT_TRUE(Result[0].empty()) << Result[0];
181 }
182
183 TEST(unescapeJsonCommandLine, ParsesEscapedQuotesInQuotedStrings) {
184   std::vector<std::string> Result = unescapeJsonCommandLine(
185       "\\\"\\\\\\\"\\\"");
186   ASSERT_EQ(1ul, Result.size());
187   EXPECT_EQ("\"", Result[0]);
188 }
189
190 TEST(unescapeJsonCommandLine, ParsesMultipleArgumentsWithEscapedCharacters) {
191   std::vector<std::string> Result = unescapeJsonCommandLine(
192       "  \\\\\\\"  \\\"a \\\\\\\" b \\\"     \\\"and\\\\\\\\c\\\"   \\\\\\\"");
193   ASSERT_EQ(4ul, Result.size());
194   EXPECT_EQ("\"", Result[0]);
195   EXPECT_EQ("a \" b ", Result[1]);
196   EXPECT_EQ("and\\c", Result[2]);
197   EXPECT_EQ("\"", Result[3]);
198 }
199
200 TEST(unescapeJsonCommandLine, ParsesStringsWithoutSpacesIntoSingleArgument) {
201   std::vector<std::string> QuotedNoSpaces = unescapeJsonCommandLine(
202       "\\\"a\\\"\\\"b\\\"");
203   ASSERT_EQ(1ul, QuotedNoSpaces.size());
204   EXPECT_EQ("ab", QuotedNoSpaces[0]);
205
206   std::vector<std::string> MixedNoSpaces = unescapeJsonCommandLine(
207       "\\\"a\\\"bcd\\\"ef\\\"\\\"\\\"\\\"g\\\"");
208   ASSERT_EQ(1ul, MixedNoSpaces.size());
209   EXPECT_EQ("abcdefg", MixedNoSpaces[0]);
210 }
211
212 TEST(unescapeJsonCommandLine, ParsesQuotedStringWithoutClosingQuote) {
213   std::vector<std::string> Unclosed = unescapeJsonCommandLine("\\\"abc");
214   ASSERT_EQ(1ul, Unclosed.size());
215   EXPECT_EQ("abc", Unclosed[0]);
216
217   std::vector<std::string> Empty = unescapeJsonCommandLine("\\\"");
218   ASSERT_EQ(1ul, Empty.size());
219   EXPECT_EQ("", Empty[0]);
220 }
221
222 } // end namespace tooling
223 } // end namespace clang