Skip to content

Commit f4e6b51

Browse files
Add tests for dynamic outputs
Co-authored-by: Marc Delorme <[email protected]>
1 parent 60a21e7 commit f4e6b51

File tree

4 files changed

+222
-2
lines changed

4 files changed

+222
-2
lines changed

src/build_test.cc

+182
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,18 @@ bool FakeCommandRunner::StartCommand(Edge* edge) {
609609
if (fs_->ReadFile(edge->inputs_[0]->path(), &content, &err) ==
610610
DiskInterface::Okay)
611611
fs_->WriteFile(edge->outputs_[0]->path(), content);
612+
} else if (edge->rule().name() == "cp-plus-bis") {
613+
assert(!edge->inputs_.empty());
614+
assert(edge->outputs_.size() >= 1);
615+
string content;
616+
string err;
617+
if (fs_->ReadFile(edge->inputs_[0]->path(), &content, &err) ==
618+
DiskInterface::Okay) {
619+
fs_->Tick();
620+
fs_->WriteFile(edge->outputs_[0]->path() + ".bis", content);
621+
fs_->Tick();
622+
fs_->WriteFile(edge->outputs_[0]->path(), content);
623+
}
612624
} else if (edge->rule().name() == "touch-implicit-dep-out") {
613625
string dep = edge->GetBinding("test_dependency");
614626
fs_->Tick();
@@ -4312,3 +4324,173 @@ TEST_F(BuildTest, ValidationWithCircularDependency) {
43124324
EXPECT_FALSE(builder_.AddTarget("out", &err));
43134325
EXPECT_EQ("dependency cycle: validate -> validate_in -> validate", err);
43144326
}
4327+
4328+
TEST_F(BuildTest, RebuildMissingDynamicOutputs) {
4329+
string err;
4330+
BuildLog build_log;
4331+
4332+
{
4333+
FakeCommandRunner command_runner(&fs_);
4334+
State state;
4335+
DepsLog deps_log;
4336+
ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
4337+
ASSERT_EQ("", err);
4338+
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
4339+
builder.command_runner_.reset(&command_runner);
4340+
4341+
ASSERT_NO_FATAL_FAILURE(
4342+
AssertParse(&state,
4343+
"rule cp-plus-bis\n"
4344+
" command = cp $in $out && cp $in $out.bis\n"
4345+
" dynout = $out.dynout\n"
4346+
"build out: cp-plus-bis in\n"));
4347+
4348+
fs_.Tick();
4349+
fs_.Create("in", "");
4350+
fs_.Create("out.dynout", "out.bis\n");
4351+
4352+
EXPECT_TRUE(builder.AddTarget("out", &err));
4353+
EXPECT_TRUE(builder.Build(&err));
4354+
ASSERT_EQ("", err);
4355+
ASSERT_EQ(1u, command_runner.commands_ran_.size());
4356+
ASSERT_GT(fs_.Stat("out", &err), 0);
4357+
ASSERT_GT(fs_.Stat("out.bis", &err), 0);
4358+
// Make sure the dynout file has been removed after its
4359+
// information has been extracted in the deps log.
4360+
ASSERT_EQ(fs_.Stat("out.dynout", &err), 0);
4361+
4362+
// all clean, no rebuild.
4363+
command_runner.commands_ran_.clear();
4364+
state.Reset();
4365+
EXPECT_TRUE(builder.AddTarget("out", &err));
4366+
EXPECT_EQ("", err);
4367+
EXPECT_TRUE(builder.AlreadyUpToDate());
4368+
4369+
// Test dynamic output are rebuilt if they are deleted.
4370+
fs_.RemoveFile("out.bis");
4371+
command_runner.commands_ran_.clear();
4372+
state.Reset();
4373+
4374+
fs_.Create("out.dynout", "out.bis\n");
4375+
EXPECT_TRUE(builder.AddTarget("out", &err));
4376+
EXPECT_TRUE(builder.Build(&err));
4377+
ASSERT_EQ("", err);
4378+
ASSERT_EQ(1u, command_runner.commands_ran_.size());
4379+
4380+
builder.command_runner_.release();
4381+
deps_log.Close();
4382+
}
4383+
4384+
// Create a new state to make sure outputs are reset
4385+
{
4386+
FakeCommandRunner command_runner(&fs_);
4387+
State state;
4388+
DepsLog deps_log;
4389+
ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
4390+
ASSERT_EQ("", err);
4391+
deps_log.Load("ninja_deps", &state, &err);
4392+
ASSERT_EQ("", err);
4393+
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
4394+
builder.command_runner_.reset(&command_runner);
4395+
4396+
ASSERT_NO_FATAL_FAILURE(
4397+
AssertParse(&state,
4398+
"rule cp-plus-bis\n"
4399+
" command = cp $in $out && cp $in $out.bis\n"
4400+
" dynout = $out.dynout\n"
4401+
"build out: cp-plus-bis in\n"));
4402+
4403+
// all clean, no rebuild.
4404+
command_runner.commands_ran_.clear();
4405+
state.Reset();
4406+
EXPECT_TRUE(builder.AddTarget("out", &err));
4407+
EXPECT_EQ("", err);
4408+
EXPECT_TRUE(builder.AlreadyUpToDate());
4409+
4410+
// Test dynamic output are rebuilt if they are deleted
4411+
// after having been rebuilt in order to make sure
4412+
// when dynamic output information was already exist they
4413+
// keep being valid for the next build.
4414+
fs_.RemoveFile("out.bis");
4415+
command_runner.commands_ran_.clear();
4416+
state.Reset();
4417+
4418+
// Recreate the dynout file because it is not created by the edge
4419+
fs_.Create("out.dynout", "out.bis\n");
4420+
EXPECT_TRUE(builder.AddTarget("out", &err));
4421+
EXPECT_TRUE(builder.Build(&err));
4422+
ASSERT_EQ("", err);
4423+
ASSERT_EQ(1u, command_runner.commands_ran_.size());
4424+
4425+
builder.command_runner_.release();
4426+
deps_log.Close();
4427+
}
4428+
4429+
RealDiskInterface disk_interface;
4430+
disk_interface.RemoveFile("ninja_deps");
4431+
}
4432+
4433+
TEST_F(BuildTest, RebuildMissingDynamicOutputsWithRestat) {
4434+
string err;
4435+
4436+
FakeCommandRunner command_runner(&fs_);
4437+
BuildLog build_log;
4438+
State state;
4439+
DepsLog deps_log;
4440+
ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
4441+
ASSERT_EQ("", err);
4442+
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
4443+
builder.command_runner_.reset(&command_runner);
4444+
4445+
ASSERT_NO_FATAL_FAILURE(
4446+
AssertParse(&state,
4447+
"rule cp-plus-bis\n"
4448+
" command = cp $in $out && cp $in $out.bis\n"
4449+
" dynout = $out.dynout\n"
4450+
" restat = 1\n"
4451+
"build out: cp-plus-bis in\n"));
4452+
4453+
fs_.Tick();
4454+
fs_.Create("in", "");
4455+
fs_.Tick();
4456+
fs_.Create("out.dynout", "out.bis\n");
4457+
fs_.Tick();
4458+
4459+
EXPECT_TRUE(builder.AddTarget("out", &err));
4460+
EXPECT_TRUE(builder.Build(&err));
4461+
ASSERT_EQ("", err);
4462+
ASSERT_EQ(1u, command_runner.commands_ran_.size());
4463+
ASSERT_GT(fs_.Stat("out", &err), 0);
4464+
ASSERT_GT(fs_.Stat("out.bis", &err), 0);
4465+
// Make sure the dynout file has been removed after its
4466+
// information has been extracted in the deps log.
4467+
ASSERT_EQ(fs_.Stat("out.dynout", &err), 0);
4468+
4469+
// all clean, no rebuild.
4470+
command_runner.commands_ran_.clear();
4471+
state.Reset();
4472+
EXPECT_TRUE(builder.AddTarget("out", &err));
4473+
EXPECT_EQ("", err);
4474+
EXPECT_TRUE(builder.AlreadyUpToDate());
4475+
4476+
fs_.RemoveFile("out.bis");
4477+
command_runner.commands_ran_.clear();
4478+
state.Reset();
4479+
4480+
// Recreate the dynout file because it is not created by the edge
4481+
fs_.Create("out.dynout", "out.bis\n");
4482+
EXPECT_TRUE(builder.AddTarget("out", &err));
4483+
EXPECT_TRUE(builder.Build(&err));
4484+
ASSERT_EQ("", err);
4485+
ASSERT_EQ(1u, command_runner.commands_ran_.size());
4486+
4487+
// Make sure the dynout file has been removed after its
4488+
// information has been extracted in the deps log.
4489+
ASSERT_EQ(fs_.Stat("out.dynout", &err), 0);
4490+
4491+
builder.command_runner_.release();
4492+
4493+
deps_log.Close();
4494+
RealDiskInterface disk_interface;
4495+
disk_interface.RemoveFile("ninja_deps");
4496+
}

src/clean_test.cc

+34
Original file line numberDiff line numberDiff line change
@@ -619,4 +619,38 @@ TEST_F(CleanDeadTest, CleanDeadPreservesInputs) {
619619
EXPECT_NE(0, fs_.Stat("out2", &err));
620620
log2.Close();
621621
}
622+
623+
TEST_F(CleanTest, CleanDynamicOutputs) {
624+
ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
625+
"rule cp-plus-bis\n"
626+
" command = cp $in $out && cp $in $out.bis\n"
627+
" dynout = $out.dynout\n"
628+
"build out: cp-plus-bis in\n"
629+
));
630+
fs_.Create("out", "");
631+
fs_.Create("out.bis", "");
632+
633+
string err;
634+
DepsLog deps_log;
635+
ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
636+
ASSERT_EQ("", err);
637+
Node* out = state_.LookupNode("out");
638+
std::vector<Node*> nodes;
639+
Node* out_bis = state_.GetNode("out.bis", 0);
640+
nodes.push_back(out_bis);
641+
deps_log.RecordDeps(out, 0, nodes, 1);
642+
643+
Cleaner cleaner(&state_, config_, &fs_, &deps_log);
644+
EXPECT_EQ(0, cleaner.CleanAll());
645+
EXPECT_EQ(2, cleaner.cleaned_files_count());
646+
EXPECT_EQ(2u, fs_.files_removed_.size());
647+
648+
EXPECT_EQ(0, fs_.Stat("out", &err));
649+
EXPECT_EQ(0, fs_.Stat("out.bis", &err));
650+
651+
deps_log.Close();
652+
RealDiskInterface disk_interface;
653+
disk_interface.RemoveFile("ninja_deps");
654+
}
655+
622656
} // anonymous namespace

