16d528ed9Sopenharmony_ci// Copyright 2018 The Chromium Authors. All rights reserved.
26d528ed9Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
36d528ed9Sopenharmony_ci// found in the LICENSE file.
46d528ed9Sopenharmony_ci
56d528ed9Sopenharmony_ci#include "gn/compile_commands_writer.h"
66d528ed9Sopenharmony_ci
76d528ed9Sopenharmony_ci#include <memory>
86d528ed9Sopenharmony_ci#include <sstream>
96d528ed9Sopenharmony_ci#include <utility>
106d528ed9Sopenharmony_ci
116d528ed9Sopenharmony_ci#include "gn/config.h"
126d528ed9Sopenharmony_ci#include "gn/ninja_target_command_util.h"
136d528ed9Sopenharmony_ci#include "gn/scheduler.h"
146d528ed9Sopenharmony_ci#include "gn/target.h"
156d528ed9Sopenharmony_ci#include "gn/test_with_scheduler.h"
166d528ed9Sopenharmony_ci#include "gn/test_with_scope.h"
176d528ed9Sopenharmony_ci#include "util/build_config.h"
186d528ed9Sopenharmony_ci#include "util/test/test.h"
196d528ed9Sopenharmony_ci
206d528ed9Sopenharmony_cinamespace {
216d528ed9Sopenharmony_ci
226d528ed9Sopenharmony_cibool CompareLabel(const Target* a, const Target* b) {
236d528ed9Sopenharmony_ci  return a->label() < b->label();
246d528ed9Sopenharmony_ci}
256d528ed9Sopenharmony_ci
266d528ed9Sopenharmony_ci// InputConversion needs a global scheduler object.
276d528ed9Sopenharmony_ciclass CompileCommandsTest : public TestWithScheduler {
286d528ed9Sopenharmony_ci public:
296d528ed9Sopenharmony_ci  CompileCommandsTest() = default;
306d528ed9Sopenharmony_ci
316d528ed9Sopenharmony_ci  const BuildSettings* build_settings() { return setup_.build_settings(); }
326d528ed9Sopenharmony_ci  const Settings* settings() { return setup_.settings(); }
336d528ed9Sopenharmony_ci  const TestWithScope& setup() { return setup_; }
346d528ed9Sopenharmony_ci  const Toolchain* toolchain() { return setup_.toolchain(); }
356d528ed9Sopenharmony_ci
366d528ed9Sopenharmony_ci  // Returns true if the two target vectors contain the same targets, order
376d528ed9Sopenharmony_ci  // independent.
386d528ed9Sopenharmony_ci  bool VectorsEqual(std::vector<const Target*> a,
396d528ed9Sopenharmony_ci                    std::vector<const Target*> b) const {
406d528ed9Sopenharmony_ci    std::sort(a.begin(), a.end(), &CompareLabel);
416d528ed9Sopenharmony_ci    std::sort(b.begin(), b.end(), &CompareLabel);
426d528ed9Sopenharmony_ci    return a == b;
436d528ed9Sopenharmony_ci  }
446d528ed9Sopenharmony_ci
456d528ed9Sopenharmony_ci private:
466d528ed9Sopenharmony_ci  TestWithScope setup_;
476d528ed9Sopenharmony_ci};
486d528ed9Sopenharmony_ci
496d528ed9Sopenharmony_ci}  // namespace
506d528ed9Sopenharmony_ci
516d528ed9Sopenharmony_ciTEST_F(CompileCommandsTest, SourceSet) {
526d528ed9Sopenharmony_ci  Err err;
536d528ed9Sopenharmony_ci
546d528ed9Sopenharmony_ci  std::vector<const Target*> targets;
556d528ed9Sopenharmony_ci  Target target(settings(), Label(SourceDir("//foo/"), "bar"));
566d528ed9Sopenharmony_ci  target.set_output_type(Target::SOURCE_SET);
576d528ed9Sopenharmony_ci  target.visibility().SetPublic();
586d528ed9Sopenharmony_ci  target.sources().push_back(SourceFile("//foo/input1.cc"));
596d528ed9Sopenharmony_ci  target.sources().push_back(SourceFile("//foo/input2.cc"));
606d528ed9Sopenharmony_ci  // Also test object files, which should be just passed through to the
616d528ed9Sopenharmony_ci  // dependents to link.
626d528ed9Sopenharmony_ci  target.sources().push_back(SourceFile("//foo/input3.o"));
636d528ed9Sopenharmony_ci  target.sources().push_back(SourceFile("//foo/input4.obj"));
646d528ed9Sopenharmony_ci  target.SetToolchain(toolchain());
656d528ed9Sopenharmony_ci  ASSERT_TRUE(target.OnResolved(&err));
666d528ed9Sopenharmony_ci  targets.push_back(&target);
676d528ed9Sopenharmony_ci
686d528ed9Sopenharmony_ci  // Source set itself.
696d528ed9Sopenharmony_ci  {
706d528ed9Sopenharmony_ci    CompileCommandsWriter writer;
716d528ed9Sopenharmony_ci    std::string out = writer.RenderJSON(build_settings(), targets);
726d528ed9Sopenharmony_ci
736d528ed9Sopenharmony_ci#if defined(OS_WIN)
746d528ed9Sopenharmony_ci    const char expected[] =
756d528ed9Sopenharmony_ci        "[\r\n"
766d528ed9Sopenharmony_ci        "  {\r\n"
776d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\r\n"
786d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
796d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc     -o  "
806d528ed9Sopenharmony_ci        "obj/foo/bar.input1.o\"\r\n"
816d528ed9Sopenharmony_ci        "  },\r\n"
826d528ed9Sopenharmony_ci        "  {\r\n"
836d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.cc\",\r\n"
846d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
856d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input2.cc     -o  "
866d528ed9Sopenharmony_ci        "obj/foo/bar.input2.o\"\r\n"
876d528ed9Sopenharmony_ci        "  }\r\n"
886d528ed9Sopenharmony_ci        "]\r\n";
896d528ed9Sopenharmony_ci#else
906d528ed9Sopenharmony_ci    const char expected[] =
916d528ed9Sopenharmony_ci        "[\n"
926d528ed9Sopenharmony_ci        "  {\n"
936d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\n"
946d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
956d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc     -o  "
966d528ed9Sopenharmony_ci        "obj/foo/bar.input1.o\"\n"
976d528ed9Sopenharmony_ci        "  },\n"
986d528ed9Sopenharmony_ci        "  {\n"
996d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.cc\",\n"
1006d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
1016d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input2.cc     -o  "
1026d528ed9Sopenharmony_ci        "obj/foo/bar.input2.o\"\n"
1036d528ed9Sopenharmony_ci        "  }\n"
1046d528ed9Sopenharmony_ci        "]\n";
1056d528ed9Sopenharmony_ci#endif
1066d528ed9Sopenharmony_ci    EXPECT_EQ(expected, out);
1076d528ed9Sopenharmony_ci  }
1086d528ed9Sopenharmony_ci
1096d528ed9Sopenharmony_ci  // A shared library that depends on the source set.
1106d528ed9Sopenharmony_ci  Target shlib_target(settings(), Label(SourceDir("//foo/"), "shlib"));
1116d528ed9Sopenharmony_ci  shlib_target.sources().push_back(SourceFile("//foo/input3.cc"));
1126d528ed9Sopenharmony_ci  shlib_target.set_output_type(Target::SHARED_LIBRARY);
1136d528ed9Sopenharmony_ci  shlib_target.public_deps().push_back(LabelTargetPair(&target));
1146d528ed9Sopenharmony_ci  shlib_target.SetToolchain(toolchain());
1156d528ed9Sopenharmony_ci  ASSERT_TRUE(shlib_target.OnResolved(&err));
1166d528ed9Sopenharmony_ci  targets.push_back(&shlib_target);
1176d528ed9Sopenharmony_ci
1186d528ed9Sopenharmony_ci  {
1196d528ed9Sopenharmony_ci    CompileCommandsWriter writer;
1206d528ed9Sopenharmony_ci    std::string out = writer.RenderJSON(build_settings(), targets);
1216d528ed9Sopenharmony_ci
1226d528ed9Sopenharmony_ci#if defined(OS_WIN)
1236d528ed9Sopenharmony_ci    const char expected[] =
1246d528ed9Sopenharmony_ci        "[\r\n"
1256d528ed9Sopenharmony_ci        "  {\r\n"
1266d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\r\n"
1276d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
1286d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc     -o  "
1296d528ed9Sopenharmony_ci        "obj/foo/bar.input1.o\"\r\n"
1306d528ed9Sopenharmony_ci        "  },\r\n"
1316d528ed9Sopenharmony_ci        "  {\r\n"
1326d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.cc\",\r\n"
1336d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
1346d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input2.cc     -o  "
1356d528ed9Sopenharmony_ci        "obj/foo/bar.input2.o\"\r\n"
1366d528ed9Sopenharmony_ci        "  },\r\n"
1376d528ed9Sopenharmony_ci        "  {\r\n"
1386d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input3.cc\",\r\n"
1396d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
1406d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input3.cc     -o  "
1416d528ed9Sopenharmony_ci        "obj/foo/libshlib.input3.o\"\r\n"
1426d528ed9Sopenharmony_ci        "  }\r\n"
1436d528ed9Sopenharmony_ci        "]\r\n";
1446d528ed9Sopenharmony_ci#else
1456d528ed9Sopenharmony_ci    const char expected[] =
1466d528ed9Sopenharmony_ci        "[\n"
1476d528ed9Sopenharmony_ci        "  {\n"
1486d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\n"
1496d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
1506d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc     -o  "
1516d528ed9Sopenharmony_ci        "obj/foo/bar.input1.o\"\n"
1526d528ed9Sopenharmony_ci        "  },\n"
1536d528ed9Sopenharmony_ci        "  {\n"
1546d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.cc\",\n"
1556d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
1566d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input2.cc     -o  "
1576d528ed9Sopenharmony_ci        "obj/foo/bar.input2.o\"\n"
1586d528ed9Sopenharmony_ci        "  },\n"
1596d528ed9Sopenharmony_ci        "  {\n"
1606d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input3.cc\",\n"
1616d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
1626d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input3.cc     -o  "
1636d528ed9Sopenharmony_ci        "obj/foo/libshlib.input3.o\"\n"
1646d528ed9Sopenharmony_ci        "  }\n"
1656d528ed9Sopenharmony_ci        "]\n";
1666d528ed9Sopenharmony_ci#endif
1676d528ed9Sopenharmony_ci    EXPECT_EQ(expected, out);
1686d528ed9Sopenharmony_ci  }
1696d528ed9Sopenharmony_ci
1706d528ed9Sopenharmony_ci  // A static library that depends on the source set (should not link it).
1716d528ed9Sopenharmony_ci  Target stlib_target(settings(), Label(SourceDir("//foo/"), "stlib"));
1726d528ed9Sopenharmony_ci  stlib_target.sources().push_back(SourceFile("//foo/input4.cc"));
1736d528ed9Sopenharmony_ci  stlib_target.set_output_type(Target::STATIC_LIBRARY);
1746d528ed9Sopenharmony_ci  stlib_target.public_deps().push_back(LabelTargetPair(&target));
1756d528ed9Sopenharmony_ci  stlib_target.SetToolchain(toolchain());
1766d528ed9Sopenharmony_ci  ASSERT_TRUE(stlib_target.OnResolved(&err));
1776d528ed9Sopenharmony_ci  targets.push_back(&stlib_target);
1786d528ed9Sopenharmony_ci
1796d528ed9Sopenharmony_ci  {
1806d528ed9Sopenharmony_ci    CompileCommandsWriter writer;
1816d528ed9Sopenharmony_ci    std::string out = writer.RenderJSON(build_settings(), targets);
1826d528ed9Sopenharmony_ci
1836d528ed9Sopenharmony_ci#if defined(OS_WIN)
1846d528ed9Sopenharmony_ci    const char expected[] =
1856d528ed9Sopenharmony_ci        "[\r\n"
1866d528ed9Sopenharmony_ci        "  {\r\n"
1876d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\r\n"
1886d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
1896d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc     -o  "
1906d528ed9Sopenharmony_ci        "obj/foo/bar.input1.o\"\r\n"
1916d528ed9Sopenharmony_ci        "  },\r\n"
1926d528ed9Sopenharmony_ci        "  {\r\n"
1936d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.cc\",\r\n"
1946d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
1956d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input2.cc     -o  "
1966d528ed9Sopenharmony_ci        "obj/foo/bar.input2.o\"\r\n"
1976d528ed9Sopenharmony_ci        "  },\r\n"
1986d528ed9Sopenharmony_ci        "  {\r\n"
1996d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input3.cc\",\r\n"
2006d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
2016d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input3.cc     -o  "
2026d528ed9Sopenharmony_ci        "obj/foo/libshlib.input3.o\"\r\n"
2036d528ed9Sopenharmony_ci        "  },\r\n"
2046d528ed9Sopenharmony_ci        "  {\r\n"
2056d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input4.cc\",\r\n"
2066d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
2076d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input4.cc     -o  "
2086d528ed9Sopenharmony_ci        "obj/foo/libstlib.input4.o\"\r\n"
2096d528ed9Sopenharmony_ci        "  }\r\n"
2106d528ed9Sopenharmony_ci        "]\r\n";
2116d528ed9Sopenharmony_ci#else
2126d528ed9Sopenharmony_ci    const char expected[] =
2136d528ed9Sopenharmony_ci        "[\n"
2146d528ed9Sopenharmony_ci        "  {\n"
2156d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\n"
2166d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
2176d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc     -o  "
2186d528ed9Sopenharmony_ci        "obj/foo/bar.input1.o\"\n"
2196d528ed9Sopenharmony_ci        "  },\n"
2206d528ed9Sopenharmony_ci        "  {\n"
2216d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.cc\",\n"
2226d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
2236d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input2.cc     -o  "
2246d528ed9Sopenharmony_ci        "obj/foo/bar.input2.o\"\n"
2256d528ed9Sopenharmony_ci        "  },\n"
2266d528ed9Sopenharmony_ci        "  {\n"
2276d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input3.cc\",\n"
2286d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
2296d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input3.cc     -o  "
2306d528ed9Sopenharmony_ci        "obj/foo/libshlib.input3.o\"\n"
2316d528ed9Sopenharmony_ci        "  },\n"
2326d528ed9Sopenharmony_ci        "  {\n"
2336d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input4.cc\",\n"
2346d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
2356d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input4.cc     -o  "
2366d528ed9Sopenharmony_ci        "obj/foo/libstlib.input4.o\"\n"
2376d528ed9Sopenharmony_ci        "  }\n"
2386d528ed9Sopenharmony_ci        "]\n";
2396d528ed9Sopenharmony_ci#endif
2406d528ed9Sopenharmony_ci    EXPECT_EQ(expected, out);
2416d528ed9Sopenharmony_ci  }
2426d528ed9Sopenharmony_ci}
2436d528ed9Sopenharmony_ci
2446d528ed9Sopenharmony_ciTEST_F(CompileCommandsTest, EscapeDefines) {
2456d528ed9Sopenharmony_ci  Err err;
2466d528ed9Sopenharmony_ci
2476d528ed9Sopenharmony_ci  std::vector<const Target*> targets;
2486d528ed9Sopenharmony_ci  TestTarget target(setup(), "//foo:bar", Target::STATIC_LIBRARY);
2496d528ed9Sopenharmony_ci  target.sources().push_back(SourceFile("//foo/input.cc"));
2506d528ed9Sopenharmony_ci  target.config_values().defines().push_back("BOOL_DEF");
2516d528ed9Sopenharmony_ci  target.config_values().defines().push_back("INT_DEF=123");
2526d528ed9Sopenharmony_ci  target.config_values().defines().push_back("STR_DEF=\"ABCD 1\"");
2536d528ed9Sopenharmony_ci  target.config_values().defines().push_back("INCLUDE=<header.h>");
2546d528ed9Sopenharmony_ci  ASSERT_TRUE(target.OnResolved(&err));
2556d528ed9Sopenharmony_ci  targets.push_back(&target);
2566d528ed9Sopenharmony_ci
2576d528ed9Sopenharmony_ci  CompileCommandsWriter writer;
2586d528ed9Sopenharmony_ci  std::string out = writer.RenderJSON(build_settings(), targets);
2596d528ed9Sopenharmony_ci
2606d528ed9Sopenharmony_ci  const char expected[] =
2616d528ed9Sopenharmony_ci      "-DBOOL_DEF -DINT_DEF=123 \\\"-DSTR_DEF=\\\\\\\"ABCD 1\\\\\\\"\\\" "
2626d528ed9Sopenharmony_ci      "\\\"-DINCLUDE=\\u003Cheader.h>\\\"";
2636d528ed9Sopenharmony_ci  EXPECT_TRUE(out.find(expected) != std::string::npos);
2646d528ed9Sopenharmony_ci}
2656d528ed9Sopenharmony_ci
2666d528ed9Sopenharmony_ciTEST_F(CompileCommandsTest, WinPrecompiledHeaders) {
2676d528ed9Sopenharmony_ci  Err err;
2686d528ed9Sopenharmony_ci
2696d528ed9Sopenharmony_ci  // This setup's toolchain does not have precompiled headers defined.
2706d528ed9Sopenharmony_ci  // A precompiled header toolchain.
2716d528ed9Sopenharmony_ci  Settings pch_settings(build_settings(), "withpch/");
2726d528ed9Sopenharmony_ci  Toolchain pch_toolchain(&pch_settings,
2736d528ed9Sopenharmony_ci                          Label(SourceDir("//toolchain/"), "withpch"));
2746d528ed9Sopenharmony_ci  pch_settings.set_toolchain_label(pch_toolchain.label());
2756d528ed9Sopenharmony_ci  pch_settings.set_default_toolchain_label(toolchain()->label());
2766d528ed9Sopenharmony_ci
2776d528ed9Sopenharmony_ci  // Declare a C++ compiler that supports PCH.
2786d528ed9Sopenharmony_ci  std::unique_ptr<Tool> cxx = Tool::CreateTool(CTool::kCToolCxx);
2796d528ed9Sopenharmony_ci  CTool* cxx_tool = cxx->AsC();
2806d528ed9Sopenharmony_ci  TestWithScope::SetCommandForTool(
2816d528ed9Sopenharmony_ci      "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} "
2826d528ed9Sopenharmony_ci      "-o {{output}}",
2836d528ed9Sopenharmony_ci      cxx_tool);
2846d528ed9Sopenharmony_ci  cxx_tool->set_outputs(SubstitutionList::MakeForTest(
2856d528ed9Sopenharmony_ci      "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
2866d528ed9Sopenharmony_ci  cxx_tool->set_precompiled_header_type(CTool::PCH_MSVC);
2876d528ed9Sopenharmony_ci  pch_toolchain.SetTool(std::move(cxx));
2886d528ed9Sopenharmony_ci
2896d528ed9Sopenharmony_ci  // Add a C compiler as well.
2906d528ed9Sopenharmony_ci  std::unique_ptr<Tool> cc = Tool::CreateTool(CTool::kCToolCc);
2916d528ed9Sopenharmony_ci  CTool* cc_tool = cc->AsC();
2926d528ed9Sopenharmony_ci  TestWithScope::SetCommandForTool(
2936d528ed9Sopenharmony_ci      "cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} "
2946d528ed9Sopenharmony_ci      "-o {{output}}",
2956d528ed9Sopenharmony_ci      cc_tool);
2966d528ed9Sopenharmony_ci  cc_tool->set_outputs(SubstitutionList::MakeForTest(
2976d528ed9Sopenharmony_ci      "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
2986d528ed9Sopenharmony_ci  cc_tool->set_precompiled_header_type(CTool::PCH_MSVC);
2996d528ed9Sopenharmony_ci  pch_toolchain.SetTool(std::move(cc));
3006d528ed9Sopenharmony_ci  pch_toolchain.ToolchainSetupComplete();
3016d528ed9Sopenharmony_ci
3026d528ed9Sopenharmony_ci  // This target doesn't specify precompiled headers.
3036d528ed9Sopenharmony_ci  {
3046d528ed9Sopenharmony_ci    std::vector<const Target*> targets;
3056d528ed9Sopenharmony_ci    Target no_pch_target(&pch_settings,
3066d528ed9Sopenharmony_ci                         Label(SourceDir("//foo/"), "no_pch_target"));
3076d528ed9Sopenharmony_ci    no_pch_target.set_output_type(Target::SOURCE_SET);
3086d528ed9Sopenharmony_ci    no_pch_target.visibility().SetPublic();
3096d528ed9Sopenharmony_ci    no_pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
3106d528ed9Sopenharmony_ci    no_pch_target.sources().push_back(SourceFile("//foo/input2.c"));
3116d528ed9Sopenharmony_ci    no_pch_target.config_values().cflags_c().push_back("-std=c99");
3126d528ed9Sopenharmony_ci    no_pch_target.SetToolchain(&pch_toolchain);
3136d528ed9Sopenharmony_ci    ASSERT_TRUE(no_pch_target.OnResolved(&err));
3146d528ed9Sopenharmony_ci    targets.push_back(&no_pch_target);
3156d528ed9Sopenharmony_ci
3166d528ed9Sopenharmony_ci    CompileCommandsWriter writer;
3176d528ed9Sopenharmony_ci    std::string out = writer.RenderJSON(build_settings(), targets);
3186d528ed9Sopenharmony_ci
3196d528ed9Sopenharmony_ci#if defined(OS_WIN)
3206d528ed9Sopenharmony_ci    const char no_pch_expected[] =
3216d528ed9Sopenharmony_ci        "[\r\n"
3226d528ed9Sopenharmony_ci        "  {\r\n"
3236d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\r\n"
3246d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
3256d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc     -o  "
3266d528ed9Sopenharmony_ci        "withpch/obj/foo/no_pch_target.input1.o\"\r\n"
3276d528ed9Sopenharmony_ci        "  },\r\n"
3286d528ed9Sopenharmony_ci        "  {\r\n"
3296d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.c\",\r\n"
3306d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
3316d528ed9Sopenharmony_ci        "    \"command\": \"cc ../../foo/input2.c   -std=c99   -o  "
3326d528ed9Sopenharmony_ci        "withpch/obj/foo/no_pch_target.input2.o\"\r\n"
3336d528ed9Sopenharmony_ci        "  }\r\n"
3346d528ed9Sopenharmony_ci        "]\r\n";
3356d528ed9Sopenharmony_ci#else
3366d528ed9Sopenharmony_ci    const char no_pch_expected[] =
3376d528ed9Sopenharmony_ci        "[\n"
3386d528ed9Sopenharmony_ci        "  {\n"
3396d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\n"
3406d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
3416d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc     -o  "
3426d528ed9Sopenharmony_ci        "withpch/obj/foo/no_pch_target.input1.o\"\n"
3436d528ed9Sopenharmony_ci        "  },\n"
3446d528ed9Sopenharmony_ci        "  {\n"
3456d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.c\",\n"
3466d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
3476d528ed9Sopenharmony_ci        "    \"command\": \"cc ../../foo/input2.c   -std=c99   -o  "
3486d528ed9Sopenharmony_ci        "withpch/obj/foo/no_pch_target.input2.o\"\n"
3496d528ed9Sopenharmony_ci        "  }\n"
3506d528ed9Sopenharmony_ci        "]\n";
3516d528ed9Sopenharmony_ci#endif
3526d528ed9Sopenharmony_ci    EXPECT_EQ(no_pch_expected, out);
3536d528ed9Sopenharmony_ci  }
3546d528ed9Sopenharmony_ci
3556d528ed9Sopenharmony_ci  // This target specifies PCH.
3566d528ed9Sopenharmony_ci  {
3576d528ed9Sopenharmony_ci    std::vector<const Target*> targets;
3586d528ed9Sopenharmony_ci    Target pch_target(&pch_settings, Label(SourceDir("//foo/"), "pch_target"));
3596d528ed9Sopenharmony_ci    pch_target.config_values().set_precompiled_header("build/precompile.h");
3606d528ed9Sopenharmony_ci    pch_target.config_values().set_precompiled_source(
3616d528ed9Sopenharmony_ci        SourceFile("//build/precompile.cc"));
3626d528ed9Sopenharmony_ci    pch_target.set_output_type(Target::SOURCE_SET);
3636d528ed9Sopenharmony_ci    pch_target.visibility().SetPublic();
3646d528ed9Sopenharmony_ci    pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
3656d528ed9Sopenharmony_ci    pch_target.sources().push_back(SourceFile("//foo/input2.c"));
3666d528ed9Sopenharmony_ci    pch_target.SetToolchain(&pch_toolchain);
3676d528ed9Sopenharmony_ci    ASSERT_TRUE(pch_target.OnResolved(&err));
3686d528ed9Sopenharmony_ci    targets.push_back(&pch_target);
3696d528ed9Sopenharmony_ci
3706d528ed9Sopenharmony_ci    CompileCommandsWriter writer;
3716d528ed9Sopenharmony_ci    std::string out = writer.RenderJSON(build_settings(), targets);
3726d528ed9Sopenharmony_ci
3736d528ed9Sopenharmony_ci#if defined(OS_WIN)
3746d528ed9Sopenharmony_ci    const char pch_win_expected[] =
3756d528ed9Sopenharmony_ci        "[\r\n"
3766d528ed9Sopenharmony_ci        "  {\r\n"
3776d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\r\n"
3786d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
3796d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc   "
3806d528ed9Sopenharmony_ci        "/Fpwithpch/obj/foo/pch_target_cc.pch /Yubuild/precompile.h   -o  "
3816d528ed9Sopenharmony_ci        "withpch/obj/foo/pch_target.input1.o\"\r\n"
3826d528ed9Sopenharmony_ci        "  },\r\n"
3836d528ed9Sopenharmony_ci        "  {\r\n"
3846d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.c\",\r\n"
3856d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
3866d528ed9Sopenharmony_ci        "    \"command\": \"cc ../../foo/input2.c   "
3876d528ed9Sopenharmony_ci        "/Fpwithpch/obj/foo/pch_target_c.pch /Yubuild/precompile.h   -o  "
3886d528ed9Sopenharmony_ci        "withpch/obj/foo/pch_target.input2.o\"\r\n"
3896d528ed9Sopenharmony_ci        "  }\r\n"
3906d528ed9Sopenharmony_ci        "]\r\n";
3916d528ed9Sopenharmony_ci#else
3926d528ed9Sopenharmony_ci    const char pch_win_expected[] =
3936d528ed9Sopenharmony_ci        "[\n"
3946d528ed9Sopenharmony_ci        "  {\n"
3956d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\n"
3966d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
3976d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc   "
3986d528ed9Sopenharmony_ci        "/Fpwithpch/obj/foo/pch_target_cc.pch /Yubuild/precompile.h   -o  "
3996d528ed9Sopenharmony_ci        "withpch/obj/foo/pch_target.input1.o\"\n"
4006d528ed9Sopenharmony_ci        "  },\n"
4016d528ed9Sopenharmony_ci        "  {\n"
4026d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.c\",\n"
4036d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
4046d528ed9Sopenharmony_ci        "    \"command\": \"cc ../../foo/input2.c   "
4056d528ed9Sopenharmony_ci        "/Fpwithpch/obj/foo/pch_target_c.pch /Yubuild/precompile.h   -o  "
4066d528ed9Sopenharmony_ci        "withpch/obj/foo/pch_target.input2.o\"\n"
4076d528ed9Sopenharmony_ci        "  }\n"
4086d528ed9Sopenharmony_ci        "]\n";
4096d528ed9Sopenharmony_ci#endif
4106d528ed9Sopenharmony_ci    EXPECT_EQ(pch_win_expected, out);
4116d528ed9Sopenharmony_ci  }
4126d528ed9Sopenharmony_ci}
4136d528ed9Sopenharmony_ci
4146d528ed9Sopenharmony_ciTEST_F(CompileCommandsTest, GCCPrecompiledHeaders) {
4156d528ed9Sopenharmony_ci  Err err;
4166d528ed9Sopenharmony_ci
4176d528ed9Sopenharmony_ci  // This setup's toolchain does not have precompiled headers defined.
4186d528ed9Sopenharmony_ci  // A precompiled header toolchain.
4196d528ed9Sopenharmony_ci  Settings pch_settings(build_settings(), "withpch/");
4206d528ed9Sopenharmony_ci  Toolchain pch_toolchain(&pch_settings,
4216d528ed9Sopenharmony_ci                          Label(SourceDir("//toolchain/"), "withpch"));
4226d528ed9Sopenharmony_ci  pch_settings.set_toolchain_label(pch_toolchain.label());
4236d528ed9Sopenharmony_ci  pch_settings.set_default_toolchain_label(toolchain()->label());
4246d528ed9Sopenharmony_ci
4256d528ed9Sopenharmony_ci  // Declare a C++ compiler that supports PCH.
4266d528ed9Sopenharmony_ci  std::unique_ptr<Tool> cxx = Tool::CreateTool(CTool::kCToolCxx);
4276d528ed9Sopenharmony_ci  CTool* cxx_tool = cxx->AsC();
4286d528ed9Sopenharmony_ci  TestWithScope::SetCommandForTool(
4296d528ed9Sopenharmony_ci      "c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} "
4306d528ed9Sopenharmony_ci      "-o {{output}}",
4316d528ed9Sopenharmony_ci      cxx_tool);
4326d528ed9Sopenharmony_ci  cxx_tool->set_outputs(SubstitutionList::MakeForTest(
4336d528ed9Sopenharmony_ci      "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
4346d528ed9Sopenharmony_ci  cxx_tool->set_precompiled_header_type(CTool::PCH_GCC);
4356d528ed9Sopenharmony_ci  pch_toolchain.SetTool(std::move(cxx));
4366d528ed9Sopenharmony_ci  pch_toolchain.ToolchainSetupComplete();
4376d528ed9Sopenharmony_ci
4386d528ed9Sopenharmony_ci  // Add a C compiler as well.
4396d528ed9Sopenharmony_ci  std::unique_ptr<Tool> cc = Tool::CreateTool(CTool::kCToolCc);
4406d528ed9Sopenharmony_ci  CTool* cc_tool = cc->AsC();
4416d528ed9Sopenharmony_ci  TestWithScope::SetCommandForTool(
4426d528ed9Sopenharmony_ci      "cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} "
4436d528ed9Sopenharmony_ci      "-o {{output}}",
4446d528ed9Sopenharmony_ci      cc_tool);
4456d528ed9Sopenharmony_ci  cc_tool->set_outputs(SubstitutionList::MakeForTest(
4466d528ed9Sopenharmony_ci      "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
4476d528ed9Sopenharmony_ci  cc_tool->set_precompiled_header_type(CTool::PCH_GCC);
4486d528ed9Sopenharmony_ci  pch_toolchain.SetTool(std::move(cc));
4496d528ed9Sopenharmony_ci  pch_toolchain.ToolchainSetupComplete();
4506d528ed9Sopenharmony_ci
4516d528ed9Sopenharmony_ci  // This target doesn't specify precompiled headers.
4526d528ed9Sopenharmony_ci  {
4536d528ed9Sopenharmony_ci    std::vector<const Target*> targets;
4546d528ed9Sopenharmony_ci    Target no_pch_target(&pch_settings,
4556d528ed9Sopenharmony_ci                         Label(SourceDir("//foo/"), "no_pch_target"));
4566d528ed9Sopenharmony_ci    no_pch_target.set_output_type(Target::SOURCE_SET);
4576d528ed9Sopenharmony_ci    no_pch_target.visibility().SetPublic();
4586d528ed9Sopenharmony_ci    no_pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
4596d528ed9Sopenharmony_ci    no_pch_target.sources().push_back(SourceFile("//foo/input2.c"));
4606d528ed9Sopenharmony_ci    no_pch_target.config_values().cflags_c().push_back("-std=c99");
4616d528ed9Sopenharmony_ci    no_pch_target.SetToolchain(&pch_toolchain);
4626d528ed9Sopenharmony_ci    ASSERT_TRUE(no_pch_target.OnResolved(&err));
4636d528ed9Sopenharmony_ci    targets.push_back(&no_pch_target);
4646d528ed9Sopenharmony_ci
4656d528ed9Sopenharmony_ci    CompileCommandsWriter writer;
4666d528ed9Sopenharmony_ci    std::string out = writer.RenderJSON(build_settings(), targets);
4676d528ed9Sopenharmony_ci
4686d528ed9Sopenharmony_ci#if defined(OS_WIN)
4696d528ed9Sopenharmony_ci    const char no_pch_expected[] =
4706d528ed9Sopenharmony_ci        "[\r\n"
4716d528ed9Sopenharmony_ci        "  {\r\n"
4726d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\r\n"
4736d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
4746d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc     -o  "
4756d528ed9Sopenharmony_ci        "withpch/obj/foo/no_pch_target.input1.o\"\r\n"
4766d528ed9Sopenharmony_ci        "  },\r\n"
4776d528ed9Sopenharmony_ci        "  {\r\n"
4786d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.c\",\r\n"
4796d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
4806d528ed9Sopenharmony_ci        "    \"command\": \"cc ../../foo/input2.c   -std=c99   -o  "
4816d528ed9Sopenharmony_ci        "withpch/obj/foo/no_pch_target.input2.o\"\r\n"
4826d528ed9Sopenharmony_ci        "  }\r\n"
4836d528ed9Sopenharmony_ci        "]\r\n";
4846d528ed9Sopenharmony_ci#else
4856d528ed9Sopenharmony_ci    const char no_pch_expected[] =
4866d528ed9Sopenharmony_ci        "[\n"
4876d528ed9Sopenharmony_ci        "  {\n"
4886d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\n"
4896d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
4906d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc     -o  "
4916d528ed9Sopenharmony_ci        "withpch/obj/foo/no_pch_target.input1.o\"\n"
4926d528ed9Sopenharmony_ci        "  },\n"
4936d528ed9Sopenharmony_ci        "  {\n"
4946d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.c\",\n"
4956d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
4966d528ed9Sopenharmony_ci        "    \"command\": \"cc ../../foo/input2.c   -std=c99   -o  "
4976d528ed9Sopenharmony_ci        "withpch/obj/foo/no_pch_target.input2.o\"\n"
4986d528ed9Sopenharmony_ci        "  }\n"
4996d528ed9Sopenharmony_ci        "]\n";
5006d528ed9Sopenharmony_ci#endif
5016d528ed9Sopenharmony_ci    EXPECT_EQ(no_pch_expected, out);
5026d528ed9Sopenharmony_ci  }
5036d528ed9Sopenharmony_ci
5046d528ed9Sopenharmony_ci  // This target specifies PCH.
5056d528ed9Sopenharmony_ci  {
5066d528ed9Sopenharmony_ci    std::vector<const Target*> targets;
5076d528ed9Sopenharmony_ci    Target pch_target(&pch_settings, Label(SourceDir("//foo/"), "pch_target"));
5086d528ed9Sopenharmony_ci    pch_target.config_values().set_precompiled_source(
5096d528ed9Sopenharmony_ci        SourceFile("//build/precompile.h"));
5106d528ed9Sopenharmony_ci    pch_target.config_values().cflags_c().push_back("-std=c99");
5116d528ed9Sopenharmony_ci    pch_target.set_output_type(Target::SOURCE_SET);
5126d528ed9Sopenharmony_ci    pch_target.visibility().SetPublic();
5136d528ed9Sopenharmony_ci    pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
5146d528ed9Sopenharmony_ci    pch_target.sources().push_back(SourceFile("//foo/input2.c"));
5156d528ed9Sopenharmony_ci    pch_target.SetToolchain(&pch_toolchain);
5166d528ed9Sopenharmony_ci    ASSERT_TRUE(pch_target.OnResolved(&err));
5176d528ed9Sopenharmony_ci    targets.push_back(&pch_target);
5186d528ed9Sopenharmony_ci
5196d528ed9Sopenharmony_ci    CompileCommandsWriter writer;
5206d528ed9Sopenharmony_ci    std::string out = writer.RenderJSON(build_settings(), targets);
5216d528ed9Sopenharmony_ci
5226d528ed9Sopenharmony_ci#if defined(OS_WIN)
5236d528ed9Sopenharmony_ci    const char pch_gcc_expected[] =
5246d528ed9Sopenharmony_ci        "[\r\n"
5256d528ed9Sopenharmony_ci        "  {\r\n"
5266d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\r\n"
5276d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
5286d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc   -include "
5296d528ed9Sopenharmony_ci        "withpch/obj/build/pch_target.precompile.h-cc   -o  "
5306d528ed9Sopenharmony_ci        "withpch/obj/foo/pch_target.input1.o\"\r\n"
5316d528ed9Sopenharmony_ci        "  },\r\n"
5326d528ed9Sopenharmony_ci        "  {\r\n"
5336d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.c\",\r\n"
5346d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\r\n"
5356d528ed9Sopenharmony_ci        "    \"command\": \"cc ../../foo/input2.c   -std=c99 -include "
5366d528ed9Sopenharmony_ci        "withpch/obj/build/pch_target.precompile.h-c   -o  "
5376d528ed9Sopenharmony_ci        "withpch/obj/foo/pch_target.input2.o\"\r\n"
5386d528ed9Sopenharmony_ci        "  }\r\n"
5396d528ed9Sopenharmony_ci        "]\r\n";
5406d528ed9Sopenharmony_ci#else
5416d528ed9Sopenharmony_ci    const char pch_gcc_expected[] =
5426d528ed9Sopenharmony_ci        "[\n"
5436d528ed9Sopenharmony_ci        "  {\n"
5446d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input1.cc\",\n"
5456d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
5466d528ed9Sopenharmony_ci        "    \"command\": \"c++ ../../foo/input1.cc   -include "
5476d528ed9Sopenharmony_ci        "withpch/obj/build/pch_target.precompile.h-cc   -o  "
5486d528ed9Sopenharmony_ci        "withpch/obj/foo/pch_target.input1.o\"\n"
5496d528ed9Sopenharmony_ci        "  },\n"
5506d528ed9Sopenharmony_ci        "  {\n"
5516d528ed9Sopenharmony_ci        "    \"file\": \"../../foo/input2.c\",\n"
5526d528ed9Sopenharmony_ci        "    \"directory\": \"out/Debug\",\n"
5536d528ed9Sopenharmony_ci        "    \"command\": \"cc ../../foo/input2.c   -std=c99 -include "
5546d528ed9Sopenharmony_ci        "withpch/obj/build/pch_target.precompile.h-c   -o  "
5556d528ed9Sopenharmony_ci        "withpch/obj/foo/pch_target.input2.o\"\n"
5566d528ed9Sopenharmony_ci        "  }\n"
5576d528ed9Sopenharmony_ci        "]\n";
5586d528ed9Sopenharmony_ci#endif
5596d528ed9Sopenharmony_ci    EXPECT_EQ(pch_gcc_expected, out);
5606d528ed9Sopenharmony_ci  }
5616d528ed9Sopenharmony_ci}
5626d528ed9Sopenharmony_ci
5636d528ed9Sopenharmony_ciTEST_F(CompileCommandsTest, EscapedFlags) {
5646d528ed9Sopenharmony_ci  Err err;
5656d528ed9Sopenharmony_ci
5666d528ed9Sopenharmony_ci  std::vector<const Target*> targets;
5676d528ed9Sopenharmony_ci  Target target(settings(), Label(SourceDir("//foo/"), "bar"));
5686d528ed9Sopenharmony_ci  target.set_output_type(Target::SOURCE_SET);
5696d528ed9Sopenharmony_ci  target.sources().push_back(SourceFile("//foo/input1.c"));
5706d528ed9Sopenharmony_ci  target.config_values().cflags_c().push_back("-DCONFIG=\"/config\"");
5716d528ed9Sopenharmony_ci  target.SetToolchain(toolchain());
5726d528ed9Sopenharmony_ci  ASSERT_TRUE(target.OnResolved(&err));
5736d528ed9Sopenharmony_ci  targets.push_back(&target);
5746d528ed9Sopenharmony_ci
5756d528ed9Sopenharmony_ci  CompileCommandsWriter writer;
5766d528ed9Sopenharmony_ci  std::string out = writer.RenderJSON(build_settings(), targets);
5776d528ed9Sopenharmony_ci
5786d528ed9Sopenharmony_ci#if defined(OS_WIN)
5796d528ed9Sopenharmony_ci  const char expected[] =
5806d528ed9Sopenharmony_ci      "[\r\n"
5816d528ed9Sopenharmony_ci      "  {\r\n"
5826d528ed9Sopenharmony_ci      "    \"file\": \"../../foo/input1.c\",\r\n"
5836d528ed9Sopenharmony_ci      "    \"directory\": \"out/Debug\",\r\n"
5846d528ed9Sopenharmony_ci      "    \"command\": \"cc ../../foo/input1.c   -DCONFIG=\\\"/config\\\"   "
5856d528ed9Sopenharmony_ci      "-o  obj/foo/bar.input1.o\"\r\n"
5866d528ed9Sopenharmony_ci      "  }\r\n"
5876d528ed9Sopenharmony_ci      "]\r\n";
5886d528ed9Sopenharmony_ci#else
5896d528ed9Sopenharmony_ci  const char expected[] =
5906d528ed9Sopenharmony_ci      "[\n"
5916d528ed9Sopenharmony_ci      "  {\n"
5926d528ed9Sopenharmony_ci      "    \"file\": \"../../foo/input1.c\",\n"
5936d528ed9Sopenharmony_ci      "    \"directory\": \"out/Debug\",\n"
5946d528ed9Sopenharmony_ci      "    \"command\": \"cc ../../foo/input1.c   -DCONFIG=\\\"/config\\\"   "
5956d528ed9Sopenharmony_ci      "-o  obj/foo/bar.input1.o\"\n"
5966d528ed9Sopenharmony_ci      "  }\n"
5976d528ed9Sopenharmony_ci      "]\n";
5986d528ed9Sopenharmony_ci#endif
5996d528ed9Sopenharmony_ci  EXPECT_EQ(expected, out);
6006d528ed9Sopenharmony_ci}
6016d528ed9Sopenharmony_ci
6026d528ed9Sopenharmony_ciTEST_F(CompileCommandsTest, CollectTargets) {
6036d528ed9Sopenharmony_ci  // Contruct the dependency tree:
6046d528ed9Sopenharmony_ci  //
6056d528ed9Sopenharmony_ci  //   //foo:bar1
6066d528ed9Sopenharmony_ci  //     //base:base
6076d528ed9Sopenharmony_ci  //   //foo:bar2
6086d528ed9Sopenharmony_ci  //     //base:i18n
6096d528ed9Sopenharmony_ci  //       //base:base
6106d528ed9Sopenharmony_ci  //       //third_party:icu
6116d528ed9Sopenharmony_ci  //   //random:random
6126d528ed9Sopenharmony_ci  Err err;
6136d528ed9Sopenharmony_ci  std::vector<const Target*> targets;
6146d528ed9Sopenharmony_ci
6156d528ed9Sopenharmony_ci  Target icu_target(settings(), Label(SourceDir("//third_party/"), "icu"));
6166d528ed9Sopenharmony_ci  icu_target.set_output_type(Target::SOURCE_SET);
6176d528ed9Sopenharmony_ci  icu_target.visibility().SetPublic();
6186d528ed9Sopenharmony_ci  icu_target.SetToolchain(toolchain());
6196d528ed9Sopenharmony_ci  ASSERT_TRUE(icu_target.OnResolved(&err));
6206d528ed9Sopenharmony_ci  targets.push_back(&icu_target);
6216d528ed9Sopenharmony_ci
6226d528ed9Sopenharmony_ci  Target base_target(settings(), Label(SourceDir("//base/"), "base"));
6236d528ed9Sopenharmony_ci  base_target.set_output_type(Target::SOURCE_SET);
6246d528ed9Sopenharmony_ci  base_target.visibility().SetPublic();
6256d528ed9Sopenharmony_ci  base_target.SetToolchain(toolchain());
6266d528ed9Sopenharmony_ci  ASSERT_TRUE(base_target.OnResolved(&err));
6276d528ed9Sopenharmony_ci  targets.push_back(&base_target);
6286d528ed9Sopenharmony_ci
6296d528ed9Sopenharmony_ci  Target base_i18n(settings(), Label(SourceDir("//base/"), "i18n"));
6306d528ed9Sopenharmony_ci  base_i18n.set_output_type(Target::SOURCE_SET);
6316d528ed9Sopenharmony_ci  base_i18n.visibility().SetPublic();
6326d528ed9Sopenharmony_ci  base_i18n.private_deps().push_back(LabelTargetPair(&icu_target));
6336d528ed9Sopenharmony_ci  base_i18n.public_deps().push_back(LabelTargetPair(&base_target));
6346d528ed9Sopenharmony_ci  base_i18n.SetToolchain(toolchain());
6356d528ed9Sopenharmony_ci  ASSERT_TRUE(base_i18n.OnResolved(&err))
6366d528ed9Sopenharmony_ci      << err.message() << " " << err.help_text();
6376d528ed9Sopenharmony_ci  targets.push_back(&base_i18n);
6386d528ed9Sopenharmony_ci
6396d528ed9Sopenharmony_ci  Target target1(settings(), Label(SourceDir("//foo/"), "bar1"));
6406d528ed9Sopenharmony_ci  target1.set_output_type(Target::SOURCE_SET);
6416d528ed9Sopenharmony_ci  target1.public_deps().push_back(LabelTargetPair(&base_target));
6426d528ed9Sopenharmony_ci  target1.SetToolchain(toolchain());
6436d528ed9Sopenharmony_ci  ASSERT_TRUE(target1.OnResolved(&err));
6446d528ed9Sopenharmony_ci  targets.push_back(&target1);
6456d528ed9Sopenharmony_ci
6466d528ed9Sopenharmony_ci  Target target2(settings(), Label(SourceDir("//foo/"), "bar2"));
6476d528ed9Sopenharmony_ci  target2.set_output_type(Target::SOURCE_SET);
6486d528ed9Sopenharmony_ci  target2.public_deps().push_back(LabelTargetPair(&base_i18n));
6496d528ed9Sopenharmony_ci  target2.SetToolchain(toolchain());
6506d528ed9Sopenharmony_ci  ASSERT_TRUE(target2.OnResolved(&err));
6516d528ed9Sopenharmony_ci  targets.push_back(&target2);
6526d528ed9Sopenharmony_ci
6536d528ed9Sopenharmony_ci  Target random_target(settings(), Label(SourceDir("//random/"), "random"));
6546d528ed9Sopenharmony_ci  random_target.set_output_type(Target::SOURCE_SET);
6556d528ed9Sopenharmony_ci  random_target.SetToolchain(toolchain());
6566d528ed9Sopenharmony_ci  ASSERT_TRUE(random_target.OnResolved(&err));
6576d528ed9Sopenharmony_ci  targets.push_back(&random_target);
6586d528ed9Sopenharmony_ci
6596d528ed9Sopenharmony_ci  // Collect everything, the result should match the input.
6606d528ed9Sopenharmony_ci  const std::string source_root("/home/me/build/");
6616d528ed9Sopenharmony_ci  LabelPattern wildcard_pattern = LabelPattern::GetPattern(
6626d528ed9Sopenharmony_ci      SourceDir(), source_root, Value(nullptr, "//*"), &err);
6636d528ed9Sopenharmony_ci  ASSERT_FALSE(err.has_error());
6646d528ed9Sopenharmony_ci  std::vector<const Target*> output = CompileCommandsWriter::CollectTargets(
6656d528ed9Sopenharmony_ci      build_settings(), targets, std::vector<LabelPattern>{wildcard_pattern},
6666d528ed9Sopenharmony_ci      std::nullopt, &err);
6676d528ed9Sopenharmony_ci  EXPECT_TRUE(VectorsEqual(output, targets));
6686d528ed9Sopenharmony_ci
6696d528ed9Sopenharmony_ci  // Collect nothing.
6706d528ed9Sopenharmony_ci  output = CompileCommandsWriter::CollectTargets(build_settings(), targets,
6716d528ed9Sopenharmony_ci                                                 std::vector<LabelPattern>(),
6726d528ed9Sopenharmony_ci                                                 std::nullopt, &err);
6736d528ed9Sopenharmony_ci  EXPECT_TRUE(output.empty());
6746d528ed9Sopenharmony_ci
6756d528ed9Sopenharmony_ci  // Collect all deps of "//foo/*".
6766d528ed9Sopenharmony_ci  LabelPattern foo_wildcard = LabelPattern::GetPattern(
6776d528ed9Sopenharmony_ci      SourceDir(), source_root, Value(nullptr, "//foo/*"), &err);
6786d528ed9Sopenharmony_ci  ASSERT_FALSE(err.has_error());
6796d528ed9Sopenharmony_ci  output = CompileCommandsWriter::CollectTargets(
6806d528ed9Sopenharmony_ci      build_settings(), targets, std::vector<LabelPattern>{foo_wildcard},
6816d528ed9Sopenharmony_ci      std::nullopt, &err);
6826d528ed9Sopenharmony_ci
6836d528ed9Sopenharmony_ci  // The result should be everything except "random".
6846d528ed9Sopenharmony_ci  std::sort(output.begin(), output.end(), &CompareLabel);
6856d528ed9Sopenharmony_ci  ASSERT_EQ(5u, output.size());
6866d528ed9Sopenharmony_ci  EXPECT_EQ(&base_target, output[0]);
6876d528ed9Sopenharmony_ci  EXPECT_EQ(&base_i18n, output[1]);
6886d528ed9Sopenharmony_ci  EXPECT_EQ(&target1, output[2]);
6896d528ed9Sopenharmony_ci  EXPECT_EQ(&target2, output[3]);
6906d528ed9Sopenharmony_ci  EXPECT_EQ(&icu_target, output[4]);
6916d528ed9Sopenharmony_ci
6926d528ed9Sopenharmony_ci  // Collect everything using the legacy filter (present string but empty).
6936d528ed9Sopenharmony_ci  output = CompileCommandsWriter::CollectTargets(build_settings(), targets,
6946d528ed9Sopenharmony_ci                                                 std::vector<LabelPattern>{},
6956d528ed9Sopenharmony_ci                                                 std::string(), &err);
6966d528ed9Sopenharmony_ci  EXPECT_TRUE(VectorsEqual(output, targets));
6976d528ed9Sopenharmony_ci
6986d528ed9Sopenharmony_ci  // Collect all deps of "bar2" using the legacy filter.
6996d528ed9Sopenharmony_ci  output = CompileCommandsWriter::CollectTargets(build_settings(), targets,
7006d528ed9Sopenharmony_ci                                                 std::vector<LabelPattern>{},
7016d528ed9Sopenharmony_ci                                                 std::string("bar2"), &err);
7026d528ed9Sopenharmony_ci  std::sort(output.begin(), output.end(), &CompareLabel);
7036d528ed9Sopenharmony_ci  ASSERT_EQ(4u, output.size());
7046d528ed9Sopenharmony_ci  EXPECT_EQ(&base_target, output[0]);
7056d528ed9Sopenharmony_ci  EXPECT_EQ(&base_i18n, output[1]);
7066d528ed9Sopenharmony_ci  EXPECT_EQ(&target2, output[2]);
7076d528ed9Sopenharmony_ci  EXPECT_EQ(&icu_target, output[3]);
7086d528ed9Sopenharmony_ci
7096d528ed9Sopenharmony_ci  // Collect all deps of "bar1" and "bar2" using the legacy filter.
7106d528ed9Sopenharmony_ci  output = CompileCommandsWriter::CollectTargets(
7116d528ed9Sopenharmony_ci      build_settings(), targets, std::vector<LabelPattern>{},
7126d528ed9Sopenharmony_ci      std::string("bar2,bar1"), &err);
7136d528ed9Sopenharmony_ci  std::sort(output.begin(), output.end(), &CompareLabel);
7146d528ed9Sopenharmony_ci  ASSERT_EQ(5u, output.size());
7156d528ed9Sopenharmony_ci  EXPECT_EQ(&base_target, output[0]);
7166d528ed9Sopenharmony_ci  EXPECT_EQ(&base_i18n, output[1]);
7176d528ed9Sopenharmony_ci  EXPECT_EQ(&target1, output[2]);
7186d528ed9Sopenharmony_ci  EXPECT_EQ(&target2, output[3]);
7196d528ed9Sopenharmony_ci  EXPECT_EQ(&icu_target, output[4]);
7206d528ed9Sopenharmony_ci
7216d528ed9Sopenharmony_ci  // Combine the legacy (bar1) and pattern (bar2) filters, we should get the
7226d528ed9Sopenharmony_ci  // union.
7236d528ed9Sopenharmony_ci  LabelPattern foo_bar2 = LabelPattern::GetPattern(
7246d528ed9Sopenharmony_ci      SourceDir(), source_root, Value(nullptr, "//foo:bar2"), &err);
7256d528ed9Sopenharmony_ci  ASSERT_FALSE(err.has_error());
7266d528ed9Sopenharmony_ci  output = CompileCommandsWriter::CollectTargets(
7276d528ed9Sopenharmony_ci      build_settings(), targets, std::vector<LabelPattern>{foo_bar2},
7286d528ed9Sopenharmony_ci      std::string("bar1"), &err);
7296d528ed9Sopenharmony_ci  std::sort(output.begin(), output.end(), &CompareLabel);
7306d528ed9Sopenharmony_ci  ASSERT_EQ(5u, output.size());
7316d528ed9Sopenharmony_ci  EXPECT_EQ(&base_target, output[0]);
7326d528ed9Sopenharmony_ci  EXPECT_EQ(&base_i18n, output[1]);
7336d528ed9Sopenharmony_ci  EXPECT_EQ(&target1, output[2]);
7346d528ed9Sopenharmony_ci  EXPECT_EQ(&target2, output[3]);
7356d528ed9Sopenharmony_ci  EXPECT_EQ(&icu_target, output[4]);
7366d528ed9Sopenharmony_ci}
737