summaryrefslogtreecommitdiff
path: root/ninja/src/build_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ninja/src/build_test.cc')
-rw-r--r--ninja/src/build_test.cc129
1 files changed, 125 insertions, 4 deletions
diff --git a/ninja/src/build_test.cc b/ninja/src/build_test.cc
index d1ac0efb8bb..86a911bd281 100644
--- a/ninja/src/build_test.cc
+++ b/ninja/src/build_test.cc
@@ -412,7 +412,7 @@ struct FakeCommandRunner : public CommandRunner {
VirtualFileSystem* fs_;
};
-struct BuildTest : public StateTestWithBuiltinRules {
+struct BuildTest : public StateTestWithBuiltinRules, public BuildLogUser {
BuildTest() : config_(MakeConfig()), command_runner_(&fs_),
builder_(&state_, config_, NULL, NULL, &fs_),
status_(config_) {
@@ -435,6 +435,15 @@ struct BuildTest : public StateTestWithBuiltinRules {
builder_.command_runner_.release();
}
+ virtual bool IsPathDead(StringPiece s) const { return false; }
+
+ /// Rebuild target in the 'working tree' (fs_).
+ /// State of command_runner_ and logs contents (if specified) ARE MODIFIED.
+ /// Handy to check for NOOP builds, and higher-level rebuild tests.
+ void RebuildTarget(const string& target, const char* manifest,
+ const char* log_path = NULL,
+ const char* deps_path = NULL);
+
// Mark a path dirty.
void Dirty(const string& path);
@@ -452,6 +461,41 @@ struct BuildTest : public StateTestWithBuiltinRules {
BuildStatus status_;
};
+void BuildTest::RebuildTarget(const string& target, const char* manifest,
+ const char* log_path, const char* deps_path) {
+ State state;
+ ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
+ AssertParse(&state, manifest);
+
+ string err;
+ BuildLog build_log, *pbuild_log = NULL;
+ if (log_path) {
+ ASSERT_TRUE(build_log.Load(log_path, &err));
+ ASSERT_TRUE(build_log.OpenForWrite(log_path, *this, &err));
+ ASSERT_EQ("", err);
+ pbuild_log = &build_log;
+ }
+
+ DepsLog deps_log, *pdeps_log = NULL;
+ if (deps_path) {
+ ASSERT_TRUE(deps_log.Load(deps_path, &state, &err));
+ ASSERT_TRUE(deps_log.OpenForWrite(deps_path, &err));
+ ASSERT_EQ("", err);
+ pdeps_log = &deps_log;
+ }
+
+ Builder builder(&state, config_, pbuild_log, pdeps_log, &fs_);
+ EXPECT_TRUE(builder.AddTarget(target, &err));
+
+ command_runner_.commands_ran_.clear();
+ builder.command_runner_.reset(&command_runner_);
+ if (!builder.AlreadyUpToDate()) {
+ bool build_res = builder.Build(&err);
+ EXPECT_TRUE(build_res) << "builder.Build(&err)";
+ }
+ builder.command_runner_.release();
+}
+
bool FakeCommandRunner::CanRunMore() {
// Only run one at a time.
return last_command_ == NULL;
@@ -1018,6 +1062,7 @@ TEST_F(BuildWithLogTest, RestatTest) {
ASSERT_EQ("", err);
EXPECT_TRUE(builder_.Build(&err));
ASSERT_EQ("", err);
+ EXPECT_EQ("[3/3]", builder_.status_->FormatProgressStatus("[%s/%t]"));
command_runner_.commands_ran_.clear();
state_.Reset();
@@ -1166,7 +1211,7 @@ TEST_F(BuildWithLogTest, RestatMissingInput) {
// See that an entry in the logfile is created, capturing
// the right mtime
- BuildLog::LogEntry * log_entry = build_log_.LookupByOutput("out1");
+ BuildLog::LogEntry* log_entry = build_log_.LookupByOutput("out1");
ASSERT_TRUE(NULL != log_entry);
ASSERT_EQ(restat_mtime, log_entry->restat_mtime);
@@ -1337,7 +1382,7 @@ TEST_F(BuildWithLogTest, RspFileCmdLineChange) {
// 3. Alter the entry in the logfile
// (to simulate a change in the command line between 2 builds)
- BuildLog::LogEntry * log_entry = build_log_.LookupByOutput("out");
+ BuildLog::LogEntry* log_entry = build_log_.LookupByOutput("out");
ASSERT_TRUE(NULL != log_entry);
ASSERT_NO_FATAL_FAILURE(AssertHash(
"cat out.rsp > out;rspfile=Original very long command",
@@ -1779,7 +1824,7 @@ TEST_F(BuildWithDepsLogTest, DepFileOKDepsLog) {
// Expect three new edges: one generating foo.o, and two more from
// loading the depfile.
- ASSERT_EQ(3, (int)state.edges_.size());
+ ASSERT_EQ(3u, state.edges_.size());
// Expect our edge to now have three inputs: foo.c and two headers.
ASSERT_EQ(3u, edge->inputs_.size());
@@ -1790,3 +1835,79 @@ TEST_F(BuildWithDepsLogTest, DepFileOKDepsLog) {
builder.command_runner_.release();
}
}
+
+/// Check that a restat rule doesn't clear an edge if the depfile is missing.
+/// Follows from: https://github.com/martine/ninja/issues/603
+TEST_F(BuildTest, RestatMissingDepfile) {
+const char* manifest =
+"rule true\n"
+" command = true\n" // Would be "write if out-of-date" in reality.
+" restat = 1\n"
+"build header.h: true header.in\n"
+"build out: cat header.h\n"
+" depfile = out.d\n";
+
+ fs_.Create("header.h", "");
+ fs_.Tick();
+ fs_.Create("out", "");
+ fs_.Create("header.in", "");
+
+ // Normally, only 'header.h' would be rebuilt, as
+ // its rule doesn't touch the output and has 'restat=1' set.
+ // But we are also missing the depfile for 'out',
+ // which should force its command to run anyway!
+ RebuildTarget("out", manifest);
+ ASSERT_EQ(2u, command_runner_.commands_ran_.size());
+}
+
+/// Check that a restat rule doesn't clear an edge if the deps are missing.
+/// https://github.com/martine/ninja/issues/603
+TEST_F(BuildWithDepsLogTest, RestatMissingDepfileDepslog) {
+ string err;
+ const char* manifest =
+"rule true\n"
+" command = true\n" // Would be "write if out-of-date" in reality.
+" restat = 1\n"
+"build header.h: true header.in\n"
+"build out: cat header.h\n"
+" deps = gcc\n"
+" depfile = out.d\n";
+
+ // Build once to populate ninja deps logs from out.d
+ fs_.Create("header.in", "");
+ fs_.Create("out.d", "out: header.h");
+ fs_.Create("header.h", "");
+
+ RebuildTarget("out", manifest, "build_log", "ninja_deps");
+ ASSERT_EQ(2u, command_runner_.commands_ran_.size());
+
+ // Sanity: this rebuild should be NOOP
+ RebuildTarget("out", manifest, "build_log", "ninja_deps");
+ ASSERT_EQ(0u, command_runner_.commands_ran_.size());
+
+ // Touch 'header.in', blank dependencies log (create a different one).
+ // Building header.h triggers 'restat' outputs cleanup.
+ // Validate that out is rebuilt netherless, as deps are missing.
+ fs_.Tick();
+ fs_.Create("header.in", "");
+
+ // (switch to a new blank deps_log "ninja_deps2")
+ RebuildTarget("out", manifest, "build_log", "ninja_deps2");
+ ASSERT_EQ(2u, command_runner_.commands_ran_.size());
+
+ // Sanity: this build should be NOOP
+ RebuildTarget("out", manifest, "build_log", "ninja_deps2");
+ ASSERT_EQ(0u, command_runner_.commands_ran_.size());
+
+ // Check that invalidating deps by target timestamp also works here
+ // Repeat the test but touch target instead of blanking the log.
+ fs_.Tick();
+ fs_.Create("header.in", "");
+ fs_.Create("out", "");
+ RebuildTarget("out", manifest, "build_log", "ninja_deps2");
+ ASSERT_EQ(2u, command_runner_.commands_ran_.size());
+
+ // And this build should be NOOP again
+ RebuildTarget("out", manifest, "build_log", "ninja_deps2");
+ ASSERT_EQ(0u, command_runner_.commands_ran_.size());
+}