• 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         EXPECT_EQ("", err);
37     }
38 
~MissingDependencyScannerTestMissingDependencyScannerTest39     ~MissingDependencyScannerTest() {
40         // Remove test file.
41         deps_log_.Close();
42     }
43 
scannerMissingDependencyScannerTest44     MissingDependencyScanner& scanner() { return scanner_; }
45 
RecordDepsLogDepMissingDependencyScannerTest46     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 
ProcessAllNodesMissingDependencyScannerTest51     void ProcessAllNodes() {
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 
CreateInitialStateMissingDependencyScannerTest61     void CreateInitialState() {
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);
68         Edge* compile_edge = state_.AddEdge(&compile_rule_);
69         state_.AddOut(compile_edge, "compiled_object", 0);
70     }
71 
CreateGraphDependencyBetweenMissingDependencyScannerTest72     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 
AssertMissingDependencyBetweenMissingDependencyScannerTest78     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 
87     ScopedFilePath scoped_file_path_ = kTestDepsLogFilename;
88     MissingDependencyTestDelegate delegate_;
89     Rule generator_rule_;
90     Rule compile_rule_;
91     DepsLog deps_log_;
92     State state_;
93     VirtualFileSystem filesystem_;
94     MissingDependencyScanner scanner_;
95 };
96 
TEST_F(MissingDependencyScannerTest,EmptyGraph)97 TEST_F(MissingDependencyScannerTest, EmptyGraph) {
98     ProcessAllNodes();
99     ASSERT_FALSE(scanner().HadMissingDeps());
100 }
101 
TEST_F(MissingDependencyScannerTest,NoMissingDep)102 TEST_F(MissingDependencyScannerTest, NoMissingDep) {
103     CreateInitialState();
104     ProcessAllNodes();
105     ASSERT_FALSE(scanner().HadMissingDeps());
106 }
107 
TEST_F(MissingDependencyScannerTest,MissingDepPresent)108 TEST_F(MissingDependencyScannerTest, MissingDepPresent) {
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 
TEST_F(MissingDependencyScannerTest,MissingDepFixedDirect)120 TEST_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 
TEST_F(MissingDependencyScannerTest,MissingDepFixedIndirect)129 TEST_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);
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 
TEST_F(MissingDependencyScannerTest,CyclicMissingDep)141 TEST_F(MissingDependencyScannerTest, CyclicMissingDep) {
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 
TEST_F(MissingDependencyScannerTest,CycleInGraph)157 TEST_F(MissingDependencyScannerTest, CycleInGraph) {
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 }
168