src/deps_log_test.cc

+5-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ TEST_F(DepsLogTest, WriteRead) {
5050
vector<Node*> deps;
5151
deps.push_back(state1.GetNode("foo.h", 0));
5252
deps.push_back(state1.GetNode("bar.h", 0));
53-
log1.RecordDeps(state1.GetNode("out.o", 0), 1, deps);
53+
deps.push_back(state1.GetNode("out.bis", 0));
54+
log1.RecordDeps(state1.GetNode("out.o", 0), 1, deps, 1);
5455

5556
deps.clear();
5657
deps.push_back(state1.GetNode("foo.h", 0));
@@ -60,9 +61,11 @@ TEST_F(DepsLogTest, WriteRead) {
6061
DepsLog::Deps* log_deps = log1.GetDeps(state1.GetNode("out.o", 0));
6162
ASSERT_TRUE(log_deps);
6263
ASSERT_EQ(1, log_deps->mtime);
63-
ASSERT_EQ(2, log_deps->node_count);
64+
ASSERT_EQ(3, log_deps->node_count);
65+
ASSERT_EQ(1, log_deps->outputs_count);
6466
ASSERT_EQ("foo.h", log_deps->nodes[0]->path());
6567
ASSERT_EQ("bar.h", log_deps->nodes[1]->path());
68+
ASSERT_EQ("out.bis", log_deps->nodes[2]->path());
6669
}
6770

6871
log1.Close();

src/manifest_parser_test.cc

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ TEST_F(ParserTest, RuleAttributes) {
6464
" command = a\n"
6565
" depfile = a\n"
6666
" deps = a\n"
67+
" dynout = a\n"
6768
" description = a\n"
6869
" generator = a\n"
6970
" restat = a\n"

0 commit comments

Comments
 (0)