summaryrefslogtreecommitdiffstats
path: root/src/build_test.cc
diff options
context:
space:
mode:
authorNico Weber <nicolasweber@gmx.de>2015-06-29 17:21:30 (GMT)
committerNico Weber <nicolasweber@gmx.de>2015-06-29 17:21:30 (GMT)
commit484c16336f19bd8970bb6e75322d61b92a229899 (patch)
tree2a8908981381da57e3f9ef3a01a8008b930f86f9 /src/build_test.cc
parent3309498174411e02e7680ea8b470bb7d1d70bdb8 (diff)
parentd18eda4c3ed7d81c3f8d6d46972a0988f1ebb05e (diff)
downloadNinja-484c16336f19bd8970bb6e75322d61b92a229899.zip
Ninja-484c16336f19bd8970bb6e75322d61b92a229899.tar.gz
Ninja-484c16336f19bd8970bb6e75322d61b92a229899.tar.bz2
v1.6.0v1.6.0
Diffstat (limited to 'src/build_test.cc')
-rw-r--r--src/build_test.cc146
1 files changed, 121 insertions, 25 deletions
diff --git a/src/build_test.cc b/src/build_test.cc
index bd1cd30..52a17c9 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -51,9 +51,9 @@ struct PlanTest : public StateTestWithBuiltinRules {
};
TEST_F(PlanTest, Basic) {
- AssertParse(&state_,
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
"build out: cat mid\n"
-"build mid: cat in\n");
+"build mid: cat in\n"));
GetNode("mid")->MarkDirty();
GetNode("out")->MarkDirty();
string err;
@@ -84,9 +84,9 @@ TEST_F(PlanTest, Basic) {
// Test that two outputs from one rule can be handled as inputs to the next.
TEST_F(PlanTest, DoubleOutputDirect) {
- AssertParse(&state_,
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
"build out: cat mid1 mid2\n"
-"build mid1 mid2: cat in\n");
+"build mid1 mid2: cat in\n"));
GetNode("mid1")->MarkDirty();
GetNode("mid2")->MarkDirty();
GetNode("out")->MarkDirty();
@@ -111,11 +111,11 @@ TEST_F(PlanTest, DoubleOutputDirect) {
// Test that two outputs from one rule can eventually be routed to another.
TEST_F(PlanTest, DoubleOutputIndirect) {
- AssertParse(&state_,
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
"build out: cat b1 b2\n"
"build b1: cat a1\n"
"build b2: cat a2\n"
-"build a1 a2: cat in\n");
+"build a1 a2: cat in\n"));
GetNode("a1")->MarkDirty();
GetNode("a2")->MarkDirty();
GetNode("b1")->MarkDirty();
@@ -149,11 +149,11 @@ TEST_F(PlanTest, DoubleOutputIndirect) {
// Test that two edges from one output can both execute.
TEST_F(PlanTest, DoubleDependent) {
- AssertParse(&state_,
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
"build out: cat a1 a2\n"
"build a1: cat mid\n"
"build a2: cat mid\n"
-"build mid: cat in\n");
+"build mid: cat in\n"));
GetNode("mid")->MarkDirty();
GetNode("a1")->MarkDirty();
GetNode("a2")->MarkDirty();
@@ -186,11 +186,11 @@ TEST_F(PlanTest, DoubleDependent) {
}
TEST_F(PlanTest, DependencyCycle) {
- AssertParse(&state_,
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
"build out: cat mid\n"
"build mid: cat in\n"
"build in: cat pre\n"
-"build pre: cat out\n");
+"build pre: cat out\n"));
GetNode("out")->MarkDirty();
GetNode("mid")->MarkDirty();
GetNode("in")->MarkDirty();
@@ -201,6 +201,43 @@ TEST_F(PlanTest, DependencyCycle) {
ASSERT_EQ("dependency cycle: out -> mid -> in -> pre -> out", err);
}
+TEST_F(PlanTest, CycleInEdgesButNotInNodes1) {
+ string err;
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"build a b: cat a\n"));
+ EXPECT_FALSE(plan_.AddTarget(GetNode("b"), &err));
+ ASSERT_EQ("dependency cycle: a -> a", err);
+}
+
+TEST_F(PlanTest, CycleInEdgesButNotInNodes2) {
+ string err;
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"build b a: cat a\n"));
+ EXPECT_FALSE(plan_.AddTarget(GetNode("b"), &err));
+ ASSERT_EQ("dependency cycle: a -> a", err);
+}
+
+TEST_F(PlanTest, CycleInEdgesButNotInNodes3) {
+ string err;
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"build a b: cat c\n"
+"build c: cat a\n"));
+ EXPECT_FALSE(plan_.AddTarget(GetNode("b"), &err));
+ ASSERT_EQ("dependency cycle: c -> a -> c", err);
+}
+
+TEST_F(PlanTest, CycleInEdgesButNotInNodes4) {
+ string err;
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"build d: cat c\n"
+"build c: cat b\n"
+"build b: cat a\n"
+"build a e: cat d\n"
+"build f: cat e\n"));
+ EXPECT_FALSE(plan_.AddTarget(GetNode("f"), &err));
+ ASSERT_EQ("dependency cycle: d -> c -> b -> a -> d", err);
+}
+
void PlanTest::TestPoolWithDepthOne(const char* test_case) {
ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, test_case));
GetNode("out1")->MarkDirty();
@@ -458,8 +495,8 @@ struct BuildTest : public StateTestWithBuiltinRules, public BuildLogUser {
/// 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);
+ const char* log_path = NULL, const char* deps_path = NULL,
+ State* state = NULL);
// Mark a path dirty.
void Dirty(const string& path);
@@ -479,10 +516,13 @@ struct BuildTest : public StateTestWithBuiltinRules, public BuildLogUser {
};
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);
+ const char* log_path, const char* deps_path,
+ State* state) {
+ State local_state, *pstate = &local_state;
+ if (state)
+ pstate = state;
+ ASSERT_NO_FATAL_FAILURE(AddCatRule(pstate));
+ AssertParse(pstate, manifest);
string err;
BuildLog build_log, *pbuild_log = NULL;
@@ -495,13 +535,13 @@ void BuildTest::RebuildTarget(const string& target, const char* manifest,
DepsLog deps_log, *pdeps_log = NULL;
if (deps_path) {
- ASSERT_TRUE(deps_log.Load(deps_path, &state, &err));
+ ASSERT_TRUE(deps_log.Load(deps_path, pstate, &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_);
+ Builder builder(pstate, config_, pbuild_log, pdeps_log, &fs_);
EXPECT_TRUE(builder.AddTarget(target, &err));
command_runner_.commands_ran_.clear();
@@ -816,8 +856,7 @@ TEST_F(BuildTest, DepFileParseError) {
fs_.Create("foo.c", "");
fs_.Create("foo.o.d", "randomtext\n");
EXPECT_FALSE(builder_.AddTarget("foo.o", &err));
- EXPECT_EQ("expected depfile 'foo.o.d' to mention 'foo.o', got 'randomtext'",
- err);
+ EXPECT_EQ("foo.o.d: expected ':' in depfile", err);
}
TEST_F(BuildTest, OrderOnlyDeps) {
@@ -1056,6 +1095,31 @@ TEST_F(BuildTest, SwallowFailuresLimit) {
ASSERT_EQ("cannot make progress due to previous errors", err);
}
+TEST_F(BuildTest, PoolEdgesReadyButNotWanted) {
+ fs_.Create("x", "");
+
+ const char* manifest =
+ "pool some_pool\n"
+ " depth = 4\n"
+ "rule touch\n"
+ " command = touch $out\n"
+ " pool = some_pool\n"
+ "rule cc\n"
+ " command = touch grit\n"
+ "\n"
+ "build B.d.stamp: cc | x\n"
+ "build C.stamp: touch B.d.stamp\n"
+ "build final.stamp: touch || C.stamp\n";
+
+ RebuildTarget("final.stamp", manifest);
+
+ fs_.RemoveFile("B.d.stamp");
+
+ State save_state;
+ RebuildTarget("final.stamp", manifest, NULL, NULL, &save_state);
+ EXPECT_GE(save_state.LookupPool("some_pool")->current_use(), 0);
+}
+
struct BuildWithLogTest : public BuildTest {
BuildWithLogTest() {
builder_.SetBuildLog(&build_log_);
@@ -1414,7 +1478,7 @@ TEST_F(BuildTest, RspFileFailure) {
ASSERT_EQ("Another very long command", fs_.files_["out.rsp"].contents);
}
-// Test that contens of the RSP file behaves like a regular part of
+// Test that contents of the RSP file behaves like a regular part of
// command line, i.e. triggers a rebuild if changed
TEST_F(BuildWithLogTest, RspFileCmdLineChange) {
ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
@@ -1484,7 +1548,7 @@ TEST_F(BuildTest, InterruptCleanup) {
EXPECT_FALSE(builder_.Build(&err));
EXPECT_EQ("interrupted by user", err);
builder_.Cleanup();
- EXPECT_GT(fs_.Stat("out1"), 0);
+ EXPECT_GT(fs_.Stat("out1", &err), 0);
err = "";
// A touched output of an interrupted command should be deleted.
@@ -1493,7 +1557,22 @@ TEST_F(BuildTest, InterruptCleanup) {
EXPECT_FALSE(builder_.Build(&err));
EXPECT_EQ("interrupted by user", err);
builder_.Cleanup();
- EXPECT_EQ(0, fs_.Stat("out2"));
+ EXPECT_EQ(0, fs_.Stat("out2", &err));
+}
+
+TEST_F(BuildTest, StatFailureAbortsBuild) {
+ const string kTooLongToStat(400, 'i');
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+("build " + kTooLongToStat + ": cat " + kTooLongToStat + "\n").c_str()));
+ // Also cyclic, for good measure.
+
+ // This simulates a stat failure:
+ fs_.files_[kTooLongToStat].mtime = -1;
+ fs_.files_[kTooLongToStat].stat_error = "stat failed";
+
+ string err;
+ EXPECT_FALSE(builder_.AddTarget(kTooLongToStat, &err));
+ EXPECT_EQ("stat failed", err);
}
TEST_F(BuildTest, PhonyWithNoInputs) {
@@ -1613,7 +1692,7 @@ TEST_F(BuildWithDepsLogTest, Straightforward) {
EXPECT_EQ("", err);
// The deps file should have been removed.
- EXPECT_EQ(0, fs_.Stat("in1.d"));
+ EXPECT_EQ(0, fs_.Stat("in1.d", &err));
// Recreate it for the next step.
fs_.Create("in1.d", "out: in2");
deps_log.Close();
@@ -1693,7 +1772,7 @@ TEST_F(BuildWithDepsLogTest, ObsoleteDeps) {
fs_.Create("out", "");
// The deps file should have been removed, so no need to timestamp it.
- EXPECT_EQ(0, fs_.Stat("in1.d"));
+ EXPECT_EQ(0, fs_.Stat("in1.d", &err));
{
State state;
@@ -2043,6 +2122,23 @@ TEST_F(BuildWithDepsLogTest, RestatMissingDepfileDepslog) {
ASSERT_EQ(0u, command_runner_.commands_ran_.size());
}
+TEST_F(BuildTest, WrongOutputInDepfileCausesRebuild) {
+ string err;
+ const char* manifest =
+"rule cc\n"
+" command = cc $in\n"
+" depfile = $out.d\n"
+"build foo.o: cc foo.c\n";
+
+ fs_.Create("foo.c", "");
+ fs_.Create("foo.o", "");
+ fs_.Create("header.h", "");
+ fs_.Create("foo.o.d", "bar.o.d: header.h\n");
+
+ RebuildTarget("foo.o", manifest, "build_log", "ninja_deps");
+ ASSERT_EQ(1u, command_runner_.commands_ran_.size());
+}
+
TEST_F(BuildTest, Console) {
ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
"rule console\n"