blob: 52354c62992d88482c414baffe6b909f18e6a897 [file] [log] [blame]
// Copyright 2024 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/ninja_outputs_writer.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "gn/builder_record.h"
#include "gn/filesystem_utils.h"
#include "gn/ninja_target_writer.h"
#include "gn/setup.h"
#include "gn/switches.h"
#include "gn/test_with_scheduler.h"
#include "util/test/test.h"
using NinjaOutputsWriterTest = TestWithScheduler;
using NinjaOutputsMap = NinjaOutputsWriter::MapType;
static void WriteFile(const base::FilePath& file, const std::string& data) {
CHECK_EQ(static_cast<int>(data.size()), // Way smaller than INT_MAX.
base::WriteFile(file, data.data(), data.size()));
}
// Collects Ninja outputs for each target. Used by multiple background threads.
struct TargetWriteInfo {
std::mutex lock;
NinjaOutputsMap ninja_outputs_map;
};
// Called on worker thread to write the ninja file.
void BackgroundDoWrite(TargetWriteInfo* write_info, const Target* target) {
std::vector<OutputFile> target_ninja_outputs;
std::string rule = NinjaTargetWriter::RunAndWriteFile(target, nullptr,
&target_ninja_outputs);
DCHECK(!rule.empty());
std::lock_guard<std::mutex> lock(write_info->lock);
write_info->ninja_outputs_map.emplace(target,
std::move(target_ninja_outputs));
}
static void ItemResolvedAndGeneratedCallback(TargetWriteInfo* write_info,
const BuilderRecord* record) {
const Item* item = record->item();
const Target* target = item->AsTarget();
if (target) {
g_scheduler->ScheduleWork(
[write_info, target]() { BackgroundDoWrite(write_info, target); });
}
}
TEST_F(NinjaOutputsWriterTest, OutputsFile) {
base::CommandLine cmdline(base::CommandLine::NO_PROGRAM);
const char kDotfileContents[] = R"(
buildconfig = "//BUILDCONFIG.gn"
)";
const char kBuildConfigContents[] = R"(
set_default_toolchain("//toolchain:default")
)";
const char kToolchainBuildContents[] = R"##(
toolchain("default") {
tool("stamp") {
command = "stamp"
}
}
toolchain("secondary") {
tool("stamp") {
command = "stamp2"
}
}
)##";
const char kBuildGnContents[] = R"##(
group("foo") {
deps = [ ":bar", ":zoo(//toolchain:secondary)" ]
}
action("bar") {
script = "//:run_bar_script.py"
outputs = [ "$root_build_dir/bar.output" ]
args = []
}
group("zoo") {
}
)##";
// Create a temp directory containing the build.
base::ScopedTempDir in_temp_dir;
ASSERT_TRUE(in_temp_dir.CreateUniqueTempDir());
base::FilePath in_path = in_temp_dir.GetPath();
WriteFile(in_path.Append(FILE_PATH_LITERAL("BUILD.gn")), kBuildGnContents);
WriteFile(in_path.Append(FILE_PATH_LITERAL("BUILDCONFIG.gn")),
kBuildConfigContents);
WriteFile(in_path.Append(FILE_PATH_LITERAL(".gn")), kDotfileContents);
EXPECT_TRUE(
base::CreateDirectory(in_path.Append(FILE_PATH_LITERAL("toolchain"))));
WriteFile(in_path.Append(FILE_PATH_LITERAL("toolchain/BUILD.gn")),
kToolchainBuildContents);
cmdline.AppendSwitch(switches::kRoot, FilePathToUTF8(in_path));
base::FilePath outputs_json_path(FILE_PATH_LITERAL("ninja_outputs.json"));
cmdline.AppendSwitch("--ninja-outputs-file",
FilePathToUTF8(outputs_json_path));
// Create another temp dir for writing the generated files to.
base::ScopedTempDir build_temp_dir;
ASSERT_TRUE(build_temp_dir.CreateUniqueTempDir());
// Run setup
Setup setup;
EXPECT_TRUE(
setup.DoSetup(FilePathToUTF8(build_temp_dir.GetPath()), true, cmdline));
TargetWriteInfo write_info;
setup.builder().set_resolved_and_generated_callback(
[&write_info](const BuilderRecord* record) {
ItemResolvedAndGeneratedCallback(&write_info, record);
});
// Do the actual load.
ASSERT_TRUE(setup.Run());
StringOutputBuffer out =
NinjaOutputsWriter::GenerateJSON(write_info.ninja_outputs_map);
// Verify that the generated file is here.
std::string generated = out.str();
std::string expected = R"##({
"//:bar": [
"bar.output",
"obj/bar.stamp"
],
"//:foo": [
"obj/foo.stamp"
],
"//:zoo": [
"obj/zoo.stamp"
],
"//:zoo(//toolchain:secondary)": [
"secondary/obj/zoo.stamp"
]
})##";
EXPECT_EQ(generated, expected);
}