Skip to content

Commit

Permalink
Add tests for dynamic outputs
Browse files Browse the repository at this point in the history
Co-authored-by: Marc Delorme <[email protected]>
  • Loading branch information
HampusAdolfsson and Dragnalith committed Jan 3, 2024
1 parent 60a21e7 commit f4e6b51
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 2 deletions.
182 changes: 182 additions & 0 deletions src/build_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,18 @@ bool FakeCommandRunner::StartCommand(Edge* edge) {
if (fs_->ReadFile(edge->inputs_[0]->path(), &content, &err) ==
DiskInterface::Okay)
fs_->WriteFile(edge->outputs_[0]->path(), content);
} else if (edge->rule().name() == "cp-plus-bis") {
assert(!edge->inputs_.empty());
assert(edge->outputs_.size() >= 1);
string content;
string err;
if (fs_->ReadFile(edge->inputs_[0]->path(), &content, &err) ==
DiskInterface::Okay) {
fs_->Tick();
fs_->WriteFile(edge->outputs_[0]->path() + ".bis", content);
fs_->Tick();
fs_->WriteFile(edge->outputs_[0]->path(), content);
}
} else if (edge->rule().name() == "touch-implicit-dep-out") {
string dep = edge->GetBinding("test_dependency");
fs_->Tick();
Expand Down Expand Up @@ -4312,3 +4324,173 @@ TEST_F(BuildTest, ValidationWithCircularDependency) {
EXPECT_FALSE(builder_.AddTarget("out", &err));
EXPECT_EQ("dependency cycle: validate -> validate_in -> validate", err);
}

TEST_F(BuildTest, RebuildMissingDynamicOutputs) {
string err;
BuildLog build_log;

{
FakeCommandRunner command_runner(&fs_);
State state;
DepsLog deps_log;
ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
ASSERT_EQ("", err);
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
builder.command_runner_.reset(&command_runner);

ASSERT_NO_FATAL_FAILURE(
AssertParse(&state,
"rule cp-plus-bis\n"
" command = cp $in $out && cp $in $out.bis\n"
" dynout = $out.dynout\n"
"build out: cp-plus-bis in\n"));

fs_.Tick();
fs_.Create("in", "");
fs_.Create("out.dynout", "out.bis\n");

EXPECT_TRUE(builder.AddTarget("out", &err));
EXPECT_TRUE(builder.Build(&err));
ASSERT_EQ("", err);
ASSERT_EQ(1u, command_runner.commands_ran_.size());
ASSERT_GT(fs_.Stat("out", &err), 0);
ASSERT_GT(fs_.Stat("out.bis", &err), 0);
// Make sure the dynout file has been removed after its
// information has been extracted in the deps log.
ASSERT_EQ(fs_.Stat("out.dynout", &err), 0);

// all clean, no rebuild.
command_runner.commands_ran_.clear();
state.Reset();
EXPECT_TRUE(builder.AddTarget("out", &err));
EXPECT_EQ("", err);
EXPECT_TRUE(builder.AlreadyUpToDate());

// Test dynamic output are rebuilt if they are deleted.
fs_.RemoveFile("out.bis");
command_runner.commands_ran_.clear();
state.Reset();

fs_.Create("out.dynout", "out.bis\n");
EXPECT_TRUE(builder.AddTarget("out", &err));
EXPECT_TRUE(builder.Build(&err));
ASSERT_EQ("", err);
ASSERT_EQ(1u, command_runner.commands_ran_.size());

builder.command_runner_.release();
deps_log.Close();
}

// Create a new state to make sure outputs are reset
{
FakeCommandRunner command_runner(&fs_);
State state;
DepsLog deps_log;
ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
ASSERT_EQ("", err);
deps_log.Load("ninja_deps", &state, &err);
ASSERT_EQ("", err);
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
builder.command_runner_.reset(&command_runner);

ASSERT_NO_FATAL_FAILURE(
AssertParse(&state,
"rule cp-plus-bis\n"
" command = cp $in $out && cp $in $out.bis\n"
" dynout = $out.dynout\n"
"build out: cp-plus-bis in\n"));

// all clean, no rebuild.
command_runner.commands_ran_.clear();
state.Reset();
EXPECT_TRUE(builder.AddTarget("out", &err));
EXPECT_EQ("", err);
EXPECT_TRUE(builder.AlreadyUpToDate());

// Test dynamic output are rebuilt if they are deleted
// after having been rebuilt in order to make sure
// when dynamic output information was already exist they
// keep being valid for the next build.
fs_.RemoveFile("out.bis");
command_runner.commands_ran_.clear();
state.Reset();

// Recreate the dynout file because it is not created by the edge
fs_.Create("out.dynout", "out.bis\n");
EXPECT_TRUE(builder.AddTarget("out", &err));
EXPECT_TRUE(builder.Build(&err));
ASSERT_EQ("", err);
ASSERT_EQ(1u, command_runner.commands_ran_.size());

builder.command_runner_.release();
deps_log.Close();
}

RealDiskInterface disk_interface;
disk_interface.RemoveFile("ninja_deps");
}

TEST_F(BuildTest, RebuildMissingDynamicOutputsWithRestat) {
string err;

FakeCommandRunner command_runner(&fs_);
BuildLog build_log;
State state;
DepsLog deps_log;
ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
ASSERT_EQ("", err);
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
builder.command_runner_.reset(&command_runner);

ASSERT_NO_FATAL_FAILURE(
AssertParse(&state,
"rule cp-plus-bis\n"
" command = cp $in $out && cp $in $out.bis\n"
" dynout = $out.dynout\n"
" restat = 1\n"
"build out: cp-plus-bis in\n"));

fs_.Tick();
fs_.Create("in", "");
fs_.Tick();
fs_.Create("out.dynout", "out.bis\n");
fs_.Tick();

EXPECT_TRUE(builder.AddTarget("out", &err));
EXPECT_TRUE(builder.Build(&err));
ASSERT_EQ("", err);
ASSERT_EQ(1u, command_runner.commands_ran_.size());
ASSERT_GT(fs_.Stat("out", &err), 0);
ASSERT_GT(fs_.Stat("out.bis", &err), 0);
// Make sure the dynout file has been removed after its
// information has been extracted in the deps log.
ASSERT_EQ(fs_.Stat("out.dynout", &err), 0);

// all clean, no rebuild.
command_runner.commands_ran_.clear();
state.Reset();
EXPECT_TRUE(builder.AddTarget("out", &err));
EXPECT_EQ("", err);
EXPECT_TRUE(builder.AlreadyUpToDate());

fs_.RemoveFile("out.bis");
command_runner.commands_ran_.clear();
state.Reset();

// Recreate the dynout file because it is not created by the edge
fs_.Create("out.dynout", "out.bis\n");
EXPECT_TRUE(builder.AddTarget("out", &err));
EXPECT_TRUE(builder.Build(&err));
ASSERT_EQ("", err);
ASSERT_EQ(1u, command_runner.commands_ran_.size());

// Make sure the dynout file has been removed after its
// information has been extracted in the deps log.
ASSERT_EQ(fs_.Stat("out.dynout", &err), 0);

builder.command_runner_.release();

deps_log.Close();
RealDiskInterface disk_interface;
disk_interface.RemoveFile("ninja_deps");
}
34 changes: 34 additions & 0 deletions src/clean_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -619,4 +619,38 @@ TEST_F(CleanDeadTest, CleanDeadPreservesInputs) {
EXPECT_NE(0, fs_.Stat("out2", &err));
log2.Close();
}

TEST_F(CleanTest, CleanDynamicOutputs) {
ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
"rule cp-plus-bis\n"
" command = cp $in $out && cp $in $out.bis\n"
" dynout = $out.dynout\n"
"build out: cp-plus-bis in\n"
));
fs_.Create("out", "");
fs_.Create("out.bis", "");

