blob: 29e6a573699cb91cd48a501e93b4d9b83591a4f0 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gn/compile_commands_writer.h"
#include <memory>
#include <sstream>
#include <utility>
#include "gn/config.h"
#include "gn/ninja_target_command_util.h"
#include "gn/scheduler.h"
#include "gn/target.h"
#include "gn/test_with_scheduler.h"
#include "gn/test_with_scope.h"
#include "util/build_config.h"
#include "util/test/test.h"
namespace {
// InputConversion needs a global scheduler object.
class CompileCommandsTest : public TestWithScheduler {
public:
CompileCommandsTest() = default;
const BuildSettings* build_settings() { return setup_.build_settings(); }
const Settings* settings() { return setup_.settings(); }
const TestWithScope& setup() { return setup_; }
const Toolchain* toolchain() { return setup_.toolchain(); }
private:
TestWithScope setup_;
};
} // namespace
TEST_F(CompileCommandsTest, SourceSet) {
Err err;
std::vector<const Target*> targets;
Target target(settings(), Label(SourceDir("//foo/"), "bar"));
target.set_output_type(Target::SOURCE_SET);
target.visibility().SetPublic();
target.sources().push_back(SourceFile("//foo/input1.cc"));
target.sources().push_back(SourceFile("//foo/input2.cc"));
// Also test object files, which should be just passed through to the
// dependents to link.
target.sources().push_back(SourceFile("//foo/input3.o"));
target.sources().push_back(SourceFile("//foo/input4.obj"));
target.SetToolchain(toolchain());
ASSERT_TRUE(target.OnResolved(&err));
targets.push_back(&target);
// Source set itself.
{
CompileCommandsWriter writer;
std::string out = writer.RenderJSON(build_settings(), targets);
#if defined(OS_WIN)
const char expected[] =
"[\r\n"
" {\r\n"
" \"file\": \"../../foo/input1.cc\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"c++ ../../foo/input1.cc -o "
"obj/foo/bar.input1.o\"\r\n"
" },\r\n"
" {\r\n"
" \"file\": \"../../foo/input2.cc\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"c++ ../../foo/input2.cc -o "
"obj/foo/bar.input2.o\"\r\n"
" }\r\n"
"]\r\n";
#else
const char expected[] =
"[\n"
" {\n"
" \"file\": \"../../foo/input1.cc\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"c++ ../../foo/input1.cc -o "
"obj/foo/bar.input1.o\"\n"
" },\n"
" {\n"
" \"file\": \"../../foo/input2.cc\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"c++ ../../foo/input2.cc -o "
"obj/foo/bar.input2.o\"\n"
" }\n"
"]\n";
#endif
EXPECT_EQ(expected, out);
}
// A shared library that depends on the source set.
Target shlib_target(settings(), Label(SourceDir("//foo/"), "shlib"));
shlib_target.sources().push_back(SourceFile("//foo/input3.cc"));
shlib_target.set_output_type(Target::SHARED_LIBRARY);
shlib_target.public_deps().push_back(LabelTargetPair(&target));
shlib_target.SetToolchain(toolchain());
ASSERT_TRUE(shlib_target.OnResolved(&err));
targets.push_back(&shlib_target);
{
CompileCommandsWriter writer;
std::string out = writer.RenderJSON(build_settings(), targets);
#if defined(OS_WIN)
const char expected[] =
"[\r\n"
" {\r\n"
" \"file\": \"../../foo/input1.cc\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"c++ ../../foo/input1.cc -o "
"obj/foo/bar.input1.o\"\r\n"
" },\r\n"
" {\r\n"
" \"file\": \"../../foo/input2.cc\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"c++ ../../foo/input2.cc -o "
"obj/foo/bar.input2.o\"\r\n"
" },\r\n"
" {\r\n"
" \"file\": \"../../foo/input3.cc\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"c++ ../../foo/input3.cc -o "
"obj/foo/libshlib.input3.o\"\r\n"
" }\r\n"
"]\r\n";
#else
const char expected[] =
"[\n"
" {\n"
" \"file\": \"../../foo/input1.cc\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"c++ ../../foo/input1.cc -o "
"obj/foo/bar.input1.o\"\n"
" },\n"
" {\n"
" \"file\": \"../../foo/input2.cc\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"c++ ../../foo/input2.cc -o "
"obj/foo/bar.input2.o\"\n"
" },\n"
" {\n"
" \"file\": \"../../foo/input3.cc\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"c++ ../../foo/input3.cc -o "
"obj/foo/libshlib.input3.o\"\n"
" }\n"
"]\n";
#endif
EXPECT_EQ(expected, out);
}
// A static library that depends on the source set (should not link it).
Target stlib_target(settings(), Label(SourceDir("//foo/"), "stlib"));
stlib_target.sources().push_back(SourceFile("//foo/input4.cc"));
stlib_target.set_output_type(Target::STATIC_LIBRARY);
stlib_target.public_deps().push_back(LabelTargetPair(&target));
stlib_target.SetToolchain(toolchain());
ASSERT_TRUE(stlib_target.OnResolved(&err));
targets.push_back(&stlib_target);
{
CompileCommandsWriter writer;
std::string out = writer.RenderJSON(build_settings(), targets);
#if defined(OS_WIN)
const char expected[] =
"[\r\n"
" {\r\n"
" \"file\": \"../../foo/input1.cc\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"c++ ../../foo/input1.cc -o "
"obj/foo/bar.input1.o\"\r\n"
" },\r\n"
" {\r\n"
" \"file\": \"../../foo/input2.cc\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"c++ ../../foo/input2.cc -o "
"obj/foo/bar.input2.o\"\r\n"
" },\r\n"
" {\r\n"
" \"file\": \"../../foo/input3.cc\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"c++ ../../foo/input3.cc -o "
"obj/foo/libshlib.input3.o\"\r\n"
" },\r\n"
" {\r\n"
" \"file\": \"../../foo/input4.cc\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"c++ ../../foo/input4.cc -o "
"obj/foo/libstlib.input4.o\"\r\n"
" }\r\n"
"]\r\n";
#else
const char expected[] =
"[\n"
" {\n"
" \"file\": \"../../foo/input1.cc\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"c++ ../../foo/input1.cc -o "
"obj/foo/bar.input1.o\"\n"
" },\n"
" {\n"
" \"file\": \"../../foo/input2.cc\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"c++ ../../foo/input2.cc -o "
"obj/foo/bar.input2.o\"\n"
" },\n"
" {\n"
" \"file\": \"../../foo/input3.cc\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"c++ ../../foo/input3.cc -o "
"obj/foo/libshlib.input3.o\"\n"
" },\n"
" {\n"
" \"file\": \"../../foo/input4.cc\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"c++ ../../foo/input4.cc -o "
"obj/foo/libstlib.input4.o\"\n"
" }\n"
"]\n";
#endif
EXPECT_EQ(expected, out);
}
}
TEST_F(CompileCommandsTest, EscapeDefines) {
Err err;
std::vector<const Target*> targets;
TestTarget target(setup(), "//foo:bar", Target::STATIC_LIBRARY);
target.sources().push_back(SourceFile("//foo/input.cc"));
target.config_values().defines().push_back("BOOL_DEF");
target.config_values().defines().push_back("INT_DEF=123");
target.config_values().defines().push_back("STR_DEF=\"ABCD 1\"");
target.config_values().defines().push_back("INCLUDE=<header.h>");
ASSERT_TRUE(target.OnResolved(&err));
targets.push_back(&target);
CompileCommandsWriter writer;
std::string out = writer.RenderJSON(build_settings(), targets);
const char expected[] =
"-DBOOL_DEF -DINT_DEF=123 \\\"-DSTR_DEF=\\\\\\\"ABCD 1\\\\\\\"\\\" "
"\\\"-DINCLUDE=\\u003Cheader.h>\\\"";
EXPECT_TRUE(out.find(expected) != std::string::npos);
}
TEST_F(CompileCommandsTest, WinPrecompiledHeaders) {
Err err;
// This setup's toolchain does not have precompiled headers defined.
// A precompiled header toolchain.
Settings pch_settings(build_settings(), "withpch/");
Toolchain pch_toolchain(&pch_settings,
Label(SourceDir("//toolchain/"), "withpch"));
pch_settings.set_toolchain_label(pch_toolchain.label());
pch_settings.set_default_toolchain_label(toolchain()->label());
// Declare a C++ compiler that supports PCH.
std::unique_ptr<Tool> cxx = Tool::CreateTool(CTool::kCToolCxx);
CTool* cxx_tool = cxx->AsC();
TestWithScope::SetCommandForTool(
"c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} "
"-o {{output}}",
cxx_tool);
cxx_tool->set_outputs(SubstitutionList::MakeForTest(
"{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
cxx_tool->set_precompiled_header_type(CTool::PCH_MSVC);
pch_toolchain.SetTool(std::move(cxx));
// Add a C compiler as well.
std::unique_ptr<Tool> cc = Tool::CreateTool(CTool::kCToolCc);
CTool* cc_tool = cc->AsC();
TestWithScope::SetCommandForTool(
"cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} "
"-o {{output}}",
cc_tool);
cc_tool->set_outputs(SubstitutionList::MakeForTest(
"{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
cc_tool->set_precompiled_header_type(CTool::PCH_MSVC);
pch_toolchain.SetTool(std::move(cc));
pch_toolchain.ToolchainSetupComplete();
// This target doesn't specify precompiled headers.
{
std::vector<const Target*> targets;
Target no_pch_target(&pch_settings,
Label(SourceDir("//foo/"), "no_pch_target"));
no_pch_target.set_output_type(Target::SOURCE_SET);
no_pch_target.visibility().SetPublic();
no_pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
no_pch_target.sources().push_back(SourceFile("//foo/input2.c"));
no_pch_target.config_values().cflags_c().push_back("-std=c99");
no_pch_target.SetToolchain(&pch_toolchain);
ASSERT_TRUE(no_pch_target.OnResolved(&err));
targets.push_back(&no_pch_target);
CompileCommandsWriter writer;
std::string out = writer.RenderJSON(build_settings(), targets);
#if defined(OS_WIN)
const char no_pch_expected[] =
"[\r\n"
" {\r\n"
" \"file\": \"../../foo/input1.cc\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"c++ ../../foo/input1.cc -o "
"withpch/obj/foo/no_pch_target.input1.o\"\r\n"
" },\r\n"
" {\r\n"
" \"file\": \"../../foo/input2.c\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"cc ../../foo/input2.c -std=c99 -o "
"withpch/obj/foo/no_pch_target.input2.o\"\r\n"
" }\r\n"
"]\r\n";
#else
const char no_pch_expected[] =
"[\n"
" {\n"
" \"file\": \"../../foo/input1.cc\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"c++ ../../foo/input1.cc -o "
"withpch/obj/foo/no_pch_target.input1.o\"\n"
" },\n"
" {\n"
" \"file\": \"../../foo/input2.c\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"cc ../../foo/input2.c -std=c99 -o "
"withpch/obj/foo/no_pch_target.input2.o\"\n"
" }\n"
"]\n";
#endif
EXPECT_EQ(no_pch_expected, out);
}
// This target specifies PCH.
{
std::vector<const Target*> targets;
Target pch_target(&pch_settings, Label(SourceDir("//foo/"), "pch_target"));
pch_target.config_values().set_precompiled_header("build/precompile.h");
pch_target.config_values().set_precompiled_source(
SourceFile("//build/precompile.cc"));
pch_target.set_output_type(Target::SOURCE_SET);
pch_target.visibility().SetPublic();
pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
pch_target.sources().push_back(SourceFile("//foo/input2.c"));
pch_target.SetToolchain(&pch_toolchain);
ASSERT_TRUE(pch_target.OnResolved(&err));
targets.push_back(&pch_target);
CompileCommandsWriter writer;
std::string out = writer.RenderJSON(build_settings(), targets);
#if defined(OS_WIN)
const char pch_win_expected[] =
"[\r\n"
" {\r\n"
" \"file\": \"../../foo/input1.cc\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"c++ ../../foo/input1.cc "
"/Fpwithpch/obj/foo/pch_target_cc.pch /Yubuild/precompile.h -o "
"withpch/obj/foo/pch_target.input1.o\"\r\n"
" },\r\n"
" {\r\n"
" \"file\": \"../../foo/input2.c\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"cc ../../foo/input2.c "
"/Fpwithpch/obj/foo/pch_target_c.pch /Yubuild/precompile.h -o "
"withpch/obj/foo/pch_target.input2.o\"\r\n"
" }\r\n"
"]\r\n";
#else
const char pch_win_expected[] =
"[\n"
" {\n"
" \"file\": \"../../foo/input1.cc\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"c++ ../../foo/input1.cc "
"/Fpwithpch/obj/foo/pch_target_cc.pch /Yubuild/precompile.h -o "
"withpch/obj/foo/pch_target.input1.o\"\n"
" },\n"
" {\n"
" \"file\": \"../../foo/input2.c\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"cc ../../foo/input2.c "
"/Fpwithpch/obj/foo/pch_target_c.pch /Yubuild/precompile.h -o "
"withpch/obj/foo/pch_target.input2.o\"\n"
" }\n"
"]\n";
#endif
EXPECT_EQ(pch_win_expected, out);
}
}
TEST_F(CompileCommandsTest, GCCPrecompiledHeaders) {
Err err;
// This setup's toolchain does not have precompiled headers defined.
// A precompiled header toolchain.
Settings pch_settings(build_settings(), "withpch/");
Toolchain pch_toolchain(&pch_settings,
Label(SourceDir("//toolchain/"), "withpch"));
pch_settings.set_toolchain_label(pch_toolchain.label());
pch_settings.set_default_toolchain_label(toolchain()->label());
// Declare a C++ compiler that supports PCH.
std::unique_ptr<Tool> cxx = Tool::CreateTool(CTool::kCToolCxx);
CTool* cxx_tool = cxx->AsC();
TestWithScope::SetCommandForTool(
"c++ {{source}} {{cflags}} {{cflags_cc}} {{defines}} {{include_dirs}} "
"-o {{output}}",
cxx_tool);
cxx_tool->set_outputs(SubstitutionList::MakeForTest(
"{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
cxx_tool->set_precompiled_header_type(CTool::PCH_GCC);
pch_toolchain.SetTool(std::move(cxx));
pch_toolchain.ToolchainSetupComplete();
// Add a C compiler as well.
std::unique_ptr<Tool> cc = Tool::CreateTool(CTool::kCToolCc);
CTool* cc_tool = cc->AsC();
TestWithScope::SetCommandForTool(
"cc {{source}} {{cflags}} {{cflags_c}} {{defines}} {{include_dirs}} "
"-o {{output}}",
cc_tool);
cc_tool->set_outputs(SubstitutionList::MakeForTest(
"{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o"));
cc_tool->set_precompiled_header_type(CTool::PCH_GCC);
pch_toolchain.SetTool(std::move(cc));
pch_toolchain.ToolchainSetupComplete();
// This target doesn't specify precompiled headers.
{
std::vector<const Target*> targets;
Target no_pch_target(&pch_settings,
Label(SourceDir("//foo/"), "no_pch_target"));
no_pch_target.set_output_type(Target::SOURCE_SET);
no_pch_target.visibility().SetPublic();
no_pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
no_pch_target.sources().push_back(SourceFile("//foo/input2.c"));
no_pch_target.config_values().cflags_c().push_back("-std=c99");
no_pch_target.SetToolchain(&pch_toolchain);
ASSERT_TRUE(no_pch_target.OnResolved(&err));
targets.push_back(&no_pch_target);
CompileCommandsWriter writer;
std::string out = writer.RenderJSON(build_settings(), targets);
#if defined(OS_WIN)
const char no_pch_expected[] =
"[\r\n"
" {\r\n"
" \"file\": \"../../foo/input1.cc\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"c++ ../../foo/input1.cc -o "
"withpch/obj/foo/no_pch_target.input1.o\"\r\n"
" },\r\n"
" {\r\n"
" \"file\": \"../../foo/input2.c\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"cc ../../foo/input2.c -std=c99 -o "
"withpch/obj/foo/no_pch_target.input2.o\"\r\n"
" }\r\n"
"]\r\n";
#else
const char no_pch_expected[] =
"[\n"
" {\n"
" \"file\": \"../../foo/input1.cc\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"c++ ../../foo/input1.cc -o "
"withpch/obj/foo/no_pch_target.input1.o\"\n"
" },\n"
" {\n"
" \"file\": \"../../foo/input2.c\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"cc ../../foo/input2.c -std=c99 -o "
"withpch/obj/foo/no_pch_target.input2.o\"\n"
" }\n"
"]\n";
#endif
EXPECT_EQ(no_pch_expected, out);
}
// This target specifies PCH.
{
std::vector<const Target*> targets;
Target pch_target(&pch_settings, Label(SourceDir("//foo/"), "pch_target"));
pch_target.config_values().set_precompiled_source(
SourceFile("//build/precompile.h"));
pch_target.config_values().cflags_c().push_back("-std=c99");
pch_target.set_output_type(Target::SOURCE_SET);
pch_target.visibility().SetPublic();
pch_target.sources().push_back(SourceFile("//foo/input1.cc"));
pch_target.sources().push_back(SourceFile("//foo/input2.c"));
pch_target.SetToolchain(&pch_toolchain);
ASSERT_TRUE(pch_target.OnResolved(&err));
targets.push_back(&pch_target);
CompileCommandsWriter writer;
std::string out = writer.RenderJSON(build_settings(), targets);
#if defined(OS_WIN)
const char pch_gcc_expected[] =
"[\r\n"
" {\r\n"
" \"file\": \"../../foo/input1.cc\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"c++ ../../foo/input1.cc -include "
"withpch/obj/build/pch_target.precompile.h-cc -o "
"withpch/obj/foo/pch_target.input1.o\"\r\n"
" },\r\n"
" {\r\n"
" \"file\": \"../../foo/input2.c\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"cc ../../foo/input2.c -std=c99 -include "
"withpch/obj/build/pch_target.precompile.h-c -o "
"withpch/obj/foo/pch_target.input2.o\"\r\n"
" }\r\n"
"]\r\n";
#else
const char pch_gcc_expected[] =
"[\n"
" {\n"
" \"file\": \"../../foo/input1.cc\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"c++ ../../foo/input1.cc -include "
"withpch/obj/build/pch_target.precompile.h-cc -o "
"withpch/obj/foo/pch_target.input1.o\"\n"
" },\n"
" {\n"
" \"file\": \"../../foo/input2.c\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"cc ../../foo/input2.c -std=c99 -include "
"withpch/obj/build/pch_target.precompile.h-c -o "
"withpch/obj/foo/pch_target.input2.o\"\n"
" }\n"
"]\n";
#endif
EXPECT_EQ(pch_gcc_expected, out);
}
}
TEST_F(CompileCommandsTest, EscapedFlags) {
Err err;
std::vector<const Target*> targets;
Target target(settings(), Label(SourceDir("//foo/"), "bar"));
target.set_output_type(Target::SOURCE_SET);
target.sources().push_back(SourceFile("//foo/input1.c"));
target.config_values().cflags_c().push_back("-DCONFIG=\"/config\"");
target.SetToolchain(toolchain());
ASSERT_TRUE(target.OnResolved(&err));
targets.push_back(&target);
CompileCommandsWriter writer;
std::string out = writer.RenderJSON(build_settings(), targets);
#if defined(OS_WIN)
const char expected[] =
"[\r\n"
" {\r\n"
" \"file\": \"../../foo/input1.c\",\r\n"
" \"directory\": \"out/Debug\",\r\n"
" \"command\": \"cc ../../foo/input1.c -DCONFIG=\\\"/config\\\" "
"-o obj/foo/bar.input1.o\"\r\n"
" }\r\n"
"]\r\n";
#else
const char expected[] =
"[\n"
" {\n"
" \"file\": \"../../foo/input1.c\",\n"
" \"directory\": \"out/Debug\",\n"
" \"command\": \"cc ../../foo/input1.c -DCONFIG=\\\"/config\\\" "
"-o obj/foo/bar.input1.o\"\n"
" }\n"
"]\n";
#endif
EXPECT_EQ(expected, out);
}
TEST_F(CompileCommandsTest, CompDBFilter) {
Err err;
std::vector<const Target*> targets;
Target target1(settings(), Label(SourceDir("//foo/"), "bar1"));
target1.set_output_type(Target::SOURCE_SET);
target1.sources().push_back(SourceFile("//foo/input1.c"));
target1.config_values().cflags_c().push_back("-DCONFIG=\"/config\"");
target1.SetToolchain(toolchain());
ASSERT_TRUE(target1.OnResolved(&err));
targets.push_back(&target1);
Target target2(settings(), Label(SourceDir("//foo/"), "bar2"));
target2.set_output_type(Target::SOURCE_SET);
target2.sources().push_back(SourceFile("//foo/input2.c"));
target2.config_values().cflags_c().push_back("-DCONFIG=\"/config\"");
target2.SetToolchain(toolchain());
ASSERT_TRUE(target2.OnResolved(&err));
targets.push_back(&target2);
Target target3(settings(), Label(SourceDir("//foo/"), "bar3"));
target3.set_output_type(Target::SOURCE_SET);
target3.sources().push_back(SourceFile("//foo/input3.c"));
target3.config_values().cflags_c().push_back("-DCONFIG=\"/config\"");
target3.SetToolchain(toolchain());
ASSERT_TRUE(target3.OnResolved(&err));
targets.push_back(&target3);
target1.private_deps().push_back(LabelTargetPair(&target2));
target1.private_deps().push_back(LabelTargetPair(&target3));
CompileCommandsWriter writer;
std::set<std::string> filter1;
std::vector<const Target*> test_results1 =
writer.FilterTargets(targets, filter1);
ASSERT_TRUE(test_results1.empty());
std::set<std::string> filter2;
filter2.insert(target1.label().name());
std::vector<const Target*> test_results2 =
writer.FilterTargets(targets, filter2);
ASSERT_EQ(test_results2, targets);
std::set<std::string> filter3;
filter3.insert(target2.label().name());
std::vector<const Target*> test_result3 =
writer.FilterTargets(targets, filter3);
std::vector<const Target*> expected_results3;
expected_results3.push_back(&target2);
ASSERT_EQ(test_result3, expected_results3);
}