1695b41eeSopenharmony_ci// Copyright 2019 Google Inc. All Rights Reserved. 2695b41eeSopenharmony_ci// 3695b41eeSopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4695b41eeSopenharmony_ci// you may not use this file except in compliance with the License. 5695b41eeSopenharmony_ci// You may obtain a copy of the License at 6695b41eeSopenharmony_ci// 7695b41eeSopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8695b41eeSopenharmony_ci// 9695b41eeSopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10695b41eeSopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11695b41eeSopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12695b41eeSopenharmony_ci// See the License for the specific language governing permissions and 13695b41eeSopenharmony_ci// limitations under the License. 14695b41eeSopenharmony_ci 15695b41eeSopenharmony_ci#include <memory> 16695b41eeSopenharmony_ci 17695b41eeSopenharmony_ci#include "deps_log.h" 18695b41eeSopenharmony_ci#include "graph.h" 19695b41eeSopenharmony_ci#include "missing_deps.h" 20695b41eeSopenharmony_ci#include "state.h" 21695b41eeSopenharmony_ci#include "test.h" 22695b41eeSopenharmony_ci 23695b41eeSopenharmony_ciconst char kTestDepsLogFilename[] = "MissingDepTest-tempdepslog"; 24695b41eeSopenharmony_ci 25695b41eeSopenharmony_ciclass MissingDependencyTestDelegate : public MissingDependencyScannerDelegate { 26695b41eeSopenharmony_ci void OnMissingDep(Node* node, const std::string& path, 27695b41eeSopenharmony_ci const Rule& generator) {} 28695b41eeSopenharmony_ci}; 29695b41eeSopenharmony_ci 30695b41eeSopenharmony_cistruct MissingDependencyScannerTest : public testing::Test { 31695b41eeSopenharmony_ci MissingDependencyScannerTest() 32695b41eeSopenharmony_ci : generator_rule_("generator_rule"), compile_rule_("compile_rule"), 33695b41eeSopenharmony_ci scanner_(&delegate_, &deps_log_, &state_, &filesystem_) { 34695b41eeSopenharmony_ci std::string err; 35695b41eeSopenharmony_ci deps_log_.OpenForWrite(kTestDepsLogFilename, &err); 36695b41eeSopenharmony_ci EXPECT_EQ("", err); 37695b41eeSopenharmony_ci } 38695b41eeSopenharmony_ci 39695b41eeSopenharmony_ci ~MissingDependencyScannerTest() { 40695b41eeSopenharmony_ci // Remove test file. 41695b41eeSopenharmony_ci deps_log_.Close(); 42695b41eeSopenharmony_ci } 43695b41eeSopenharmony_ci 44695b41eeSopenharmony_ci MissingDependencyScanner& scanner() { return scanner_; } 45695b41eeSopenharmony_ci 46695b41eeSopenharmony_ci void RecordDepsLogDep(const std::string& from, const std::string& to) { 47695b41eeSopenharmony_ci Node* node_deps[] = { state_.LookupNode(to) }; 48695b41eeSopenharmony_ci deps_log_.RecordDeps(state_.LookupNode(from), 0, 1, node_deps); 49695b41eeSopenharmony_ci } 50695b41eeSopenharmony_ci 51695b41eeSopenharmony_ci void ProcessAllNodes() { 52695b41eeSopenharmony_ci std::string err; 53695b41eeSopenharmony_ci std::vector<Node*> nodes = state_.RootNodes(&err); 54695b41eeSopenharmony_ci EXPECT_EQ("", err); 55695b41eeSopenharmony_ci for (std::vector<Node*>::iterator it = nodes.begin(); it != nodes.end(); 56695b41eeSopenharmony_ci ++it) { 57695b41eeSopenharmony_ci scanner().ProcessNode(*it); 58695b41eeSopenharmony_ci } 59695b41eeSopenharmony_ci } 60695b41eeSopenharmony_ci 61695b41eeSopenharmony_ci void CreateInitialState() { 62695b41eeSopenharmony_ci EvalString deps_type; 63695b41eeSopenharmony_ci deps_type.AddText("gcc"); 64695b41eeSopenharmony_ci compile_rule_.AddBinding("deps", deps_type); 65695b41eeSopenharmony_ci generator_rule_.AddBinding("deps", deps_type); 66695b41eeSopenharmony_ci Edge* header_edge = state_.AddEdge(&generator_rule_); 67695b41eeSopenharmony_ci state_.AddOut(header_edge, "generated_header", 0); 68695b41eeSopenharmony_ci Edge* compile_edge = state_.AddEdge(&compile_rule_); 69695b41eeSopenharmony_ci state_.AddOut(compile_edge, "compiled_object", 0); 70695b41eeSopenharmony_ci } 71695b41eeSopenharmony_ci 72695b41eeSopenharmony_ci void CreateGraphDependencyBetween(const char* from, const char* to) { 73695b41eeSopenharmony_ci Node* from_node = state_.LookupNode(from); 74695b41eeSopenharmony_ci Edge* from_edge = from_node->in_edge(); 75695b41eeSopenharmony_ci state_.AddIn(from_edge, to, 0); 76695b41eeSopenharmony_ci } 77695b41eeSopenharmony_ci 78695b41eeSopenharmony_ci void AssertMissingDependencyBetween(const char* flaky, const char* generated, 79695b41eeSopenharmony_ci Rule* rule) { 80695b41eeSopenharmony_ci Node* flaky_node = state_.LookupNode(flaky); 81695b41eeSopenharmony_ci ASSERT_EQ(1u, scanner().nodes_missing_deps_.count(flaky_node)); 82695b41eeSopenharmony_ci Node* generated_node = state_.LookupNode(generated); 83695b41eeSopenharmony_ci ASSERT_EQ(1u, scanner().generated_nodes_.count(generated_node)); 84695b41eeSopenharmony_ci ASSERT_EQ(1u, scanner().generator_rules_.count(rule)); 85695b41eeSopenharmony_ci } 86695b41eeSopenharmony_ci 87695b41eeSopenharmony_ci ScopedFilePath scoped_file_path_ = kTestDepsLogFilename; 88695b41eeSopenharmony_ci MissingDependencyTestDelegate delegate_; 89695b41eeSopenharmony_ci Rule generator_rule_; 90695b41eeSopenharmony_ci Rule compile_rule_; 91695b41eeSopenharmony_ci DepsLog deps_log_; 92695b41eeSopenharmony_ci State state_; 93695b41eeSopenharmony_ci VirtualFileSystem filesystem_; 94695b41eeSopenharmony_ci MissingDependencyScanner scanner_; 95695b41eeSopenharmony_ci}; 96695b41eeSopenharmony_ci 97695b41eeSopenharmony_ciTEST_F(MissingDependencyScannerTest, EmptyGraph) { 98695b41eeSopenharmony_ci ProcessAllNodes(); 99695b41eeSopenharmony_ci ASSERT_FALSE(scanner().HadMissingDeps()); 100695b41eeSopenharmony_ci} 101695b41eeSopenharmony_ci 102695b41eeSopenharmony_ciTEST_F(MissingDependencyScannerTest, NoMissingDep) { 103695b41eeSopenharmony_ci CreateInitialState(); 104695b41eeSopenharmony_ci ProcessAllNodes(); 105695b41eeSopenharmony_ci ASSERT_FALSE(scanner().HadMissingDeps()); 106695b41eeSopenharmony_ci} 107695b41eeSopenharmony_ci 108695b41eeSopenharmony_ciTEST_F(MissingDependencyScannerTest, MissingDepPresent) { 109695b41eeSopenharmony_ci CreateInitialState(); 110695b41eeSopenharmony_ci // compiled_object uses generated_header, without a proper dependency 111695b41eeSopenharmony_ci RecordDepsLogDep("compiled_object", "generated_header"); 112695b41eeSopenharmony_ci ProcessAllNodes(); 113695b41eeSopenharmony_ci ASSERT_TRUE(scanner().HadMissingDeps()); 114695b41eeSopenharmony_ci ASSERT_EQ(1u, scanner().nodes_missing_deps_.size()); 115695b41eeSopenharmony_ci ASSERT_EQ(1u, scanner().missing_dep_path_count_); 116695b41eeSopenharmony_ci AssertMissingDependencyBetween("compiled_object", "generated_header", 117695b41eeSopenharmony_ci &generator_rule_); 118695b41eeSopenharmony_ci} 119695b41eeSopenharmony_ci 120695b41eeSopenharmony_ciTEST_F(MissingDependencyScannerTest, MissingDepFixedDirect) { 121695b41eeSopenharmony_ci CreateInitialState(); 122695b41eeSopenharmony_ci // Adding the direct dependency fixes the missing dep 123695b41eeSopenharmony_ci CreateGraphDependencyBetween("compiled_object", "generated_header"); 124695b41eeSopenharmony_ci RecordDepsLogDep("compiled_object", "generated_header"); 125695b41eeSopenharmony_ci ProcessAllNodes(); 126695b41eeSopenharmony_ci ASSERT_FALSE(scanner().HadMissingDeps()); 127695b41eeSopenharmony_ci} 128695b41eeSopenharmony_ci 129695b41eeSopenharmony_ciTEST_F(MissingDependencyScannerTest, MissingDepFixedIndirect) { 130695b41eeSopenharmony_ci CreateInitialState(); 131695b41eeSopenharmony_ci // Adding an indirect dependency also fixes the issue 132695b41eeSopenharmony_ci Edge* intermediate_edge = state_.AddEdge(&generator_rule_); 133695b41eeSopenharmony_ci state_.AddOut(intermediate_edge, "intermediate", 0); 134695b41eeSopenharmony_ci CreateGraphDependencyBetween("compiled_object", "intermediate"); 135695b41eeSopenharmony_ci CreateGraphDependencyBetween("intermediate", "generated_header"); 136695b41eeSopenharmony_ci RecordDepsLogDep("compiled_object", "generated_header"); 137695b41eeSopenharmony_ci ProcessAllNodes(); 138695b41eeSopenharmony_ci ASSERT_FALSE(scanner().HadMissingDeps()); 139695b41eeSopenharmony_ci} 140695b41eeSopenharmony_ci 141695b41eeSopenharmony_ciTEST_F(MissingDependencyScannerTest, CyclicMissingDep) { 142695b41eeSopenharmony_ci CreateInitialState(); 143695b41eeSopenharmony_ci RecordDepsLogDep("generated_header", "compiled_object"); 144695b41eeSopenharmony_ci RecordDepsLogDep("compiled_object", "generated_header"); 145695b41eeSopenharmony_ci // In case of a cycle, both paths are reported (and there is 146695b41eeSopenharmony_ci // no way to fix the issue by adding deps). 147695b41eeSopenharmony_ci ProcessAllNodes(); 148695b41eeSopenharmony_ci ASSERT_TRUE(scanner().HadMissingDeps()); 149695b41eeSopenharmony_ci ASSERT_EQ(2u, scanner().nodes_missing_deps_.size()); 150695b41eeSopenharmony_ci ASSERT_EQ(2u, scanner().missing_dep_path_count_); 151695b41eeSopenharmony_ci AssertMissingDependencyBetween("compiled_object", "generated_header", 152695b41eeSopenharmony_ci &generator_rule_); 153695b41eeSopenharmony_ci AssertMissingDependencyBetween("generated_header", "compiled_object", 154695b41eeSopenharmony_ci &compile_rule_); 155695b41eeSopenharmony_ci} 156695b41eeSopenharmony_ci 157695b41eeSopenharmony_ciTEST_F(MissingDependencyScannerTest, CycleInGraph) { 158695b41eeSopenharmony_ci CreateInitialState(); 159695b41eeSopenharmony_ci CreateGraphDependencyBetween("compiled_object", "generated_header"); 160695b41eeSopenharmony_ci CreateGraphDependencyBetween("generated_header", "compiled_object"); 161695b41eeSopenharmony_ci // The missing-deps tool doesn't deal with cycles in the graph, because 162695b41eeSopenharmony_ci // there will be an error loading the graph before we get to the tool. 163695b41eeSopenharmony_ci // This test is to illustrate that. 164695b41eeSopenharmony_ci std::string err; 165695b41eeSopenharmony_ci std::vector<Node*> nodes = state_.RootNodes(&err); 166695b41eeSopenharmony_ci ASSERT_NE("", err); 167695b41eeSopenharmony_ci} 168