#include "gn/target.h"
#include <memory>
#include <utility>
#include "gn/build_settings.h"
#include "gn/config.h"
#include "gn/resolved_target_data.h"
#include "gn/scheduler.h"
#include "gn/settings.h"
#include "gn/test_with_scheduler.h"
#include "gn/test_with_scope.h"
#include "gn/toolchain.h"
#include "util/test/test.h"
namespace {
void AssertSchedulerHasOneUnknownFileMatching(const Target* target,
const SourceFile& file) {
auto unknown = g_scheduler->GetUnknownGeneratedInputs();
ASSERT_EQ(1u, unknown.size());
auto found = unknown.find(file);
ASSERT_TRUE(found != unknown.end()) << file.value();
EXPECT_TRUE(target == found->second)
<< "Target doesn't match. Expected\n "
<< target->label().GetUserVisibleName(false) << "\nBut got\n "
<< found->second->label().GetUserVisibleName(false);
}
}
using TargetTest = TestWithScheduler;
TEST_F(TargetTest, DependentConfigs) {
TestWithScope setup;
Err err;
TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
TestTarget b(setup, "//foo:b", Target::STATIC_LIBRARY);
TestTarget c(setup, "//foo:c", Target::STATIC_LIBRARY);
a.private_deps().push_back(LabelTargetPair(&b));
b.private_deps().push_back(LabelTargetPair(&c));
Config config(setup.settings(), Label(SourceDir("//foo/"), "config"));
config.visibility().SetPublic();
ASSERT_TRUE(config.OnResolved(&err));
c.configs().push_back(LabelConfigPair(&config));
Config all(setup.settings(), Label(SourceDir("//foo/"), "all"));
all.visibility().SetPublic();
ASSERT_TRUE(all.OnResolved(&err));
c.all_dependent_configs().push_back(LabelConfigPair(&all));
Config direct(setup.settings(), Label(SourceDir("//foo/"), "direct"));
direct.visibility().SetPublic();
ASSERT_TRUE(direct.OnResolved(&err));
c.public_configs().push_back(LabelConfigPair(&direct));
ASSERT_TRUE(c.OnResolved(&err));
ASSERT_TRUE(b.OnResolved(&err));
ASSERT_TRUE(a.OnResolved(&err));
ASSERT_EQ(2u, b.configs().size());
EXPECT_EQ(&all, b.configs()[0].ptr);
EXPECT_EQ(&direct, b.configs()[1].ptr);
ASSERT_EQ(1u, b.all_dependent_configs().size());
EXPECT_EQ(&all, b.all_dependent_configs()[0].ptr);
ASSERT_EQ(1u, a.configs().size());
EXPECT_EQ(&all, a.configs()[0].ptr);
EXPECT_EQ(&all, a.all_dependent_configs()[0].ptr);
TestTarget a_fwd(setup, "//foo:a_fwd", Target::EXECUTABLE);
TestTarget b_fwd(setup, "//foo:b_fwd", Target::STATIC_LIBRARY);
a_fwd.private_deps().push_back(LabelTargetPair(&b_fwd));
b_fwd.private_deps().push_back(LabelTargetPair(&c));
ASSERT_TRUE(b_fwd.OnResolved(&err));
ASSERT_TRUE(a_fwd.OnResolved(&err));
ASSERT_EQ(1u, a_fwd.configs().size());
EXPECT_EQ(&all, a_fwd.configs()[0].ptr);
ASSERT_EQ(1u, a_fwd.all_dependent_configs().size());
EXPECT_EQ(&all, a_fwd.all_dependent_configs()[0].ptr);
}
TEST_F(TargetTest, NoDependentConfigsBetweenToolchains) {
TestWithScope setup;
Err err;
Toolchain other_toolchain(setup.settings(),
Label(SourceDir("//other/"), "toolchain"));
TestWithScope::SetupToolchain(&other_toolchain);
Target a(setup.settings(),
Label(SourceDir("//foo/"), "a", other_toolchain.label().dir(),
other_toolchain.label().name()));
a.set_output_type(Target::EXECUTABLE);
EXPECT_TRUE(a.SetToolchain(&other_toolchain, &err));
TestTarget b(setup, "//foo:b", Target::EXECUTABLE);
TestTarget c(setup, "//foo:c", Target::SOURCE_SET);
a.private_deps().push_back(LabelTargetPair(&b));
b.private_deps().push_back(LabelTargetPair(&c));
Config all_dependent(setup.settings(), Label(SourceDir("//foo/"), "all"));
all_dependent.visibility().SetPublic();
ASSERT_TRUE(all_dependent.OnResolved(&err));
c.all_dependent_configs().push_back(LabelConfigPair(&all_dependent));
Config public_config(setup.settings(), Label(SourceDir("//foo/"), "public"));
public_config.visibility().SetPublic();
ASSERT_TRUE(public_config.OnResolved(&err));
c.public_configs().push_back(LabelConfigPair(&public_config));
Config public_config2(setup.settings(),
Label(SourceDir("//foo/"), "public2"));
public_config2.visibility().SetPublic();
ASSERT_TRUE(public_config2.OnResolved(&err));
b.public_configs().push_back(LabelConfigPair(&public_config2));
ASSERT_TRUE(c.OnResolved(&err));
ASSERT_TRUE(b.OnResolved(&err));
ASSERT_TRUE(a.OnResolved(&err));
ASSERT_EQ(3u, b.configs().size());
EXPECT_EQ(&public_config2, b.configs()[0].ptr);
EXPECT_EQ(&all_dependent, b.configs()[1].ptr);
EXPECT_EQ(&public_config, b.configs()[2].ptr);
ASSERT_EQ(1u, b.all_dependent_configs().size());
EXPECT_EQ(&all_dependent, b.all_dependent_configs()[0].ptr);
ASSERT_EQ(0u, a.configs().size());
ASSERT_EQ(0u, a.all_dependent_configs().size());
}
TEST_F(TargetTest, DependentConfigsBetweenToolchainsWhenSet) {
TestWithScope setup;
Err err;
Toolchain other_toolchain(setup.settings(),
Label(SourceDir("//other/"), "toolchain"));
TestWithScope::SetupToolchain(&other_toolchain);
other_toolchain.set_propagates_configs(true);
TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
Target b(setup.settings(),
Label(SourceDir("//foo/"), "b", other_toolchain.label().dir(),
other_toolchain.label().name()));
b.visibility().SetPublic();
b.set_output_type(Target::SHARED_LIBRARY);
EXPECT_TRUE(b.SetToolchain(&other_toolchain, &err));
a.private_deps().push_back(LabelTargetPair(&b));
Config all_dependent(setup.settings(), Label(SourceDir("//foo/"), "all"));
all_dependent.visibility().SetPublic();
ASSERT_TRUE(all_dependent.OnResolved(&err));
b.all_dependent_configs().push_back(LabelConfigPair(&all_dependent));
Config public_config(setup.settings(), Label(SourceDir("//foo/"), "public"));
public_config.visibility().SetPublic();
ASSERT_TRUE(public_config.OnResolved(&err));
b.public_configs().push_back(LabelConfigPair(&public_config));
ASSERT_TRUE(b.OnResolved(&err));
ASSERT_TRUE(a.OnResolved(&err));
ASSERT_EQ(2u, a.configs().size());
EXPECT_EQ(&all_dependent, a.configs()[0].ptr);
EXPECT_EQ(&public_config, a.configs()[1].ptr);
ASSERT_EQ(1u, a.all_dependent_configs().size());
EXPECT_EQ(&all_dependent, a.all_dependent_configs()[0].ptr);
}
TEST_F(TargetTest, GetComputedOutputName) {
TestWithScope setup;
Err err;
TestTarget basic(setup, "//foo:bar", Target::EXECUTABLE);
ASSERT_TRUE(basic.OnResolved(&err));
EXPECT_EQ("bar", basic.GetComputedOutputName());
TestTarget with_name(setup, "//foo:bar", Target::EXECUTABLE);
with_name.set_output_name("myoutput");
ASSERT_TRUE(with_name.OnResolved(&err));
EXPECT_EQ("myoutput", with_name.GetComputedOutputName());
TestTarget with_prefix(setup, "//foo:bar", Target::STATIC_LIBRARY);
ASSERT_TRUE(with_prefix.OnResolved(&err));
EXPECT_EQ("libbar", with_prefix.GetComputedOutputName());
TestTarget dup_prefix(setup, "//foo:bar", Target::STATIC_LIBRARY);
dup_prefix.set_output_name("libbar");
ASSERT_TRUE(dup_prefix.OnResolved(&err));
EXPECT_EQ("libbar", dup_prefix.GetComputedOutputName());
TestTarget override_prefix(setup, "//foo:bar", Target::SHARED_LIBRARY);
override_prefix.set_output_prefix_override(true);
ASSERT_TRUE(dup_prefix.OnResolved(&err));
EXPECT_EQ("bar", override_prefix.GetComputedOutputName());
}
TEST_F(TargetTest, VisibilityFails) {
TestWithScope setup;
Err err;
TestTarget b(setup, "//private:b", Target::STATIC_LIBRARY);
b.visibility().SetPrivate(b.label().dir());
ASSERT_TRUE(b.OnResolved(&err));
TestTarget a(setup, "//app:a", Target::EXECUTABLE);
a.private_deps().push_back(LabelTargetPair(&b));
IdentifierNode origin;
a.private_deps()[0].origin = &origin;
ASSERT_FALSE(a.OnResolved(&err));
}
TEST_F(TargetTest, VisibilityConfigFails) {
TestWithScope setup;
Err err;
Label config_label(SourceDir("//a/"), "config");
Config config(setup.settings(), config_label);
config.visibility().SetPrivate(config.label().dir());
ASSERT_TRUE(config.OnResolved(&err));
TestTarget a(setup, "//app:a", Target::EXECUTABLE);
a.configs().push_back(LabelConfigPair(&config));
ASSERT_FALSE(a.OnResolved(&err));
TestTarget b(setup, "//app:b", Target::EXECUTABLE);
b.public_configs().push_back(LabelConfigPair(&config));
ASSERT_FALSE(b.OnResolved(&err));
TestTarget c(setup, "//app:c", Target::EXECUTABLE);
c.all_dependent_configs().push_back(LabelConfigPair(&config));
ASSERT_FALSE(c.OnResolved(&err));
}
TEST_F(TargetTest, VisibilityConfigGroup) {
TestWithScope setup;
Err err;
Label config_label(SourceDir("//a/"), "config");
Config config(setup.settings(), config_label);
config.visibility().SetPrivate(config.label().dir());
ASSERT_TRUE(config.OnResolved(&err));
TestTarget a(setup, "//a:a", Target::GROUP);
a.public_configs().push_back(LabelConfigPair(&config));
ASSERT_TRUE(a.OnResolved(&err));
TestTarget b(setup, "//app:b", Target::EXECUTABLE);
b.private_deps().push_back(LabelTargetPair(&a));
ASSERT_TRUE(b.OnResolved(&err));
}
TEST_F(TargetTest, VisibilityDatadeps) {
TestWithScope setup;
Err err;
TestTarget b(setup, "//public:b", Target::STATIC_LIBRARY);
ASSERT_TRUE(b.OnResolved(&err));
TestTarget a(setup, "//app:a", Target::EXECUTABLE);
a.data_deps().push_back(LabelTargetPair(&b));
IdentifierNode origin;
a.data_deps()[0].origin = &origin;
ASSERT_TRUE(a.OnResolved(&err)) << err.help_text();
}
TEST_F(TargetTest, VisibilityGroup) {
TestWithScope setup;
Err err;
IdentifierNode origin;
TestTarget b(setup, "//private:b", Target::STATIC_LIBRARY);
b.visibility().SetPrivate(b.label().dir());
ASSERT_TRUE(b.OnResolved(&err));
TestTarget g(setup, "//public:g", Target::GROUP);
g.private_deps().push_back(LabelTargetPair(&b));
g.private_deps()[0].origin = &origin;
ASSERT_TRUE(b.OnResolved(&err));
TestTarget a(setup, "//app:a", Target::EXECUTABLE);
a.private_deps().push_back(LabelTargetPair(&g));
a.private_deps()[0].origin = &origin;
ASSERT_TRUE(a.OnResolved(&err));
}
TEST_F(TargetTest, Testonly) {
TestWithScope setup;
Err err;
TestTarget testlib(setup, "//test:testlib", Target::STATIC_LIBRARY);
testlib.set_testonly(true);
ASSERT_TRUE(testlib.OnResolved(&err));
TestTarget test(setup, "//test:test", Target::EXECUTABLE);
test.set_testonly(true);
test.private_deps().push_back(LabelTargetPair(&testlib));
ASSERT_TRUE(test.OnResolved(&err));
TestTarget product(setup, "//app:product", Target::EXECUTABLE);
product.set_testonly(false);
product.private_deps().push_back(LabelTargetPair(&testlib));
ASSERT_FALSE(product.OnResolved(&err));
}
TEST_F(TargetTest, TestonlyConfig) {
TestWithScope setup;
Err err;
Config testconfig(setup.settings(), Label(SourceDir("//test/"), "config"));
testconfig.set_testonly(true);
testconfig.visibility().SetPublic();
ASSERT_TRUE(testconfig.OnResolved(&err));
TestTarget test(setup, "//test:test", Target::EXECUTABLE);
test.set_testonly(true);
test.configs().push_back(LabelConfigPair(&testconfig));
ASSERT_TRUE(test.OnResolved(&err));
TestTarget product(setup, "//app:product", Target::EXECUTABLE);
product.set_testonly(false);
product.configs().push_back(LabelConfigPair(&testconfig));
ASSERT_FALSE(product.OnResolved(&err));
}
TEST_F(TargetTest, PublicConfigs) {
TestWithScope setup;
Err err;
Label pub_config_label(SourceDir("//a/"), "pubconfig");
Config pub_config(setup.settings(), pub_config_label);
pub_config.visibility().SetPublic();
LibFile lib_name("testlib");
pub_config.own_values().libs().push_back(lib_name);
ASSERT_TRUE(pub_config.OnResolved(&err));
TestTarget dest(setup, "//a:a", Target::SOURCE_SET);
dest.public_configs().push_back(LabelConfigPair(&pub_config));
ASSERT_TRUE(dest.OnResolved(&err));
TestTarget pub(setup, "//a:pub", Target::SOURCE_SET);
pub.public_deps().push_back(LabelTargetPair(&dest));
ASSERT_TRUE(pub.OnResolved(&err));
TestTarget dep_on_pub(setup, "//a:dop", Target::SOURCE_SET);
dep_on_pub.private_deps().push_back(LabelTargetPair(&pub));
ASSERT_TRUE(dep_on_pub.OnResolved(&err));
ASSERT_EQ(1u, dep_on_pub.configs().size());
EXPECT_EQ(&pub_config, dep_on_pub.configs()[0].ptr);
ResolvedTargetData resolved;
const auto& dep_on_pub_all_libs = resolved.GetLinkedLibraries(&dep_on_pub);
ASSERT_EQ(1u, dep_on_pub_all_libs.size());
ASSERT_EQ(lib_name, dep_on_pub_all_libs[0]);
TestTarget forward(setup, "//a:f", Target::SOURCE_SET);
forward.private_deps().push_back(LabelTargetPair(&dest));
ASSERT_TRUE(forward.OnResolved(&err));
}
TEST_F(TargetTest, ConfigOrdering) {
TestWithScope setup;
Err err;
TestTarget dep1(setup, "//:dep1", Target::SOURCE_SET);
Label dep1_all_config_label(SourceDir("//"), "dep1_all_config");
Config dep1_all_config(setup.settings(), dep1_all_config_label);
dep1_all_config.visibility().SetPublic();
ASSERT_TRUE(dep1_all_config.OnResolved(&err));
dep1.all_dependent_configs().push_back(LabelConfigPair(&dep1_all_config));
Label dep1_public_config_label(SourceDir("//"), "dep1_public_config");
Config dep1_public_config(setup.settings(), dep1_public_config_label);
dep1_public_config.visibility().SetPublic();
ASSERT_TRUE(dep1_public_config.OnResolved(&err));
dep1.public_configs().push_back(LabelConfigPair(&dep1_public_config));
ASSERT_TRUE(dep1.OnResolved(&err));
TestTarget dep2(setup, "//:dep2", Target::SOURCE_SET);
Label dep2_all_config_label(SourceDir("//"), "dep2_all_config");
Config dep2_all_config(setup.settings(), dep2_all_config_label);
dep2_all_config.visibility().SetPublic();
ASSERT_TRUE(dep2_all_config.OnResolved(&err));
dep2.all_dependent_configs().push_back(LabelConfigPair(&dep2_all_config));
Label dep2_public_config_label(SourceDir("//"), "dep2_public_config");
Config dep2_public_config(setup.settings(), dep2_public_config_label);
dep2_public_config.visibility().SetPublic();
ASSERT_TRUE(dep2_public_config.OnResolved(&err));
dep2.public_configs().push_back(LabelConfigPair(&dep2_public_config));
ASSERT_TRUE(dep2.OnResolved(&err));
TestTarget target(setup, "//:foo", Target::SOURCE_SET);
target.private_deps().push_back(LabelTargetPair(&dep1));
target.private_deps().push_back(LabelTargetPair(&dep2));
Label public_config_label(SourceDir("//"), "public");
Config public_config(setup.settings(), public_config_label);
public_config.visibility().SetPublic();
ASSERT_TRUE(public_config.OnResolved(&err));
target.public_configs().push_back(LabelConfigPair(&public_config));
Label private_config_label(SourceDir("//"), "private");
Config private_config(setup.settings(), private_config_label);
private_config.visibility().SetPublic();
ASSERT_TRUE(private_config.OnResolved(&err));
target.configs().push_back(LabelConfigPair(&private_config));
ASSERT_TRUE(target.OnResolved(&err));
const auto& computed = target.configs();
ASSERT_EQ(6u, computed.size());
EXPECT_EQ(private_config_label, computed[0].label);
EXPECT_EQ(public_config_label, computed[1].label);
EXPECT_EQ(dep1_all_config_label, computed[2].label);
EXPECT_EQ(dep2_all_config_label, computed[3].label);
EXPECT_EQ(dep1_public_config_label, computed[4].label);
EXPECT_EQ(dep2_public_config_label, computed[5].label);
}
TEST_F(TargetTest, LinkAndDepOutputs) {
TestWithScope setup;
Err err;
Toolchain toolchain(setup.settings(), Label(SourceDir("//tc/"), "tc"));
std::unique_ptr<Tool> solink = Tool::CreateTool(CTool::kCToolSolink);
CTool* solink_tool = solink->AsC();
solink_tool->set_output_prefix("lib");
solink_tool->set_default_output_extension(".so");
const char kLinkPattern[] =
"{{root_out_dir}}/{{target_output_name}}{{output_extension}}";
SubstitutionPattern link_output =
SubstitutionPattern::MakeForTest(kLinkPattern);
solink_tool->set_link_output(link_output);
const char kDependPattern[] =
"{{root_out_dir}}/{{target_output_name}}{{output_extension}}.TOC";
SubstitutionPattern depend_output =
SubstitutionPattern::MakeForTest(kDependPattern);
solink_tool->set_depend_output(depend_output);
solink_tool->set_outputs(
SubstitutionList::MakeForTest(kLinkPattern, kDependPattern));
toolchain.SetTool(std::move(solink));
Target target(setup.settings(), Label(SourceDir("//a/"), "a"));
target.set_output_type(Target::SHARED_LIBRARY);
target.SetToolchain(&toolchain);
ASSERT_TRUE(target.OnResolved(&err));
EXPECT_EQ("./liba.so", target.link_output_file().value());
ASSERT_TRUE(target.has_dependency_output_file());
EXPECT_EQ("./liba.so.TOC", target.dependency_output_file().value());
ASSERT_EQ(1u, target.runtime_outputs().size());
EXPECT_EQ("./liba.so", target.runtime_outputs()[0].value());
}
TEST_F(TargetTest, RustLinkAndDepOutputs) {
TestWithScope setup;
Err err;
Toolchain toolchain(setup.settings(), Label(SourceDir("//tc/"), "tc"));
std::unique_ptr<Tool> tool = Tool::CreateTool(RustTool::kRsToolDylib);
RustTool* rust_tool = tool->AsRust();
rust_tool->set_output_prefix("lib");
rust_tool->set_default_output_extension(".so");
const char kLinkPattern[] =
"{{root_out_dir}}/{{target_output_name}}{{output_extension}}";
SubstitutionPattern link_output =
SubstitutionPattern::MakeForTest(kLinkPattern);
rust_tool->set_link_output(link_output);
const char kDependPattern[] =
"{{root_out_dir}}/{{target_output_name}}{{output_extension}}.TOC";
SubstitutionPattern depend_output =
SubstitutionPattern::MakeForTest(kDependPattern);
rust_tool->set_depend_output(depend_output);
rust_tool->set_outputs(
SubstitutionList::MakeForTest(kLinkPattern, kDependPattern));
toolchain.SetTool(std::move(tool));
Target target(setup.settings(), Label(SourceDir("//a/"), "a"));
target.source_types_used().Set(SourceFile::SOURCE_RS);
target.rust_values().set_crate_type(RustValues::CRATE_DYLIB);
target.set_output_type(Target::SHARED_LIBRARY);
target.SetToolchain(&toolchain);
ASSERT_TRUE(target.OnResolved(&err));
EXPECT_EQ("./liba.so", target.link_output_file().value());
EXPECT_EQ("./liba.so.TOC", target.dependency_output_file().value());
ASSERT_EQ(1u, target.runtime_outputs().size());
EXPECT_EQ("./liba.so", target.runtime_outputs()[0].value());
}
TEST_F(TargetTest, RuntimeOuputs) {
TestWithScope setup;
Err err;
Toolchain toolchain(setup.settings(), Label(SourceDir("//tc/"), "tc"));
std::unique_ptr<Tool> solink = Tool::CreateTool(CTool::kCToolSolink);
CTool* solink_tool = solink->AsC();
solink_tool->set_output_prefix("");
solink_tool->set_default_output_extension(".dll");
const char kLibPattern[] =
"{{root_out_dir}}/{{target_output_name}}{{output_extension}}.lib";
const char kDllPattern[] =
"{{root_out_dir}}/{{target_output_name}}{{output_extension}}";
const char kPdbPattern[] = "{{root_out_dir}}/{{target_output_name}}.pdb";
SubstitutionPattern pdb_pattern =
SubstitutionPattern::MakeForTest(kPdbPattern);
solink_tool->set_outputs(
SubstitutionList::MakeForTest(kLibPattern, kDllPattern, kPdbPattern));
solink_tool->set_runtime_outputs(
SubstitutionList::MakeForTest(kDllPattern, kPdbPattern));
toolchain.SetTool(std::move(solink));
Target target(setup.settings(), Label(SourceDir("//a/"), "a"));
target.set_output_type(Target::SHARED_LIBRARY);
target.SetToolchain(&toolchain);
ASSERT_TRUE(target.OnResolved(&err));
EXPECT_EQ("./a.dll.lib", target.link_output_file().value());
ASSERT_TRUE(target.has_dependency_output_file());
EXPECT_EQ("./a.dll.lib", target.dependency_output_file().value());
ASSERT_EQ(2u, target.runtime_outputs().size());
EXPECT_EQ("./a.dll", target.runtime_outputs()[0].value());
EXPECT_EQ("./a.pdb", target.runtime_outputs()[1].value());
std::vector<SourceFile> computed_outputs;
EXPECT_TRUE(target.GetOutputsAsSourceFiles(LocationRange(), true,
&computed_outputs, &err));
ASSERT_EQ(3u, computed_outputs.size());
EXPECT_EQ("//out/Debug/a.dll.lib", computed_outputs[0].value());
EXPECT_EQ("//out/Debug/a.dll", computed_outputs[1].value());
EXPECT_EQ("//out/Debug/a.pdb", computed_outputs[2].value());
}
TEST_F(TargetTest, RustRuntimeOuputs) {
TestWithScope setup;
Err err;
Toolchain toolchain(setup.settings(), Label(SourceDir("//tc/"), "tc"));
std::unique_ptr<Tool> tool = Tool::CreateTool(RustTool::kRsToolCDylib);
RustTool* rust_tool = tool->AsRust();
rust_tool->set_output_prefix("");
rust_tool->set_default_output_extension(".dll");
const char kLibPattern[] =
"{{root_out_dir}}/{{target_output_name}}{{output_extension}}.lib";
const char kDllPattern[] =
"{{root_out_dir}}/{{target_output_name}}{{output_extension}}";
const char kPdbPattern[] = "{{root_out_dir}}/{{target_output_name}}.pdb";
SubstitutionPattern pdb_pattern =
SubstitutionPattern::MakeForTest(kPdbPattern);
rust_tool->set_outputs(
SubstitutionList::MakeForTest(kLibPattern, kDllPattern, kPdbPattern));
rust_tool->set_runtime_outputs(
SubstitutionList::MakeForTest(kDllPattern, kPdbPattern));
toolchain.SetTool(std::move(tool));
Target target(setup.settings(), Label(SourceDir("//a/"), "a"));
target.source_types_used().Set(SourceFile::SOURCE_RS);
target.rust_values().set_crate_type(RustValues::CRATE_CDYLIB);
target.set_output_type(Target::SHARED_LIBRARY);
target.SetToolchain(&toolchain);
ASSERT_TRUE(target.OnResolved(&err));
EXPECT_EQ("./a.dll.lib", target.link_output_file().value());
EXPECT_EQ("./a.dll.lib", target.dependency_output_file().value());
ASSERT_EQ(2u, target.runtime_outputs().size());
EXPECT_EQ("./a.dll", target.runtime_outputs()[0].value());
EXPECT_EQ("./a.pdb", target.runtime_outputs()[1].value());
std::vector<SourceFile> computed_outputs;
EXPECT_TRUE(target.GetOutputsAsSourceFiles(LocationRange(), true,
&computed_outputs, &err));
ASSERT_EQ(3u, computed_outputs.size());
EXPECT_EQ("//out/Debug/a.dll.lib", computed_outputs[0].value());
EXPECT_EQ("//out/Debug/a.dll", computed_outputs[1].value());
EXPECT_EQ("//out/Debug/a.pdb", computed_outputs[2].value());
}
TEST_F(TargetTest, GetOutputFilesForSource_ActionForEach) {
TestWithScope setup;
TestTarget target(setup, "//a:a", Target::ACTION_FOREACH);
target.sources().push_back(SourceFile("//a/source_file1.txt"));
target.sources().push_back(SourceFile("//a/source_file2.txt"));
target.action_values().outputs() =
SubstitutionList::MakeForTest("//out/Debug/{{source_file_part}}.one",
"//out/Debug/{{source_file_part}}.two");
Err err;
ASSERT_TRUE(target.OnResolved(&err));
const char* computed_tool_type = nullptr;
std::vector<OutputFile> output;
bool result = target.GetOutputFilesForSource(SourceFile("//source/input.txt"),
&computed_tool_type, &output);
ASSERT_TRUE(result);
ASSERT_EQ(2u, output.size());
EXPECT_EQ("input.txt.one", output[0].value());
EXPECT_EQ("input.txt.two", output[1].value());
std::vector<SourceFile> computed_outputs;
EXPECT_TRUE(target.GetOutputsAsSourceFiles(LocationRange(), true,
&computed_outputs, &err));
ASSERT_EQ(4u, computed_outputs.size());
EXPECT_EQ("//out/Debug/source_file1.txt.one", computed_outputs[0].value());
EXPECT_EQ("//out/Debug/source_file1.txt.two", computed_outputs[1].value());
EXPECT_EQ("//out/Debug/source_file2.txt.one", computed_outputs[2].value());
EXPECT_EQ("//out/Debug/source_file2.txt.two", computed_outputs[3].value());
}
TEST_F(TargetTest, GetOutputFilesForSource_Action) {
TestWithScope setup;
TestTarget target(setup, "//a:a", Target::ACTION);
target.sources().push_back(SourceFile("//a/source_file1.txt"));
target.action_values().outputs() =
SubstitutionList::MakeForTest("//out/Debug/one", "//out/Debug/two");
Err err;
ASSERT_TRUE(target.OnResolved(&err));
const char* computed_tool_type = nullptr;
std::vector<OutputFile> output;
bool result = target.GetOutputFilesForSource(SourceFile("//source/input.txt"),
&computed_tool_type, &output);
ASSERT_TRUE(result);
ASSERT_EQ(2u, output.size());
EXPECT_EQ("one", output[0].value());
EXPECT_EQ("two", output[1].value());
std::vector<SourceFile> computed_outputs;
EXPECT_TRUE(target.GetOutputsAsSourceFiles(LocationRange(), true,
&computed_outputs, &err));
ASSERT_EQ(2u, computed_outputs.size());
EXPECT_EQ("//out/Debug/one", computed_outputs[0].value());
EXPECT_EQ("//out/Debug/two", computed_outputs[1].value());
target.action_values().outputs() =
SubstitutionList::MakeForTest("//out/Debug/one");
target.set_output_type(Target::COPY_FILES);
result = target.GetOutputFilesForSource(SourceFile("//source/input.txt"),
&computed_tool_type, &output);
ASSERT_TRUE(result);
ASSERT_EQ(1u, output.size());
EXPECT_EQ("one", output[0].value());
EXPECT_TRUE(target.GetOutputsAsSourceFiles(LocationRange(), true,
&computed_outputs, &err));
ASSERT_EQ(1u, computed_outputs.size()) << computed_outputs.size();
EXPECT_EQ("//out/Debug/one", computed_outputs[0].value());
}
TEST_F(TargetTest, HasRealInputs) {
TestWithScope setup;
Err err;
TestTarget target_a(setup, "//a:a", Target::ACTION);
ASSERT_TRUE(target_a.FillOutputFiles(&err));
EXPECT_TRUE(target_a.HasRealInputs());
TestTarget target_b(setup, "//a:b", Target::GROUP);
ASSERT_TRUE(target_b.FillOutputFiles(&err));
EXPECT_FALSE(target_b.HasRealInputs());
target_b.private_deps().push_back(LabelTargetPair(&target_a));
ASSERT_TRUE(target_b.FillOutputFiles(&err));
EXPECT_TRUE(target_b.HasRealInputs());
TestTarget target_c(setup, "//a:c", Target::SOURCE_SET);
target_c.config_values().inputs().push_back(SourceFile("//a/no_tool.txt"));
ASSERT_TRUE(target_c.FillOutputFiles(&err));
EXPECT_FALSE(target_c.HasRealInputs());
TestTarget target_d(setup, "//a:c2", Target::GROUP);
target_c.private_deps().push_back(LabelTargetPair(&target_d));
ASSERT_TRUE(target_c.FillOutputFiles(&err));
EXPECT_FALSE(target_c.HasRealInputs());
TestTarget target_e(setup, "//a:d", Target::EXECUTABLE);
target_e.sources().push_back(SourceFile("//a/source.cc"));
ASSERT_TRUE(target_e.FillOutputFiles(&err));
EXPECT_TRUE(target_e.HasRealInputs());
target_c.private_deps().push_back(LabelTargetPair(&target_e));
ASSERT_TRUE(target_c.FillOutputFiles(&err));
EXPECT_TRUE(target_c.HasRealInputs());
}
TEST_F(TargetTest, GeneratedInputs) {
TestWithScope setup;
Err err;
SourceFile generated_file("//out/Debug/generated.cc");
TestTarget non_existent_generator(setup, "//foo:non_existent_generator",
Target::EXECUTABLE);
non_existent_generator.sources().push_back(generated_file);
EXPECT_TRUE(non_existent_generator.OnResolved(&err)) << err.message();
AssertSchedulerHasOneUnknownFileMatching(&non_existent_generator,
generated_file);
scheduler().ClearUnknownGeneratedInputsAndWrittenFiles();
TestTarget generator(setup, "//foo:generator", Target::ACTION);
generator.action_values().outputs() =
SubstitutionList::MakeForTest(generated_file.value().c_str());
err = Err();
EXPECT_TRUE(generator.OnResolved(&err)) << err.message();
TestTarget existent_generator(setup, "//foo:existent_generator",
Target::SHARED_LIBRARY);
existent_generator.sources().push_back(generated_file);
existent_generator.private_deps().push_back(LabelTargetPair(&generator));
EXPECT_TRUE(existent_generator.OnResolved(&err)) << err.message();
EXPECT_TRUE(scheduler().GetUnknownGeneratedInputs().empty());
TestTarget indirect_private(setup, "//foo:indirect_private",
Target::EXECUTABLE);
indirect_private.sources().push_back(generated_file);
indirect_private.public_deps().push_back(
LabelTargetPair(&existent_generator));
EXPECT_TRUE(indirect_private.OnResolved(&err));
AssertSchedulerHasOneUnknownFileMatching(&indirect_private, generated_file);
scheduler().ClearUnknownGeneratedInputsAndWrittenFiles();
TestTarget existent_public(setup, "//foo:existent_public",
Target::SHARED_LIBRARY);
existent_public.public_deps().push_back(LabelTargetPair(&generator));
EXPECT_TRUE(existent_public.OnResolved(&err)) << err.message();
TestTarget indirect_public(setup, "//foo:indirect_public",
Target::EXECUTABLE);
indirect_public.sources().push_back(generated_file);
indirect_public.public_deps().push_back(LabelTargetPair(&existent_public));
EXPECT_TRUE(indirect_public.OnResolved(&err)) << err.message();
EXPECT_TRUE(scheduler().GetUnknownGeneratedInputs().empty());
}
TEST_F(TargetTest, WriteFileGeneratedInputs) {
TestWithScope setup;
Err err;
SourceFile generated_file("//out/Debug/generated.data");
TestTarget non_existent_generator(setup, "//foo:non_existent_generator",
Target::EXECUTABLE);
non_existent_generator.sources().push_back(generated_file);
EXPECT_TRUE(non_existent_generator.OnResolved(&err));
AssertSchedulerHasOneUnknownFileMatching(&non_existent_generator,
generated_file);
scheduler().ClearUnknownGeneratedInputsAndWrittenFiles();
TestTarget existent_generator(setup, "//foo:existent_generator",
Target::EXECUTABLE);
existent_generator.sources().push_back(generated_file);
EXPECT_TRUE(existent_generator.OnResolved(&err));
scheduler().AddWrittenFile(generated_file);
EXPECT_TRUE(scheduler().GetUnknownGeneratedInputs().empty());
}
TEST_F(TargetTest, WriteRuntimeDepsGeneratedInputs) {
TestWithScope setup;
Err err;
SourceFile source_file("//out/Debug/generated.runtime_deps");
OutputFile output_file(setup.build_settings(), source_file);
TestTarget generator(setup, "//foo:generator", Target::EXECUTABLE);
generator.set_write_runtime_deps_output(output_file);
g_scheduler->AddWriteRuntimeDepsTarget(&generator);
TestTarget middle_data_dep(setup, "//foo:middle", Target::EXECUTABLE);
middle_data_dep.data_deps().push_back(LabelTargetPair(&generator));
TestTarget dep_missing(setup, "//foo:no_dep", Target::EXECUTABLE);
dep_missing.sources().push_back(source_file);
EXPECT_TRUE(dep_missing.OnResolved(&err));
AssertSchedulerHasOneUnknownFileMatching(&dep_missing, source_file);
scheduler().ClearUnknownGeneratedInputsAndWrittenFiles();
TestTarget dep_present(setup, "//foo:with_dep", Target::EXECUTABLE);
dep_present.sources().push_back(source_file);
dep_present.private_deps().push_back(LabelTargetPair(&generator));
EXPECT_TRUE(dep_present.OnResolved(&err));
EXPECT_TRUE(scheduler().GetUnknownGeneratedInputs().empty());
TestTarget dep_indirect(setup, "//foo:with_dep", Target::EXECUTABLE);
dep_indirect.sources().push_back(source_file);
dep_indirect.data_deps().push_back(LabelTargetPair(&middle_data_dep));
EXPECT_TRUE(dep_indirect.OnResolved(&err));
AssertSchedulerHasOneUnknownFileMatching(&dep_indirect, source_file);
scheduler().ClearUnknownGeneratedInputsAndWrittenFiles();
TestTarget data_dep_present(setup, "//foo:with_dep", Target::EXECUTABLE);
data_dep_present.sources().push_back(source_file);
data_dep_present.data_deps().push_back(LabelTargetPair(&generator));
EXPECT_TRUE(data_dep_present.OnResolved(&err));
EXPECT_TRUE(scheduler().GetUnknownGeneratedInputs().empty());
}
TEST_F(TargetTest, ObjectGeneratedInputs) {
TestWithScope setup;
Err err;
SourceFile source_file("//source.cc");
TestTarget source_generator(setup, "//:source_target", Target::SOURCE_SET);
source_generator.sources().push_back(source_file);
EXPECT_TRUE(source_generator.OnResolved(&err));
SourceFile object_file("//out/Debug/obj/source_target.source.o");
TestTarget final_target(setup, "//:final", Target::ACTION);
final_target.config_values().inputs().push_back(object_file);
EXPECT_TRUE(final_target.OnResolved(&err));
AssertSchedulerHasOneUnknownFileMatching(&final_target, object_file);
}
TEST_F(TargetTest, ResolvePrecompiledHeaders) {
TestWithScope setup;
Err err;
Target target(setup.settings(), Label(SourceDir("//foo/"), "bar",
SourceDir("//toolchain/"), "default"));
EXPECT_TRUE(target.ResolvePrecompiledHeaders(&err));
Config config_1(
setup.settings(),
Label(SourceDir("//foo/"), "c1", SourceDir("//toolchain/"), "default"));
std::string pch_1("pch.h");
SourceFile pcs_1("//pcs.cc");
config_1.own_values().set_precompiled_header(pch_1);
config_1.own_values().set_precompiled_source(pcs_1);
ASSERT_TRUE(config_1.OnResolved(&err));
target.configs().push_back(LabelConfigPair(&config_1));
EXPECT_TRUE(target.ResolvePrecompiledHeaders(&err));
EXPECT_EQ(pch_1, target.config_values().precompiled_header());
EXPECT_TRUE(target.config_values().precompiled_source() == pcs_1);
EXPECT_TRUE(target.ResolvePrecompiledHeaders(&err));
EXPECT_TRUE(target.config_values().precompiled_header() == pch_1);
EXPECT_TRUE(target.config_values().precompiled_source() == pcs_1);
Config config_2(
setup.settings(),
Label(SourceDir("//foo/"), "c2", SourceDir("//toolchain/"), "default"));
std::string pch_2("pch2.h");
SourceFile pcs_2("//pcs2.cc");
config_2.own_values().set_precompiled_header(pch_2);
config_2.own_values().set_precompiled_source(pcs_2);
ASSERT_TRUE(config_2.OnResolved(&err));
target.configs().push_back(LabelConfigPair(&config_2));
EXPECT_FALSE(target.ResolvePrecompiledHeaders(&err));
EXPECT_EQ(
"The target //foo:bar\n"
"has conflicting precompiled header settings.\n"
"\n"
"From //foo:bar\n"
" header: pch.h\n"
" source: //pcs.cc\n"
"\n"
"From //foo:c2\n"
" header: pch2.h\n"
" source: //pcs2.cc",
err.help_text());
}
TEST_F(TargetTest, AssertNoDeps) {
TestWithScope setup;
Err err;
TestTarget a(setup, "//a", Target::SHARED_LIBRARY);
ASSERT_TRUE(a.OnResolved(&err));
TestTarget b(setup, "//b", Target::SHARED_LIBRARY);
b.private_deps().push_back(LabelTargetPair(&a));
b.assert_no_deps().push_back(LabelPattern(LabelPattern::RECURSIVE_DIRECTORY,
SourceDir("//disallowed/"),
std::string(), Label()));
ASSERT_TRUE(b.OnResolved(&err));
LabelPattern disallow_a(LabelPattern::RECURSIVE_DIRECTORY, SourceDir("//a/"),
std::string(), Label());
TestTarget c(setup, "//c", Target::EXECUTABLE);
c.private_deps().push_back(LabelTargetPair(&b));
c.assert_no_deps().push_back(disallow_a);
ASSERT_FALSE(c.OnResolved(&err));
EXPECT_EQ(
"//c:c has an assert_no_deps entry:\n"
" //a/*\n"
"which fails for the dependency path:\n"
" //c:c ->\n"
" //b:b ->\n"
" //a:a",
err.help_text());
err = Err();
TestTarget exe(setup, "//exe", Target::EXECUTABLE);
exe.private_deps().push_back(LabelTargetPair(&b));
ASSERT_TRUE(exe.OnResolved(&err));
TestTarget d(setup, "//d", Target::EXECUTABLE);
d.private_deps().push_back(LabelTargetPair(&exe));
d.assert_no_deps().push_back(disallow_a);
ASSERT_TRUE(d.OnResolved(&err));
TestTarget a2(setup, "//a:a2", Target::EXECUTABLE);
a2.assert_no_deps().push_back(disallow_a);
ASSERT_TRUE(a2.OnResolved(&err));
}
TEST_F(TargetTest, PullRecursiveBundleData) {
TestWithScope setup;
Err err;
TestTarget a(setup, "//foo:a", Target::CREATE_BUNDLE);
TestTarget b(setup, "//foo:b", Target::BUNDLE_DATA);
TestTarget c(setup, "//foo:c", Target::CREATE_BUNDLE);
TestTarget d(setup, "//foo:d", Target::BUNDLE_DATA);
TestTarget e(setup, "//foo:e", Target::GROUP);
TestTarget f(setup, "//foo:f", Target::BUNDLE_DATA);
a.public_deps().push_back(LabelTargetPair(&b));
a.public_deps().push_back(LabelTargetPair(&c));
a.public_deps().push_back(LabelTargetPair(&e));
c.public_deps().push_back(LabelTargetPair(&d));
e.public_deps().push_back(LabelTargetPair(&f));
e.public_deps().push_back(LabelTargetPair(&b));
a.bundle_data().root_dir() = SourceDir("//out/foo_a.bundle");
a.bundle_data().resources_dir() = SourceDir("//out/foo_a.bundle/Resources");
b.sources().push_back(SourceFile("//foo/b1.txt"));
b.sources().push_back(SourceFile("//foo/b2.txt"));
b.action_values().outputs() = SubstitutionList::MakeForTest(
"{{bundle_resources_dir}}/{{source_file_part}}");
ASSERT_TRUE(b.OnResolved(&err));
c.bundle_data().root_dir() = SourceDir("//out/foo_c.bundle");
c.bundle_data().resources_dir() = SourceDir("//out/foo_c.bundle/Resources");
d.sources().push_back(SourceFile("//foo/d.txt"));
d.action_values().outputs() = SubstitutionList::MakeForTest(
"{{bundle_resources_dir}}/{{source_file_part}}");
ASSERT_TRUE(d.OnResolved(&err));
f.sources().push_back(SourceFile("//foo/f1.txt"));
f.sources().push_back(SourceFile("//foo/f2.txt"));
f.sources().push_back(SourceFile("//foo/f3.txt"));
f.sources().push_back(
SourceFile("//foo/Foo.xcassets/foo.imageset/Contents.json"));
f.sources().push_back(
SourceFile("//foo/Foo.xcassets/foo.imageset/FooEmpty-29.png"));
f.sources().push_back(
SourceFile("//foo/Foo.xcassets/foo.imageset/FooEmpty-29@2x.png"));
f.sources().push_back(
SourceFile("//foo/Foo.xcassets/foo.imageset/FooEmpty-29@3x.png"));
f.sources().push_back(
SourceFile("//foo/Foo.xcassets/file/with/no/known/pattern"));
f.sources().push_back(
SourceFile("//foo/Foo.xcassets/nested/bar.xcassets/my/file"));
f.action_values().outputs() = SubstitutionList::MakeForTest(
"{{bundle_resources_dir}}/{{source_file_part}}");
ASSERT_TRUE(f.OnResolved(&err));
ASSERT_TRUE(e.OnResolved(&err));
ASSERT_TRUE(c.OnResolved(&err));
ASSERT_TRUE(a.OnResolved(&err));
ASSERT_EQ(a.bundle_data().file_rules().size(), 2u);
ASSERT_EQ(a.bundle_data().file_rules()[0].sources().size(), 2u);
ASSERT_EQ(a.bundle_data().file_rules()[1].sources().size(), 3u);
ASSERT_EQ(a.bundle_data().assets_catalog_sources().size(), 1u);
ASSERT_EQ(a.bundle_data().forwarded_bundle_deps().size(), 2u);
ASSERT_EQ(c.bundle_data().file_rules().size(), 1u);
ASSERT_EQ(c.bundle_data().file_rules()[0].sources().size(), 1u);
ASSERT_EQ(c.bundle_data().forwarded_bundle_deps().size(), 1u);
ASSERT_TRUE(e.bundle_data().file_rules().empty());
ASSERT_TRUE(e.bundle_data().assets_catalog_sources().empty());
ASSERT_EQ(e.bundle_data().forwarded_bundle_deps().size(), 2u);
}
TEST(TargetTest, CollectMetadataNoRecurse) {
TestWithScope setup;
TestTarget one(setup, "//foo:one", Target::SOURCE_SET);
Value a_expected(nullptr, Value::LIST);
a_expected.list_value().push_back(Value(nullptr, "foo"));
one.metadata().contents().insert(
std::pair<std::string_view, Value>("a", a_expected));
Value b_expected(nullptr, Value::LIST);
b_expected.list_value().push_back(Value(nullptr, true));
one.metadata().contents().insert(
std::pair<std::string_view, Value>("b", b_expected));
one.metadata().set_source_dir(SourceDir("/usr/home/files/"));
std::vector<std::string> data_keys;
data_keys.push_back("a");
data_keys.push_back("b");
std::vector<std::string> walk_keys;
Err err;
std::vector<Value> result;
TargetSet targets;
one.GetMetadata(data_keys, walk_keys, SourceDir(), false, &result, &targets,
&err);
EXPECT_FALSE(err.has_error());
std::vector<Value> expected;
expected.push_back(Value(nullptr, "foo"));
expected.push_back(Value(nullptr, true));
EXPECT_EQ(result, expected);
}
TEST(TargetTest, CollectMetadataWithRecurse) {
TestWithScope setup;
TestTarget one(setup, "//foo:one", Target::SOURCE_SET);
Value a_expected(nullptr, Value::LIST);
a_expected.list_value().push_back(Value(nullptr, "foo"));
one.metadata().contents().insert(
std::pair<std::string_view, Value>("a", a_expected));
Value b_expected(nullptr, Value::LIST);
b_expected.list_value().push_back(Value(nullptr, true));
one.metadata().contents().insert(
std::pair<std::string_view, Value>("b", b_expected));
TestTarget two(setup, "//foo:two", Target::SOURCE_SET);
Value a_2_expected(nullptr, Value::LIST);
a_2_expected.list_value().push_back(Value(nullptr, "bar"));
two.metadata().contents().insert(
std::pair<std::string_view, Value>("a", a_2_expected));
one.public_deps().push_back(LabelTargetPair(&two));
std::vector<std::string> data_keys;
data_keys.push_back("a");
data_keys.push_back("b");
std::vector<std::string> walk_keys;
Err err;
std::vector<Value> result;
TargetSet targets;
one.GetMetadata(data_keys, walk_keys, SourceDir(), false, &result, &targets,
&err);
EXPECT_FALSE(err.has_error());
std::vector<Value> expected;
expected.push_back(Value(nullptr, "bar"));
expected.push_back(Value(nullptr, "foo"));
expected.push_back(Value(nullptr, true));
EXPECT_EQ(result, expected);
}
TEST(TargetTest, CollectMetadataWithRecurseHole) {
TestWithScope setup;
TestTarget one(setup, "//foo:one", Target::SOURCE_SET);
Value a_expected(nullptr, Value::LIST);
a_expected.list_value().push_back(Value(nullptr, "foo"));
one.metadata().contents().insert(
std::pair<std::string_view, Value>("a", a_expected));
Value b_expected(nullptr, Value::LIST);
b_expected.list_value().push_back(Value(nullptr, true));
one.metadata().contents().insert(
std::pair<std::string_view, Value>("b", b_expected));
TestTarget two(setup, "//foo:two", Target::SOURCE_SET);
TestTarget three(setup, "//foo:three", Target::SOURCE_SET);
Value a_3_expected(nullptr, Value::LIST);
a_3_expected.list_value().push_back(Value(nullptr, "bar"));
three.metadata().contents().insert(
std::pair<std::string_view, Value>("a", a_3_expected));
one.public_deps().push_back(LabelTargetPair(&two));
two.public_deps().push_back(LabelTargetPair(&three));
std::vector<std::string> data_keys;
data_keys.push_back("a");
data_keys.push_back("b");
std::vector<std::string> walk_keys;
Err err;
std::vector<Value> result;
TargetSet targets;
one.GetMetadata(data_keys, walk_keys, SourceDir(), false, &result, &targets,
&err);
EXPECT_FALSE(err.has_error());
std::vector<Value> expected;
expected.push_back(Value(nullptr, "bar"));
expected.push_back(Value(nullptr, "foo"));
expected.push_back(Value(nullptr, true));
EXPECT_EQ(result, expected);
}
TEST(TargetTest, CollectMetadataWithBarrier) {
TestWithScope setup;
TestTarget one(setup, "//foo:one", Target::SOURCE_SET);
Value a_expected(nullptr, Value::LIST);
a_expected.list_value().push_back(Value(nullptr, "foo"));
one.metadata().contents().insert(
std::pair<std::string_view, Value>("a", a_expected));
Value walk_expected(nullptr, Value::LIST);
walk_expected.list_value().push_back(Value(nullptr, "two"));
one.metadata().contents().insert(
std::pair<std::string_view, Value>("walk", walk_expected));
TestTarget two(setup, "//foo/two:two", Target::SOURCE_SET);
Value a_2_expected(nullptr, Value::LIST);
a_2_expected.list_value().push_back(Value(nullptr, "bar"));
two.metadata().contents().insert(
std::pair<std::string_view, Value>("a", a_2_expected));
TestTarget three(setup, "//foo:three", Target::SOURCE_SET);
Value a_3_expected(nullptr, Value::LIST);
a_3_expected.list_value().push_back(Value(nullptr, "baz"));
three.metadata().contents().insert(
std::pair<std::string_view, Value>("a", a_3_expected));
one.private_deps().push_back(LabelTargetPair(&two));
one.public_deps().push_back(LabelTargetPair(&three));
std::vector<std::string> data_keys;
data_keys.push_back("a");
std::vector<std::string> walk_keys;
walk_keys.push_back("walk");
Err err;
std::vector<Value> result;
TargetSet targets;
one.GetMetadata(data_keys, walk_keys, SourceDir(), false, &result, &targets,
&err);
EXPECT_FALSE(err.has_error()) << err.message();
std::vector<Value> expected;
expected.push_back(Value(nullptr, "bar"));
expected.push_back(Value(nullptr, "foo"));
EXPECT_EQ(result, expected) << result.size();
}
TEST(TargetTest, CollectMetadataWithError) {
TestWithScope setup;
TestTarget one(setup, "//foo:one", Target::SOURCE_SET);
Value a_expected(nullptr, Value::LIST);
a_expected.list_value().push_back(Value(nullptr, "foo"));
one.metadata().contents().insert(
std::pair<std::string_view, Value>("a", a_expected));
Value walk_expected(nullptr, Value::LIST);
walk_expected.list_value().push_back(Value(nullptr, "//foo:missing"));
one.metadata().contents().insert(
std::pair<std::string_view, Value>("walk", walk_expected));
std::vector<std::string> data_keys;
data_keys.push_back("a");
std::vector<std::string> walk_keys;
walk_keys.push_back("walk");
Err err;
std::vector<Value> result;
TargetSet targets;
one.GetMetadata(data_keys, walk_keys, SourceDir(), false, &result, &targets,
&err);
EXPECT_TRUE(err.has_error());
EXPECT_EQ(err.message(),
"I was expecting //foo:missing(//toolchain:default) to be a "
"dependency of //foo:one(//toolchain:default). "
"Make sure it's included in the deps or data_deps, and that you've "
"specified the appropriate toolchain.")
<< err.message();
}
TEST_F(TargetTest, WriteMetadataCollection) {
TestWithScope setup;
Err err;
SourceFile source_file("//out/Debug/metadata.json");
OutputFile output_file(setup.build_settings(), source_file);
TestTarget generator(setup, "//foo:write", Target::GENERATED_FILE);
generator.action_values().outputs() =
SubstitutionList::MakeForTest("//out/Debug/metadata.json");
EXPECT_TRUE(generator.OnResolved(&err));
TestTarget middle_data_dep(setup, "//foo:middle", Target::EXECUTABLE);
middle_data_dep.data_deps().push_back(LabelTargetPair(&generator));
EXPECT_TRUE(middle_data_dep.OnResolved(&err));
TestTarget dep_missing(setup, "//foo:no_dep", Target::EXECUTABLE);
dep_missing.sources().push_back(source_file);
EXPECT_TRUE(dep_missing.OnResolved(&err));
AssertSchedulerHasOneUnknownFileMatching(&dep_missing, source_file);
scheduler().ClearUnknownGeneratedInputsAndWrittenFiles();
TestTarget dep_present(setup, "//foo:with_dep", Target::EXECUTABLE);
dep_present.sources().push_back(source_file);
dep_present.private_deps().push_back(LabelTargetPair(&generator));
EXPECT_TRUE(dep_present.OnResolved(&err));
EXPECT_TRUE(scheduler().GetUnknownGeneratedInputs().empty());
TestTarget dep_indirect(setup, "//foo:indirect_dep", Target::EXECUTABLE);
dep_indirect.sources().push_back(source_file);
dep_indirect.data_deps().push_back(LabelTargetPair(&middle_data_dep));
EXPECT_TRUE(dep_indirect.OnResolved(&err));
AssertSchedulerHasOneUnknownFileMatching(&dep_indirect, source_file);
scheduler().ClearUnknownGeneratedInputsAndWrittenFiles();
TestTarget data_dep_present(setup, "//foo:with_data_dep", Target::EXECUTABLE);
data_dep_present.sources().push_back(source_file);
data_dep_present.data_deps().push_back(LabelTargetPair(&generator));
EXPECT_TRUE(data_dep_present.OnResolved(&err));
EXPECT_TRUE(scheduler().GetUnknownGeneratedInputs().empty());
}
TEST_F(TargetTest, ModuleMap) {
TestWithScope setup;
Toolchain toolchain(setup.settings(), Label(SourceDir("//tc/"), "tc"));
std::unique_ptr<Tool> tool = Tool::CreateTool(CTool::kCToolCxxModule);
CTool* cxx_module = tool->AsC();
cxx_module->set_outputs(
SubstitutionList::MakeForTest("{{source_file_part}}.pcm"));
toolchain.SetTool(std::move(tool));
Target target(setup.settings(), Label(SourceDir("//a/"), "a"));
target.set_output_type(Target::SOURCE_SET);
target.SetToolchain(&toolchain);
Err err;
ASSERT_TRUE(target.OnResolved(&err));
const char* computed_tool_type = nullptr;
std::vector<OutputFile> output;
bool result = target.GetOutputFilesForSource(
SourceFile("//source/input.modulemap"), &computed_tool_type, &output);
ASSERT_TRUE(result);
EXPECT_EQ(std::string("cxx_module"), std::string(computed_tool_type));
ASSERT_EQ(1u, output.size());
EXPECT_EQ("input.modulemap.pcm", output[0].value()) << output[0].value();
}
TEST(TargetTest, CollectMetadataWithValidation) {
TestWithScope setup;
TestTarget a(setup, "//foo:a", Target::SOURCE_SET);
Value a_expected(nullptr, Value::LIST);
a_expected.list_value().push_back(Value(nullptr, "foo"));
a.metadata().contents().emplace("walk", a_expected);
TestTarget b(setup, "//foo:b", Target::SOURCE_SET);
Value b_expected(nullptr, Value::LIST);
b_expected.list_value().push_back(Value(nullptr, "bar"));
b.metadata().contents().emplace("walk", b_expected);
a.validations().push_back(LabelTargetPair(&b));
std::vector<std::string> data_keys = {"walk"};
std::vector<std::string> walk_keys;
std::vector<Value> result;
TargetSet targets;
Err err;
a.GetMetadata(data_keys, walk_keys, SourceDir(), false, &result, &targets,
&err);
EXPECT_FALSE(err.has_error());
std::vector<Value> expected = {Value(nullptr, "bar"), Value(nullptr, "foo")};
EXPECT_EQ(result, expected);
}