• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
25 class MissingDependencyTestDelegate : public MissingDependencyScannerDelegate {
OnMissingDep(Node * node,const std::string & path,const Rule & generator)26   void OnMissingDep(Node* node, const std::string& path,
27                     const Rule& generator) {}
28 };
29 
30 struct MissingDependencyScannerTest : public testing::Test {
MissingDependencyScannerTestMissingDependencyScannerTest31   MissingDependencyScannerTest()
32       : generator_rule_("generator_rule"), compile_rule_("compile_rule"),
33         scanner_(&delegate_, &deps_log_, &state_, &filesystem_) {
34     std::string err;
35     deps_log_.OpenForWrite(kTestDepsLogFilename, &err);
36     ASSERT_EQ("", err);
37   }
38 
scannerMissingDependencyScannerTest39   MissingDependencyScanner& scanner() { return scanner_; }
40 
RecordDepsLogDepMissingDependencyScannerTest41   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 
ProcessAllNodesMissingDependencyScannerTest46   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 
CreateInitialStateMissingDependencyScannerTest56   void CreateInitialState() {
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 
CreateGraphDependencyBetweenMissingDependencyScannerTest67   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 
AssertMissingDependencyBetweenMissingDependencyScannerTest73   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 
82   MissingDependencyTestDelegate delegate_;
83   Rule generator_rule_;
84   Rule compile_rule_;
85   DepsLog deps_log_;
86   State state_;
87   VirtualFileSystem filesystem_;
88   MissingDependencyScanner scanner_;
89 };
90 
TEST_F(MissingDependencyScannerTest,EmptyGraph)91 TEST_F(MissingDependencyScannerTest, EmptyGraph) {
92   ProcessAllNodes();
93   ASSERT_FALSE(scanner().HadMissingDeps());
94 }
95 
TEST_F(MissingDependencyScannerTest,NoMissingDep)96 TEST_F(MissingDependencyScannerTest, NoMissingDep) {
97   CreateInitialState();
98   ProcessAllNodes();
99   ASSERT_FALSE(scanner().HadMissingDeps());
100 }
101 
TEST_F(MissingDependencyScannerTest,MissingDepPresent)102 TEST_F(MissingDependencyScannerTest, MissingDepPresent) {
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 
TEST_F(MissingDependencyScannerTest,MissingDepFixedDirect)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 
TEST_F(MissingDependencyScannerTest,MissingDepFixedIndirect)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 
TEST_F(MissingDependencyScannerTest,CyclicMissingDep)135 TEST_F(MissingDependencyScannerTest, CyclicMissingDep) {
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 
TEST_F(MissingDependencyScannerTest,CycleInGraph)151 TEST_F(MissingDependencyScannerTest, CycleInGraph) {
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 
163