Ninja
missing_deps_test.cc
Go to the documentation of this file.
1// Copyright 2019 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <memory>
16
17#include "deps_log.h"
18#include "graph.h"
19#include "missing_deps.h"
20#include "state.h"
21#include "test.h"
22
23const char kTestDepsLogFilename[] = "MissingDepTest-tempdepslog";
24
26 void OnMissingDep(Node* node, const std::string& path,
27 const Rule& generator) {}
28};
29
30struct MissingDependencyScannerTest : public testing::Test {
32 : generator_rule_("generator_rule"), compile_rule_("compile_rule"),
34 std::string err;
35 deps_log_.OpenForWrite(kTestDepsLogFilename, &err);
36 EXPECT_EQ("", err);
37 }
38
40 // Remove test file.
41 deps_log_.Close();
42 }
43
45
46 void RecordDepsLogDep(const std::string& from, const std::string& to) {
47 Node* node_deps[] = { state_.LookupNode(to) };
48 deps_log_.RecordDeps(state_.LookupNode(from), 0, 1, node_deps);
49 }
50
52 std::string err;
53 std::vector<Node*> nodes = state_.RootNodes(&err);
54 EXPECT_EQ("", err);
55 for (std::vector<Node*>::iterator it = nodes.begin(); it != nodes.end();
56 ++it) {
57 scanner().ProcessNode(*it);
58 }
59 }
60
62 EvalString deps_type;
63 deps_type.AddText("gcc");
64 compile_rule_.AddBinding("deps", deps_type);
65 generator_rule_.AddBinding("deps", deps_type);
66 Edge* header_edge = state_.AddEdge(&generator_rule_);
67 state_.AddOut(header_edge, "generated_header", 0, nullptr);
68 Edge* compile_edge = state_.AddEdge(&compile_rule_);
69 state_.AddOut(compile_edge, "compiled_object", 0, nullptr);
70 }
71
72 void CreateGraphDependencyBetween(const char* from, const char* to) {
73 Node* from_node = state_.LookupNode(from);
74 Edge* from_edge = from_node->in_edge();
75 state_.AddIn(from_edge, to, 0);
76 }
77
78 void AssertMissingDependencyBetween(const char* flaky, const char* generated,
79 Rule* rule) {
80 Node* flaky_node = state_.LookupNode(flaky);
81 ASSERT_EQ(1u, scanner().nodes_missing_deps_.count(flaky_node));
82 Node* generated_node = state_.LookupNode(generated);
83 ASSERT_EQ(1u, scanner().generated_nodes_.count(generated_node));
84 ASSERT_EQ(1u, scanner().generator_rules_.count(rule));
85 }
86
95};
96
98 ProcessAllNodes();
99 ASSERT_FALSE(scanner().HadMissingDeps());
100}
101
103 CreateInitialState();
104 ProcessAllNodes();
105 ASSERT_FALSE(scanner().HadMissingDeps());
106}
107
109 CreateInitialState();
110 // compiled_object uses generated_header, without a proper dependency
111 RecordDepsLogDep("compiled_object", "generated_header");
112 ProcessAllNodes();
113 ASSERT_TRUE(scanner().HadMissingDeps());
114 ASSERT_EQ(1u, scanner().nodes_missing_deps_.size());
115 ASSERT_EQ(1u, scanner().missing_dep_path_count_);
116 AssertMissingDependencyBetween("compiled_object", "generated_header",
117 &generator_rule_);
118}
119
120TEST_F(MissingDependencyScannerTest, MissingDepFixedDirect) {
121 CreateInitialState();
122 // Adding the direct dependency fixes the missing dep
123 CreateGraphDependencyBetween("compiled_object", "generated_header");
124 RecordDepsLogDep("compiled_object", "generated_header");
125 ProcessAllNodes();
126 ASSERT_FALSE(scanner().HadMissingDeps());
127}
128
129TEST_F(MissingDependencyScannerTest, MissingDepFixedIndirect) {
130 CreateInitialState();
131 // Adding an indirect dependency also fixes the issue
132 Edge* intermediate_edge = state_.AddEdge(&generator_rule_);
133 state_.AddOut(intermediate_edge, "intermediate", 0, nullptr);
134 CreateGraphDependencyBetween("compiled_object", "intermediate");
135 CreateGraphDependencyBetween("intermediate", "generated_header");
136 RecordDepsLogDep("compiled_object", "generated_header");
137 ProcessAllNodes();
138 ASSERT_FALSE(scanner().HadMissingDeps());
139}
140
142 CreateInitialState();
143 RecordDepsLogDep("generated_header", "compiled_object");
144 RecordDepsLogDep("compiled_object", "generated_header");
145 // In case of a cycle, both paths are reported (and there is
146 // no way to fix the issue by adding deps).
147 ProcessAllNodes();
148 ASSERT_TRUE(scanner().HadMissingDeps());
149 ASSERT_EQ(2u, scanner().nodes_missing_deps_.size());
150 ASSERT_EQ(2u, scanner().missing_dep_path_count_);
151 AssertMissingDependencyBetween("compiled_object", "generated_header",
152 &generator_rule_);
153 AssertMissingDependencyBetween("generated_header", "compiled_object",
154 &compile_rule_);
155}
156
158 CreateInitialState();
159 CreateGraphDependencyBetween("compiled_object", "generated_header");
160 CreateGraphDependencyBetween("generated_header", "compiled_object");
161 // The missing-deps tool doesn't deal with cycles in the graph, because
162 // there will be an error loading the graph before we get to the tool.
163 // This test is to illustrate that.
164 std::string err;
165 std::vector<Node*> nodes = state_.RootNodes(&err);
166 ASSERT_NE("", err);
167}
void OnMissingDep(Node *node, const std::string &path, const Rule &generator)
const char kTestDepsLogFilename[]
TEST_F(MissingDependencyScannerTest, EmptyGraph)
As build commands run they can output extra dependency information (e.g.
Definition deps_log.h:68
An edge in the dependency graph; links between Nodes using Rules.
Definition graph.h:175
A tokenized string that contains variable references.
Definition eval_env.h:35
void AddText(StringPiece text)
Definition eval_env.cc:126
MissingDependencyScanner scanner_
void CreateGraphDependencyBetween(const char *from, const char *to)
MissingDependencyTestDelegate delegate_
void AssertMissingDependencyBetween(const char *flaky, const char *generated, Rule *rule)
MissingDependencyScanner & scanner()
void RecordDepsLogDep(const std::string &from, const std::string &to)
void ProcessNode(Node *node)
Information about a node in the dependency graph: the file, whether it's dirty, mtime,...
Definition graph.h:42
Edge * in_edge() const
Definition graph.h:100
An invocable build command and associated metadata (description, etc.).
Definition eval_env.h:66
A class that records a file path and ensures that it is removed on destruction.
Definition test.h:106
Global state (file status) for a single run.
Definition state.h:95
An implementation of DiskInterface that uses an in-memory representation of disk state.
Definition test.h:51