summaryrefslogtreecommitdiffstats
path: root/src/test.cc
diff options
context:
space:
mode:
authorNico Weber <nicolasweber@gmx.de>2015-03-15 23:34:03 (GMT)
committerNico Weber <nicolasweber@gmx.de>2015-03-15 23:34:03 (GMT)
commit56e9d08c028d2c16f787041dc1f41271464a8bdc (patch)
tree7c666efb09121fba46787e3bd3b47bf28ddeb5f2 /src/test.cc
parent51f06facf46e7a1a5338a4ca2ec9b8441c44c405 (diff)
downloadNinja-56e9d08c028d2c16f787041dc1f41271464a8bdc.zip
Ninja-56e9d08c028d2c16f787041dc1f41271464a8bdc.tar.gz
Ninja-56e9d08c028d2c16f787041dc1f41271464a8bdc.tar.bz2
Build self-consistent graphs for dupe edges with multiple outputs.
Fixes #867, both the crashes and "[stuck]" issues. The problem was that a duplicate edge would modify the in_edge of the outputs of the new build rule, but the edge corresponding to the old build rule would still think that the in_edge points to itself. `old_edge->outputs_[0]->in_edge()` would not return `old_edge`, which confused the scan logic. As fix, let `State::AddOut()` reject changing in_edge if it's already set. This changes behavior in a minor way: Previously, if there were multiple edges for a single output, the last edge would be kept. Now, the first edge is kept. This only had mostly-well-defined semantics if all duplicate edges are the same (which is the only case I've seen in practice), and for that case the behavior doesn't change. For testing, add a VerifyGraph() function and call that every time any test graph is parsed. That's a bit more code than just copying the test cases from the bug into build_test.cc, but it also yields better test coverage overall.
Diffstat (limited to 'src/test.cc')
-rw-r--r--src/test.cc22
1 files changed, 22 insertions, 0 deletions
diff --git a/src/test.cc b/src/test.cc
index f667fef..76b8416 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -28,6 +28,7 @@
#endif
#include "build_log.h"
+#include "graph.h"
#include "manifest_parser.h"
#include "util.h"
@@ -98,12 +99,33 @@ void AssertParse(State* state, const char* input) {
string err;
EXPECT_TRUE(parser.ParseTest(input, &err));
ASSERT_EQ("", err);
+ VerifyGraph(*state);
}
void AssertHash(const char* expected, uint64_t actual) {
ASSERT_EQ(BuildLog::LogEntry::HashCommand(expected), actual);
}
+void VerifyGraph(const State& state) {
+ for (vector<Edge*>::const_iterator e = state.edges_.begin();
+ e != state.edges_.end(); ++e) {
+ // All edges need at least one output.
+ EXPECT_FALSE((*e)->outputs_.empty());
+ // Check that the edge's inputs have the edge as out edge.
+ for (vector<Node*>::const_iterator in_node = (*e)->inputs_.begin();
+ in_node != (*e)->inputs_.end(); ++in_node) {
+ const vector<Edge*>& out_edges = (*in_node)->out_edges();
+ EXPECT_NE(std::find(out_edges.begin(), out_edges.end(), *e),
+ out_edges.end());
+ }
+ // Check that the edge's outputs have the edge as in edge.
+ for (vector<Node*>::const_iterator out_node = (*e)->outputs_.begin();
+ out_node != (*e)->outputs_.end(); ++out_node) {
+ EXPECT_EQ((*out_node)->in_edge(), *e);
+ }
+ }
+}
+
void VirtualFileSystem::Create(const string& path,
const string& contents) {
files_[path].mtime = now_;