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 
23 const char kTestDepsLogFilename[] = "MissingDepTest-tempdepslog";
24 
26  void OnMissingDep(Node* node, const std::string& path,
27  const Rule& generator) {}
28 };
29 
32  : generator_rule_("generator_rule"), compile_rule_("compile_rule"),
34  std::string err;
36  ASSERT_EQ("", err);
37  }
38 
40 
41  void RecordDepsLogDep(const std::string& from, const std::string& to) {
42  Node* node_deps[] = { state_.LookupNode(to) };
43  deps_log_.RecordDeps(state_.LookupNode(from), 0, 1, node_deps);
44  }
45 
46  void ProcessAllNodes() {
47  std::string err;
48  std::vector<Node*> nodes = state_.RootNodes(&err);
49  EXPECT_EQ("", err);
50  for (std::vector<Node*>::iterator it = nodes.begin(); it != nodes.end();
51  ++it) {
52  scanner().ProcessNode(*it);
53  }
54  }
55 
57  EvalString deps_type;
58  deps_type.AddText("gcc");
59  compile_rule_.AddBinding("deps", deps_type);
60  generator_rule_.AddBinding("deps", deps_type);
61  Edge* header_edge = state_.AddEdge(&generator_rule_);
62  state_.AddOut(header_edge, "generated_header", 0);
63  Edge* compile_edge = state_.AddEdge(&compile_rule_);
64  state_.AddOut(compile_edge, "compiled_object", 0);
65  }
66 
67  void CreateGraphDependencyBetween(const char* from, const char* to) {
68  Node* from_node = state_.LookupNode(from);
69  Edge* from_edge = from_node->in_edge();
70  state_.AddIn(from_edge, to, 0);
71  }
72 
73  void AssertMissingDependencyBetween(const char* flaky, const char* generated,
74  Rule* rule) {
75  Node* flaky_node = state_.LookupNode(flaky);
76  ASSERT_EQ(1u, scanner().nodes_missing_deps_.count(flaky_node));
77  Node* generated_node = state_.LookupNode(generated);
78  ASSERT_EQ(1u, scanner().generated_nodes_.count(generated_node));
79  ASSERT_EQ(1u, scanner().generator_rules_.count(rule));
80  }
81 
89 };
90 
92  ProcessAllNodes();
93  ASSERT_FALSE(scanner().HadMissingDeps());
94 }
95 
97  CreateInitialState();
98  ProcessAllNodes();
99  ASSERT_FALSE(scanner().HadMissingDeps());
100 }
101 
103  CreateInitialState();
104  // compiled_object uses generated_header, without a proper dependency
105  RecordDepsLogDep("compiled_object", "generated_header");
106  ProcessAllNodes();
107  ASSERT_TRUE(scanner().HadMissingDeps());
108  ASSERT_EQ(1u, scanner().nodes_missing_deps_.size());
109  ASSERT_EQ(1u, scanner().missing_dep_path_count_);
110  AssertMissingDependencyBetween("compiled_object", "generated_header",
111  &generator_rule_);
112 }
113 
114 TEST_F(MissingDependencyScannerTest, MissingDepFixedDirect) {
115  CreateInitialState();
116  // Adding the direct dependency fixes the missing dep
117  CreateGraphDependencyBetween("compiled_object", "generated_header");
118  RecordDepsLogDep("compiled_object", "generated_header");
119  ProcessAllNodes();
120  ASSERT_FALSE(scanner().HadMissingDeps());
121 }
122 
123 TEST_F(MissingDependencyScannerTest, MissingDepFixedIndirect) {
124  CreateInitialState();
125  // Adding an indirect dependency also fixes the issue
126  Edge* intermediate_edge = state_.AddEdge(&generator_rule_);
127  state_.AddOut(intermediate_edge, "intermediate", 0);
128  CreateGraphDependencyBetween("compiled_object", "intermediate");
129  CreateGraphDependencyBetween("intermediate", "generated_header");
130  RecordDepsLogDep("compiled_object", "generated_header");
131  ProcessAllNodes();
132  ASSERT_FALSE(scanner().HadMissingDeps());
133 }
134 
136  CreateInitialState();
137  RecordDepsLogDep("generated_header", "compiled_object");
138  RecordDepsLogDep("compiled_object", "generated_header");
139  // In case of a cycle, both paths are reported (and there is
140  // no way to fix the issue by adding deps).
141  ProcessAllNodes();
142  ASSERT_TRUE(scanner().HadMissingDeps());
143  ASSERT_EQ(2u, scanner().nodes_missing_deps_.size());
144  ASSERT_EQ(2u, scanner().missing_dep_path_count_);
145  AssertMissingDependencyBetween("compiled_object", "generated_header",
146  &generator_rule_);
147  AssertMissingDependencyBetween("generated_header", "compiled_object",
148  &compile_rule_);
149 }
150 
152  CreateInitialState();
153  CreateGraphDependencyBetween("compiled_object", "generated_header");
154  CreateGraphDependencyBetween("generated_header", "compiled_object");
155  // The missing-deps tool doesn't deal with cycles in the graph, because
156  // there will be an error loading the graph before we get to the tool.
157  // This test is to illustrate that.
158  std::string err;
159  std::vector<Node*> nodes = state_.RootNodes(&err);
160  ASSERT_NE("", err);
161 }
162 
void AssertMissingDependencyBetween(const char *flaky, const char *generated, Rule *rule)
An implementation of DiskInterface that uses an in-memory representation of disk state.
Definition: test.h:134
Edge * in_edge() const
Definition: graph.h:104
void RecordDepsLogDep(const std::string &from, const std::string &to)
Information about a node in the dependency graph: the file, whether it&#39;s dirty, mtime, etc.
Definition: graph.h:39
void AddIn(Edge *edge, StringPiece path, uint64_t slash_bits)
Definition: state.cc:129
MissingDependencyScanner & scanner()
An edge in the dependency graph; links between Nodes using Rules.
Definition: graph.h:164
Node * LookupNode(StringPiece path) const
Definition: state.cc:105
std::vector< Node * > RootNodes(std::string *error) const
Definition: state.cc:160
void OnMissingDep(Node *node, const std::string &path, const Rule &generator)
Edge * AddEdge(const Rule *rule)
Definition: state.cc:86
As build commands run they can output extra dependency information (e.g.
Definition: deps_log.h:68
void ProcessNode(Node *node)
Definition: missing_deps.cc:78
bool AddOut(Edge *edge, StringPiece path, uint64_t slash_bits)
Definition: state.cc:135
bool RecordDeps(Node *node, TimeStamp mtime, const std::vector< Node *> &nodes)
#define EXPECT_EQ(a, b)
Definition: test.h:64
void AddBinding(const std::string &key, const EvalString &val)
Definition: eval_env.cc:55
An invocable build command and associated metadata (description, etc.).
Definition: eval_env.h:59
#define ASSERT_FALSE(a)
Definition: test.h:95
MissingDependencyTestDelegate delegate_
bool OpenForWrite(const std::string &path, std::string *err)
Definition: deps_log.cc:48
#define ASSERT_EQ(a, b)
Definition: test.h:81
TEST_F(MissingDependencyScannerTest, EmptyGraph)
MissingDependencyScanner scanner_
#define ASSERT_NE(a, b)
Definition: test.h:83
const char kTestDepsLogFilename[]
void AddText(StringPiece text)
Definition: eval_env.cc:112
Global state (file status) for a single run.
Definition: state.h:92
#define ASSERT_TRUE(a)
Definition: test.h:93
A tokenized string that contains variable references.
Definition: eval_env.h:34
void CreateGraphDependencyBetween(const char *from, const char *to)