#include <memory>
#include "deps_log.h"
#include "graph.h"
#include "missing_deps.h"
#include "state.h"
#include "test.h"
const char kTestDepsLogFilename[] = "MissingDepTest-tempdepslog";
class MissingDependencyTestDelegate : public MissingDependencyScannerDelegate {
void OnMissingDep(Node* node, const std::string& path,
const Rule& generator) {}
};
struct MissingDependencyScannerTest : public testing::Test {
MissingDependencyScannerTest()
: generator_rule_("generator_rule"), compile_rule_("compile_rule"),
scanner_(&delegate_, &deps_log_, &state_, &filesystem_) {
std::string err;
deps_log_.OpenForWrite(kTestDepsLogFilename, &err);
ASSERT_EQ("", err);
}
MissingDependencyScanner& scanner() { return scanner_; }
void RecordDepsLogDep(const std::string& from, const std::string& to) {
Node* node_deps[] = { state_.LookupNode(to) };
deps_log_.RecordDeps(state_.LookupNode(from), 0, 1, node_deps);
}
void ProcessAllNodes() {
std::string err;
std::vector<Node*> nodes = state_.RootNodes(&err);
EXPECT_EQ("", err);
for (std::vector<Node*>::iterator it = nodes.begin(); it != nodes.end();
++it) {
scanner().ProcessNode(*it);
}
}
void CreateInitialState() {
EvalString deps_type;
deps_type.AddText("gcc");
compile_rule_.AddBinding("deps", deps_type);
generator_rule_.AddBinding("deps", deps_type);
Edge* header_edge = state_.AddEdge(&generator_rule_);
state_.AddOut(header_edge, "generated_header", 0);
Edge* compile_edge = state_.AddEdge(&compile_rule_);
state_.AddOut(compile_edge, "compiled_object", 0);
}
void CreateGraphDependencyBetween(const char* from, const char* to) {
Node* from_node = state_.LookupNode(from);
Edge* from_edge = from_node->in_edge();
state_.AddIn(from_edge, to, 0);
}
void AssertMissingDependencyBetween(const char* flaky, const char* generated,
Rule* rule) {
Node* flaky_node = state_.LookupNode(flaky);
ASSERT_EQ(1u, scanner().nodes_missing_deps_.count(flaky_node));
Node* generated_node = state_.LookupNode(generated);
ASSERT_EQ(1u, scanner().generated_nodes_.count(generated_node));
ASSERT_EQ(1u, scanner().generator_rules_.count(rule));
}
MissingDependencyTestDelegate delegate_;
Rule generator_rule_;
Rule compile_rule_;
DepsLog deps_log_;
State state_;
VirtualFileSystem filesystem_;
MissingDependencyScanner scanner_;
};
TEST_F(MissingDependencyScannerTest, EmptyGraph) {
ProcessAllNodes();
ASSERT_FALSE(scanner().HadMissingDeps());
}
TEST_F(MissingDependencyScannerTest, NoMissingDep) {
CreateInitialState();
ProcessAllNodes();
ASSERT_FALSE(scanner().HadMissingDeps());
}
TEST_F(MissingDependencyScannerTest, MissingDepPresent) {
CreateInitialState();
RecordDepsLogDep("compiled_object", "generated_header");
ProcessAllNodes();
ASSERT_TRUE(scanner().HadMissingDeps());
ASSERT_EQ(1u, scanner().nodes_missing_deps_.size());
ASSERT_EQ(1u, scanner().missing_dep_path_count_);
AssertMissingDependencyBetween("compiled_object", "generated_header",
&generator_rule_);
}
TEST_F(MissingDependencyScannerTest, MissingDepFixedDirect) {
CreateInitialState();
CreateGraphDependencyBetween("compiled_object", "generated_header");
RecordDepsLogDep("compiled_object", "generated_header");
ProcessAllNodes();
ASSERT_FALSE(scanner().HadMissingDeps());
}
TEST_F(MissingDependencyScannerTest, MissingDepFixedIndirect) {
CreateInitialState();
Edge* intermediate_edge = state_.AddEdge(&generator_rule_);
state_.AddOut(intermediate_edge, "intermediate", 0);
CreateGraphDependencyBetween("compiled_object", "intermediate");
CreateGraphDependencyBetween("intermediate", "generated_header");
RecordDepsLogDep("compiled_object", "generated_header");
ProcessAllNodes();
ASSERT_FALSE(scanner().HadMissingDeps());
}
TEST_F(MissingDependencyScannerTest, CyclicMissingDep) {
CreateInitialState();
RecordDepsLogDep("generated_header", "compiled_object");
RecordDepsLogDep("compiled_object", "generated_header");
ProcessAllNodes();
ASSERT_TRUE(scanner().HadMissingDeps());
ASSERT_EQ(2u, scanner().nodes_missing_deps_.size());
ASSERT_EQ(2u, scanner().missing_dep_path_count_);
AssertMissingDependencyBetween("compiled_object", "generated_header",
&generator_rule_);
AssertMissingDependencyBetween("generated_header", "compiled_object",
&compile_rule_);
}
TEST_F(MissingDependencyScannerTest, CycleInGraph) {
CreateInitialState();
CreateGraphDependencyBetween("compiled_object", "generated_header");
CreateGraphDependencyBetween("generated_header", "compiled_object");
std::string err;
std::vector<Node*> nodes = state_.RootNodes(&err);
ASSERT_NE("", err);
}