string err;
DepsLog deps_log;
ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
ASSERT_EQ("", err);
Node* out = state_.LookupNode("out");
std::vector<Node*> nodes;
Node* out_bis = state_.GetNode("out.bis", 0);
nodes.push_back(out_bis);
deps_log.RecordDeps(out, 0, nodes, 1);

Cleaner cleaner(&state_, config_, &fs_, &deps_log);
EXPECT_EQ(0, cleaner.CleanAll());
EXPECT_EQ(2, cleaner.cleaned_files_count());
EXPECT_EQ(2u, fs_.files_removed_.size());

EXPECT_EQ(0, fs_.Stat("out", &err));
EXPECT_EQ(0, fs_.Stat("out.bis", &err));

deps_log.Close();
RealDiskInterface disk_interface;
disk_interface.RemoveFile("ninja_deps");
}

} // anonymous namespace
7 changes: 5 additions & 2 deletions src/deps_log_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ TEST_F(DepsLogTest, WriteRead) {
vector<Node*> deps;
deps.push_back(state1.GetNode("foo.h", 0));
deps.push_back(state1.GetNode("bar.h", 0));
log1.RecordDeps(state1.GetNode("out.o", 0), 1, deps);
deps.push_back(state1.GetNode("out.bis", 0));
log1.RecordDeps(state1.GetNode("out.o", 0), 1, deps, 1);

deps.clear();
deps.push_back(state1.GetNode("foo.h", 0));
Expand All @@ -60,9 +61,11 @@ TEST_F(DepsLogTest, WriteRead) {
DepsLog::Deps* log_deps = log1.GetDeps(state1.GetNode("out.o", 0));
ASSERT_TRUE(log_deps);
ASSERT_EQ(1, log_deps->mtime);
ASSERT_EQ(2, log_deps->node_count);
ASSERT_EQ(3, log_deps->node_count);
ASSERT_EQ(1, log_deps->outputs_count);
ASSERT_EQ("foo.h", log_deps->nodes[0]->path());
ASSERT_EQ("bar.h", log_deps->nodes[1]->path());
ASSERT_EQ("out.bis", log_deps->nodes[2]->path());
}

log1.Close();
Expand Down
1 change: 1 addition & 0 deletions src/manifest_parser_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ TEST_F(ParserTest, RuleAttributes) {
" command = a\n"
" depfile = a\n"
" deps = a\n"
" dynout = a\n"
" description = a\n"
" generator = a\n"
" restat = a\n"
Expand Down

0 comments on commit f4e6b51

Please sign in to comment.