• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "gn/compile_commands_writer.h"
6 
7 #include <memory>
8 #include <sstream>
9 #include <utility>
10 
11 #include "gn/config.h"
12 #include "gn/ninja_target_command_util.h"
13 #include "gn/scheduler.h"
14 #include "gn/target.h"
15 #include "gn/test_with_scheduler.h"
16 #include "gn/test_with_scope.h"
17 #include "util/build_config.h"
18 #include "util/test/test.h"
19 
20 namespace {
21 
22 // InputConversion needs a global scheduler object.
23 class CompileCommandsTest : public TestWithScheduler {
24  public:
25   CompileCommandsTest() = default;
26 
build_settings()27   const BuildSettings* build_settings() { return setup_.build_settings(); }
settings()28   const Settings* settings() { return setup_.settings(); }
setup()29   const TestWithScope& setup() { return setup_; }
toolchain()30   const Toolchain* toolchain() { return setup_.toolchain(); }
31 
32  private:
33   TestWithScope setup_;
34 };
35 
36 }  // namespace
37 
TEST_F(CompileCommandsTest,SourceSet)38 TEST_F(CompileCommandsTest, SourceSet) {
39   Err err;
40 
41   std::vector<const Target*> targets;
42   Target target(settings(), Label(SourceDir("//foo/"), "bar"));
43   target.set_output_type(Target::SOURCE_SET);
44   target.visibility().SetPublic();
45   target.sources().push_back(SourceFile("//foo/input1.cc"));
46   target.sources().push_back(SourceFile("//foo/input2.cc"));
47   // Also test object files, which should be just passed through to the
48   // dependents to link.
49   target.sources().push_back(SourceFile("//foo/input3.o"));
50   target.sources().push_back(SourceFile("//foo/input4.obj"));
51   target.SetToolchain(toolchain());
52   ASSERT_TRUE(target.OnResolved(&err));
53   targets.push_back(&target);
54 
55   // Source set itself.
56   {
57     std::string out;
58     CompileCommandsWriter writer;
59     writer.RenderJSON(build_settings(), targets, &out);
60 
61 #if defined(OS_WIN)
62     const char expected[] =
63         "[\r\n"
64         "  {\r\n"
65         "    \"file\": \"../../foo/input1.cc\",\r\n"
66         "    \"directory\": \"out/Debug\",\r\n"
67         "    \"command\": \"c++ ../../foo/input1.cc     -o  "
68         "obj/foo/bar.input1.o\"\r\n"
69         "  },\r\n"
70         "  {\r\n"
71         "    \"file\": \"../../foo/input2.cc\",\r\n"
72         "    \"directory\": \"out/Debug\",\r\n"
73         "    \"command\": \"c++ ../../foo/input2.cc     -o  "
74         "obj/foo/bar.input2.o\"\r\n"
75         "  }\r\n"
76         "]\r\n";
77 #else
78     const char expected[] =
79         "[\n"
80         "  {\n"
81         "    \"file\": \"../../foo/input1.cc\",\n"
82         "    \"directory\": \"out/Debug\",\n"
83         "    \"command\": \"c++ ../../foo/input1.cc     -o  "
84         "obj/foo/bar.input1.o\"\n"
85         "  },\n"
86         "  {\n"
87         "    \"file\": \"../../foo/input2.cc\",\n"
88         "    \"directory\": \"out/Debug\",\n"
89         "    \"command\": \"c++ ../../foo/input2.cc     -o  "
90         "obj/foo/bar.input2.o\"\n"
91         "  }\n"
92         "]\n";
93 #endif
94     EXPECT_EQ(expected, out);
95   }
96 
97   // A shared library that depends on the source set.
98   Target shlib_target(settings(), Label(SourceDir("//foo/"), "shlib"));
99   shlib_target.sources().push_back(SourceFile("//foo/input3.cc"));
100   shlib_target.set_output_type(Target::SHARED_LIBRARY);
101   shlib_target.public_deps().push_back(LabelTargetPair(&target));
102   shlib_target.SetToolchain(toolchain());
103   ASSERT_TRUE(shlib_target.OnResolved(&err));
104   targets.push_back(&shlib_target);
105 
106   {
107     std::string out;
108     CompileCommandsWriter writer;
109     writer.RenderJSON(build_settings(), targets, &out);
110 
111 #if defined(OS_WIN)
112     const char expected[] =
113         "[\r\n"
114         "  {\r\n"
115         "    \"file\": \"../../foo/input1.cc\",\r\n"
116         "    \"directory\": \"out/Debug\",\r\n"
117         "    \"command\": \"c++ ../../foo/input1.cc     -o  "
118         "obj/foo/bar.input1.o\"\r\n"
119         "  },\r\n"
120         "  {\r\n"
121         "    \"file\": \"../../foo/input2.cc\",\r\n"
122         "    \"directory\": \"out/Debug\",\r\n"
123         "    \"command\": \"c++ ../../foo/input2.cc     -o  "
124         "obj/foo/bar.input2.o\"\r\n"
125         "  },\r\n"
126         "  {\r\n"
127         "    \"file\": \"../../foo/input3.cc\",\r\n"
128         "    \"directory\": \"out/Debug\",\r\n"
129         "    \"command\": \"c++ ../../foo/input3.cc     -o  "
130         "obj/foo/libshlib.input3.o\"\r\n"
131         "  }\r\n"
132         "]\r\n";
133 #else
134     const char expected[] =
135         "[\n"
136         "  {\n"
137         "    \"file\": \"../../foo/input1.cc\",\n"
138         "    \"directory\": \"out/Debug\",\n"
139         "    \"command\": \"c++ ../../foo/input1.cc     -o  "
140         "obj/foo/bar.input1.o\"\n"
141         "  },\n"
142         "  {\n"
143         "    \"file\": \"../../foo/input2.cc\",\n"
144         "    \"directory\": \"out/Debug\",\n"
145         "    \"command\": \"c++ ../../foo/input2.cc     -o  "
146         "obj/foo/bar.input2.o\"\n"
147         "  },\n"
148         "  {\n"
149         "    \"file\": \"../../foo/input3.cc\",\n"
150         "    \"directory\": \"out/Debug\",\n"
151         "    \"command\": \"c++ ../../foo/input3.cc     -o  "
152         "obj/foo/libshlib.input3.o\"\n"
153         "  }\n"
154         "]\n";
155 #endif
156     EXPECT_EQ(expected, out);
157   }
158 
159   // A static library that depends on the source set (should not link it).
160   Target stlib_target(settings(), Label(SourceDir("//foo/"), "stlib"));
161   stlib_target.sources().push_back(SourceFile("//foo/input4.cc"));
162   stlib_target.set_output_type(Target::STATIC_LIBRARY);
163   stlib_target.public_deps().push_back(LabelTargetPair(&target));
164   stlib_target.SetToolchain(toolchain());
165   ASSERT_TRUE(stlib_target.OnResolved(&err));
166   targets.push_back(&stlib_target);
167 
168   {
169     std::string out;
170     CompileCommandsWriter writer;
171     writer.RenderJSON(build_settings(), targets, &out);
172 
173 #if defined(OS_WIN)
174     const char expected[] =
175         "[\r\n"
176         "  {\r\n"
177         "    \"file\": \"../../foo/input1.cc\",\r\n"
178         "    \"directory\": \"out/Debug\",\r\n"
179         "    \"command\": \"c++ ../../foo/input1.cc     -o  "
180         "obj/foo/bar.input1.o\"\r\n"
181         "  },\r\n"
182         "  {\r\n"
183         "    \"file\": \"../../foo/input2.cc\",\r\n"
184         "    \"directory\": \"out/Debug\",\r\n"
185         "    \"command\": \"c++ ../../foo/input2.cc     -o  "
186         "obj/foo/bar.input2.o\"\r\n"
187         "  },\r\n"
188         "  {\r\n"
189         "    \"file\": \"../../foo/input3.cc\",\r\n"
190         "    \"directory\": \"out/Debug\",\r\n"
191         "    \"command\": \"c++ ../../foo/input3.cc     -o  "
192         "obj/foo/libshlib.input3.o\"\r\n"
193         "  },\r\n"
194         "  {\r\n"
195         "    \"file\": \"../../foo/input4.cc\",\r\n"
196         "    \"directory\": \"out/Debug\",\r\n"
197         "    \"command\": \"c++ ../../foo/input4.cc     -o  "
198         "obj/foo/libstlib.input4.o\"\r\n"
199         "  }\r\n"
200         "]\r\n";
201 #else
202     const char expected[] =
203         "[\n"
204         "  {\n"
205         "    \"file\": \"../../foo/input1.cc\",\n"
206         "    \"directory\": \"out/Debug\",\n"
207         "    \"command\": \"c++ ../../foo/input1.cc     -o  "
208         "obj/foo/bar.input1.o\"\n"
209         "  },\n"
210         "  {\n"
211         "    \"file\": \"../../foo/input2.cc\",\n"
212         "    \"directory\": \"out/Debug\",\n"
213         "    \"command\": \"c++ ../../foo/input2.cc     -o  "
214         "obj/foo/bar.input2.o\"\n"
215         "  },\n"
216         "  {\n"
217         "    \"file\": \"../../foo/input3.cc\",\n"
218         "    \"directory\": \"out/Debug\",\n"
219         "    \"command\": \"c++ ../../foo/input3.cc     -o  "
220         "obj/foo/libshlib.input3.o\"\n"
221         "  },\n"
222         "  {\n"
223         "    \"file\": \"../../foo/input4.cc\",\n"
224         "    \"directory\": \"out/Debug\",\n"
225         "    \"command\": \"c++ ../../foo/input4.cc     -o  "
226         "obj/foo/libstlib.input4.o\"\n"
227         "  }\n"
228         "]\n";
229 #endif
230     EXPECT_EQ(expected, out);
231   }
232 }
233 
TEST_F(CompileCommandsTest,EscapeDefines)234 TEST_F(CompileCommandsTest, EscapeDefines) {
235   Err err;
236 
237   std::vector<const Target*> targets;
238   TestTarget target(setup(), "//foo:bar", Target::STATIC_LIBRARY);
239   target.sources().push_back(SourceFile("//foo/input.cc"));
240   target.config_values().defines().push_back("BOOL_DEF");
241   target.config_values().defines().push_back("INT_DEF=123");
242   target.config_values().defines().push_back("STR_DEF=\"ABCD 1\"");
243   ASSERT_TRUE(target.OnResolved(&err));
244   targets.push_back(&target);
245 
246   std::string out;
247   CompileCommandsWriter writer;
248   writer.RenderJSON(build_settings(), targets, &out);
249 
250   const char expected[] =
251       "-DBOOL_DEF -DINT_DEF=123 -DSTR_DEF=\\\\\\\"ABCD\\\\ 1\\\\\\\"";
252   EXPECT_TRUE(out.find(expected) != std::string::npos);
253 }
254 
TEST_F(CompileCommandsTest,WinPrecompiledHeaders)255 TEST_F(CompileCommandsTest, WinPrecompiledHeaders) {
256   Err err;
257 
258   // This setup's toolchain does not have precompiled headers defined.
259   // A precompiled header toolchain.
260   Settings pch_settings(build_settings(), "withpch/");
261   Toolchain pch_toolchain(&pch_settings,
262                           Label(SourceDir("//toolchain/"), "withpch"));
263   pch_settings.set_toolchain_label(pch_toolchain.label());
264   pch_settings.set_default_toolchain_label(toolchain()->label());
265 
266   // Declare a C++ compiler that supports PCH.
267   std::unique_ptr<Tool> cxx = Tool::CreateTool(CTool::kCToolCxx);
268   CTool* cxx_tool = cxx->AsC();
269   TestWithScope::SetCommandForTool(
270       "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} "
271       "-o {{output}}",
272       cxx_tool);
273   cxx_tool->set_outputs(SubstitutionList::MakeForTest(
274       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
275   cxx_tool->set_precompiled_header_type(CTool::PCH_MSVC);
276   pch_toolchain.SetTool(std::move(cxx));
277 
278   // Add a C compiler as well.
279   std::unique_ptr<Tool> cc = Tool::CreateTool(CTool::kCToolCc);
280   CTool* cc_tool = cc->AsC();
281   TestWithScope::SetCommandForTool(
282       "cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} "
283       "-o {{output}}",
284       cc_tool);
285   cc_tool->set_outputs(SubstitutionList::MakeForTest(
286       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
287   cc_tool->set_precompiled_header_type(CTool::PCH_MSVC);
288   pch_toolchain.SetTool(std::move(cc));
289   pch_toolchain.ToolchainSetupComplete();
290 
291   // This target doesn't specify precompiled headers.
292   {
293     std::vector<const Target*> targets;
294     Target no_pch_target(&pch_settings,
295                          Label(SourceDir("//foo/"), "no_pch_target"));
296     no_pch_target.set_output_type(Target::SOURCE_SET);
297     no_pch_target.visibility().SetPublic();
298     no_pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
299     no_pch_target.sources().push_back(SourceFile("//foo/input2.c"));
300     no_pch_target.config_values().cflags_c().push_back("-std=c99");
301     no_pch_target.SetToolchain(&pch_toolchain);
302     ASSERT_TRUE(no_pch_target.OnResolved(&err));
303     targets.push_back(&no_pch_target);
304 
305     std::string out;
306     CompileCommandsWriter writer;
307     writer.RenderJSON(build_settings(), targets, &out);
308 
309 #if defined(OS_WIN)
310     const char no_pch_expected[] =
311         "[\r\n"
312         "  {\r\n"
313         "    \"file\": \"../../foo/input1.cc\",\r\n"
314         "    \"directory\": \"out/Debug\",\r\n"
315         "    \"command\": \"c++ ../../foo/input1.cc     -o  "
316         "withpch/obj/foo/no_pch_target.input1.o\"\r\n"
317         "  },\r\n"
318         "  {\r\n"
319         "    \"file\": \"../../foo/input2.c\",\r\n"
320         "    \"directory\": \"out/Debug\",\r\n"
321         "    \"command\": \"cc ../../foo/input2.c   -std=c99   -o  "
322         "withpch/obj/foo/no_pch_target.input2.o\"\r\n"
323         "  }\r\n"
324         "]\r\n";
325 #else
326     const char no_pch_expected[] =
327         "[\n"
328         "  {\n"
329         "    \"file\": \"../../foo/input1.cc\",\n"
330         "    \"directory\": \"out/Debug\",\n"
331         "    \"command\": \"c++ ../../foo/input1.cc     -o  "
332         "withpch/obj/foo/no_pch_target.input1.o\"\n"
333         "  },\n"
334         "  {\n"
335         "    \"file\": \"../../foo/input2.c\",\n"
336         "    \"directory\": \"out/Debug\",\n"
337         "    \"command\": \"cc ../../foo/input2.c   -std=c99   -o  "
338         "withpch/obj/foo/no_pch_target.input2.o\"\n"
339         "  }\n"
340         "]\n";
341 #endif
342     EXPECT_EQ(no_pch_expected, out);
343   }
344 
345   // This target specifies PCH.
346   {
347     std::vector<const Target*> targets;
348     Target pch_target(&pch_settings, Label(SourceDir("//foo/"), "pch_target"));
349     pch_target.config_values().set_precompiled_header("build/precompile.h");
350     pch_target.config_values().set_precompiled_source(
351         SourceFile("//build/precompile.cc"));
352     pch_target.set_output_type(Target::SOURCE_SET);
353     pch_target.visibility().SetPublic();
354     pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
355     pch_target.sources().push_back(SourceFile("//foo/input2.c"));
356     pch_target.SetToolchain(&pch_toolchain);
357     ASSERT_TRUE(pch_target.OnResolved(&err));
358     targets.push_back(&pch_target);
359 
360     std::string out;
361     CompileCommandsWriter writer;
362     writer.RenderJSON(build_settings(), targets, &out);
363 
364 #if defined(OS_WIN)
365     const char pch_win_expected[] =
366         "[\r\n"
367         "  {\r\n"
368         "    \"file\": \"../../foo/input1.cc\",\r\n"
369         "    \"directory\": \"out/Debug\",\r\n"
370         "    \"command\": \"c++ ../../foo/input1.cc   "
371         "/Fpwithpch/obj/foo/pch_target_cc.pch /Yubuild/precompile.h   -o  "
372         "withpch/obj/foo/pch_target.input1.o\"\r\n"
373         "  },\r\n"
374         "  {\r\n"
375         "    \"file\": \"../../foo/input2.c\",\r\n"
376         "    \"directory\": \"out/Debug\",\r\n"
377         "    \"command\": \"cc ../../foo/input2.c   "
378         "/Fpwithpch/obj/foo/pch_target_c.pch /Yubuild/precompile.h   -o  "
379         "withpch/obj/foo/pch_target.input2.o\"\r\n"
380         "  }\r\n"
381         "]\r\n";
382 #else
383     const char pch_win_expected[] =
384         "[\n"
385         "  {\n"
386         "    \"file\": \"../../foo/input1.cc\",\n"
387         "    \"directory\": \"out/Debug\",\n"
388         "    \"command\": \"c++ ../../foo/input1.cc   "
389         "/Fpwithpch/obj/foo/pch_target_cc.pch /Yubuild/precompile.h   -o  "
390         "withpch/obj/foo/pch_target.input1.o\"\n"
391         "  },\n"
392         "  {\n"
393         "    \"file\": \"../../foo/input2.c\",\n"
394         "    \"directory\": \"out/Debug\",\n"
395         "    \"command\": \"cc ../../foo/input2.c   "
396         "/Fpwithpch/obj/foo/pch_target_c.pch /Yubuild/precompile.h   -o  "
397         "withpch/obj/foo/pch_target.input2.o\"\n"
398         "  }\n"
399         "]\n";
400 #endif
401     EXPECT_EQ(pch_win_expected, out);
402   }
403 }
404 
TEST_F(CompileCommandsTest,GCCPrecompiledHeaders)405 TEST_F(CompileCommandsTest, GCCPrecompiledHeaders) {
406   Err err;
407 
408   // This setup's toolchain does not have precompiled headers defined.
409   // A precompiled header toolchain.
410   Settings pch_settings(build_settings(), "withpch/");
411   Toolchain pch_toolchain(&pch_settings,
412                           Label(SourceDir("//toolchain/"), "withpch"));
413   pch_settings.set_toolchain_label(pch_toolchain.label());
414   pch_settings.set_default_toolchain_label(toolchain()->label());
415 
416   // Declare a C++ compiler that supports PCH.
417   std::unique_ptr<Tool> cxx = Tool::CreateTool(CTool::kCToolCxx);
418   CTool* cxx_tool = cxx->AsC();
419   TestWithScope::SetCommandForTool(
420       "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} "
421       "-o {{output}}",
422       cxx_tool);
423   cxx_tool->set_outputs(SubstitutionList::MakeForTest(
424       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
425   cxx_tool->set_precompiled_header_type(CTool::PCH_GCC);
426   pch_toolchain.SetTool(std::move(cxx));
427   pch_toolchain.ToolchainSetupComplete();
428 
429   // Add a C compiler as well.
430   std::unique_ptr<Tool> cc = Tool::CreateTool(CTool::kCToolCc);
431   CTool* cc_tool = cc->AsC();
432   TestWithScope::SetCommandForTool(
433       "cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} "
434       "-o {{output}}",
435       cc_tool);
436   cc_tool->set_outputs(SubstitutionList::MakeForTest(
437       "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
438   cc_tool->set_precompiled_header_type(CTool::PCH_GCC);
439   pch_toolchain.SetTool(std::move(cc));
440   pch_toolchain.ToolchainSetupComplete();
441 
442   // This target doesn't specify precompiled headers.
443   {
444     std::vector<const Target*> targets;
445     Target no_pch_target(&pch_settings,
446                          Label(SourceDir("//foo/"), "no_pch_target"));
447     no_pch_target.set_output_type(Target::SOURCE_SET);
448     no_pch_target.visibility().SetPublic();
449     no_pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
450     no_pch_target.sources().push_back(SourceFile("//foo/input2.c"));
451     no_pch_target.config_values().cflags_c().push_back("-std=c99");
452     no_pch_target.SetToolchain(&pch_toolchain);
453     ASSERT_TRUE(no_pch_target.OnResolved(&err));
454     targets.push_back(&no_pch_target);
455 
456     std::string out;
457     CompileCommandsWriter writer;
458     writer.RenderJSON(build_settings(), targets, &out);
459 
460 #if defined(OS_WIN)
461     const char no_pch_expected[] =
462         "[\r\n"
463         "  {\r\n"
464         "    \"file\": \"../../foo/input1.cc\",\r\n"
465         "    \"directory\": \"out/Debug\",\r\n"
466         "    \"command\": \"c++ ../../foo/input1.cc     -o  "
467         "withpch/obj/foo/no_pch_target.input1.o\"\r\n"
468         "  },\r\n"
469         "  {\r\n"
470         "    \"file\": \"../../foo/input2.c\",\r\n"
471         "    \"directory\": \"out/Debug\",\r\n"
472         "    \"command\": \"cc ../../foo/input2.c   -std=c99   -o  "
473         "withpch/obj/foo/no_pch_target.input2.o\"\r\n"
474         "  }\r\n"
475         "]\r\n";
476 #else
477     const char no_pch_expected[] =
478         "[\n"
479         "  {\n"
480         "    \"file\": \"../../foo/input1.cc\",\n"
481         "    \"directory\": \"out/Debug\",\n"
482         "    \"command\": \"c++ ../../foo/input1.cc     -o  "
483         "withpch/obj/foo/no_pch_target.input1.o\"\n"
484         "  },\n"
485         "  {\n"
486         "    \"file\": \"../../foo/input2.c\",\n"
487         "    \"directory\": \"out/Debug\",\n"
488         "    \"command\": \"cc ../../foo/input2.c   -std=c99   -o  "
489         "withpch/obj/foo/no_pch_target.input2.o\"\n"
490         "  }\n"
491         "]\n";
492 #endif
493     EXPECT_EQ(no_pch_expected, out);
494   }
495 
496   // This target specifies PCH.
497   {
498     std::vector<const Target*> targets;
499     Target pch_target(&pch_settings, Label(SourceDir("//foo/"), "pch_target"));
500     pch_target.config_values().set_precompiled_source(
501         SourceFile("//build/precompile.h"));
502     pch_target.config_values().cflags_c().push_back("-std=c99");
503     pch_target.set_output_type(Target::SOURCE_SET);
504     pch_target.visibility().SetPublic();
505     pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
506     pch_target.sources().push_back(SourceFile("//foo/input2.c"));
507     pch_target.SetToolchain(&pch_toolchain);
508     ASSERT_TRUE(pch_target.OnResolved(&err));
509     targets.push_back(&pch_target);
510 
511     std::string out;
512     CompileCommandsWriter writer;
513     writer.RenderJSON(build_settings(), targets, &out);
514 
515 #if defined(OS_WIN)
516     const char pch_gcc_expected[] =
517         "[\r\n"
518         "  {\r\n"
519         "    \"file\": \"../../foo/input1.cc\",\r\n"
520         "    \"directory\": \"out/Debug\",\r\n"
521         "    \"command\": \"c++ ../../foo/input1.cc   -include "
522         "withpch/obj/build/pch_target.precompile.h-cc   -o  "
523         "withpch/obj/foo/pch_target.input1.o\"\r\n"
524         "  },\r\n"
525         "  {\r\n"
526         "    \"file\": \"../../foo/input2.c\",\r\n"
527         "    \"directory\": \"out/Debug\",\r\n"
528         "    \"command\": \"cc ../../foo/input2.c   -std=c99 -include "
529         "withpch/obj/build/pch_target.precompile.h-c   -o  "
530         "withpch/obj/foo/pch_target.input2.o\"\r\n"
531         "  }\r\n"
532         "]\r\n";
533 #else
534     const char pch_gcc_expected[] =
535         "[\n"
536         "  {\n"
537         "    \"file\": \"../../foo/input1.cc\",\n"
538         "    \"directory\": \"out/Debug\",\n"
539         "    \"command\": \"c++ ../../foo/input1.cc   -include "
540         "withpch/obj/build/pch_target.precompile.h-cc   -o  "
541         "withpch/obj/foo/pch_target.input1.o\"\n"
542         "  },\n"
543         "  {\n"
544         "    \"file\": \"../../foo/input2.c\",\n"
545         "    \"directory\": \"out/Debug\",\n"
546         "    \"command\": \"cc ../../foo/input2.c   -std=c99 -include "
547         "withpch/obj/build/pch_target.precompile.h-c   -o  "
548         "withpch/obj/foo/pch_target.input2.o\"\n"
549         "  }\n"
550         "]\n";
551 #endif
552     EXPECT_EQ(pch_gcc_expected, out);
553   }
554 }
555 
TEST_F(CompileCommandsTest,EscapedFlags)556 TEST_F(CompileCommandsTest, EscapedFlags) {
557   Err err;
558 
559   std::vector<const Target*> targets;
560   Target target(settings(), Label(SourceDir("//foo/"), "bar"));
561   target.set_output_type(Target::SOURCE_SET);
562   target.sources().push_back(SourceFile("//foo/input1.c"));
563   target.config_values().cflags_c().push_back("-DCONFIG=\"/config\"");
564   target.SetToolchain(toolchain());
565   ASSERT_TRUE(target.OnResolved(&err));
566   targets.push_back(&target);
567 
568   std::string out;
569   CompileCommandsWriter writer;
570   writer.RenderJSON(build_settings(), targets, &out);
571 
572 #if defined(OS_WIN)
573   const char expected[] =
574       "[\r\n"
575       "  {\r\n"
576       "    \"file\": \"../../foo/input1.c\",\r\n"
577       "    \"directory\": \"out/Debug\",\r\n"
578       "    \"command\": \"cc ../../foo/input1.c   -DCONFIG=\\\"/config\\\"   "
579       "-o  obj/foo/bar.input1.o\"\r\n"
580       "  }\r\n"
581       "]\r\n";
582 #else
583   const char expected[] =
584       "[\n"
585       "  {\n"
586       "    \"file\": \"../../foo/input1.c\",\n"
587       "    \"directory\": \"out/Debug\",\n"
588       "    \"command\": \"cc ../../foo/input1.c   -DCONFIG=\\\"/config\\\"   "
589       "-o  obj/foo/bar.input1.o\"\n"
590       "  }\n"
591       "]\n";
592 #endif
593   EXPECT_EQ(expected, out);
594 }
595 
TEST_F(CompileCommandsTest,CompDBFilter)596 TEST_F(CompileCommandsTest, CompDBFilter) {
597   Err err;
598 
599   std::vector<const Target*> targets;
600   Target target1(settings(), Label(SourceDir("//foo/"), "bar1"));
601   target1.set_output_type(Target::SOURCE_SET);
602   target1.sources().push_back(SourceFile("//foo/input1.c"));
603   target1.config_values().cflags_c().push_back("-DCONFIG=\"/config\"");
604   target1.SetToolchain(toolchain());
605   ASSERT_TRUE(target1.OnResolved(&err));
606   targets.push_back(&target1);
607 
608   Target target2(settings(), Label(SourceDir("//foo/"), "bar2"));
609   target2.set_output_type(Target::SOURCE_SET);
610   target2.sources().push_back(SourceFile("//foo/input2.c"));
611   target2.config_values().cflags_c().push_back("-DCONFIG=\"/config\"");
612   target2.SetToolchain(toolchain());
613   ASSERT_TRUE(target2.OnResolved(&err));
614   targets.push_back(&target2);
615 
616   Target target3(settings(), Label(SourceDir("//foo/"), "bar3"));
617   target3.set_output_type(Target::SOURCE_SET);
618   target3.sources().push_back(SourceFile("//foo/input3.c"));
619   target3.config_values().cflags_c().push_back("-DCONFIG=\"/config\"");
620   target3.SetToolchain(toolchain());
621   ASSERT_TRUE(target3.OnResolved(&err));
622   targets.push_back(&target3);
623 
624   target1.private_deps().push_back(LabelTargetPair(&target2));
625   target1.private_deps().push_back(LabelTargetPair(&target3));
626 
627   CompileCommandsWriter writer;
628 
629   std::set<std::string> filter1;
630   std::vector<const Target*> test_results1 =
631       writer.FilterTargets(targets, filter1);
632   ASSERT_TRUE(test_results1.empty());
633 
634   std::set<std::string> filter2;
635   filter2.insert(target1.label().name());
636   std::vector<const Target*> test_results2 =
637       writer.FilterTargets(targets, filter2);
638   ASSERT_EQ(test_results2, targets);
639 
640   std::set<std::string> filter3;
641   filter3.insert(target2.label().name());
642   std::vector<const Target*> test_result3 =
643       writer.FilterTargets(targets, filter3);
644   std::vector<const Target*> expected_results3;
645   expected_results3.push_back(&target2);
646   ASSERT_EQ(test_result3, expected_results3);
647 }
648