1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <vector> 6 7 #include "testing/gtest/include/gtest/gtest.h" 8 #include "tools/gn/header_checker.h" 9 #include "tools/gn/scheduler.h" 10 #include "tools/gn/target.h" 11 #include "tools/gn/test_with_scope.h" 12 13 namespace { 14 15 class HeaderCheckerTest : public testing::Test { 16 public: 17 HeaderCheckerTest() 18 : a_(setup_.settings(), Label(SourceDir("//a/"), "a")), 19 b_(setup_.settings(), Label(SourceDir("//b/"), "a")), 20 c_(setup_.settings(), Label(SourceDir("//c/"), "c")) { 21 a_.deps().push_back(LabelTargetPair(&b_)); 22 b_.deps().push_back(LabelTargetPair(&c_)); 23 24 // Start with all public visibility. 25 a_.visibility().SetPublic(); 26 b_.visibility().SetPublic(); 27 c_.visibility().SetPublic(); 28 29 targets_.push_back(&a_); 30 targets_.push_back(&b_); 31 targets_.push_back(&c_); 32 } 33 34 protected: 35 Scheduler scheduler_; 36 37 TestWithScope setup_; 38 39 // Some headers that are automatically set up with a dependency chain. 40 // a -> b -> c 41 Target a_; 42 Target b_; 43 Target c_; 44 45 std::vector<const Target*> targets_; 46 }; 47 48 } // namespace 49 50 TEST_F(HeaderCheckerTest, IsDependencyOf) { 51 scoped_refptr<HeaderChecker> checker( 52 new HeaderChecker(setup_.build_settings(), targets_)); 53 54 std::vector<const Target*> chain; 55 EXPECT_FALSE(checker->IsDependencyOf(&a_, &a_, &chain)); 56 57 chain.clear(); 58 EXPECT_TRUE(checker->IsDependencyOf(&b_, &a_, &chain)); 59 ASSERT_EQ(2u, chain.size()); 60 EXPECT_EQ(&b_, chain[0]); 61 EXPECT_EQ(&a_, chain[1]); 62 63 chain.clear(); 64 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, &chain)); 65 ASSERT_EQ(3u, chain.size()); 66 EXPECT_EQ(&c_, chain[0]); 67 EXPECT_EQ(&b_, chain[1]); 68 EXPECT_EQ(&a_, chain[2]); 69 70 chain.clear(); 71 EXPECT_FALSE(checker->IsDependencyOf(&a_, &c_, &chain)); 72 EXPECT_TRUE(chain.empty()); 73 } 74 75 TEST_F(HeaderCheckerTest, CheckInclude) { 76 InputFile input_file(SourceFile("//some_file.cc")); 77 input_file.SetContents(std::string()); 78 LocationRange range; // Dummy value. 79 80 // Add a disconnected target d with a header to check that you have to have 81 // to depend on a target listing a header. 82 Target d(setup_.settings(), Label(SourceDir("//"), "d")); 83 SourceFile d_header("//d_header.h"); 84 d.sources().push_back(SourceFile(d_header)); 85 86 // Add a header on B and say everything in B is public. 87 SourceFile b_public("//b_public.h"); 88 b_.sources().push_back(b_public); 89 c_.set_all_headers_public(true); 90 91 // Add a public and private header on C. 92 SourceFile c_public("//c_public.h"); 93 SourceFile c_private("//c_private.h"); 94 c_.sources().push_back(c_private); 95 c_.public_headers().push_back(c_public); 96 c_.set_all_headers_public(false); 97 98 targets_.push_back(&d); 99 scoped_refptr<HeaderChecker> checker( 100 new HeaderChecker(setup_.build_settings(), targets_)); 101 102 // A file in target A can't include a header from D because A has no 103 // dependency on D. 104 Err err; 105 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, d_header, range, &err)); 106 EXPECT_TRUE(err.has_error()); 107 108 // A can include the public header in B. 109 err = Err(); 110 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, b_public, range, &err)); 111 EXPECT_FALSE(err.has_error()); 112 113 // Check A depending on the public and private headers in C. 114 err = Err(); 115 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, c_public, range, &err)); 116 EXPECT_FALSE(err.has_error()); 117 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, c_private, range, &err)); 118 EXPECT_TRUE(err.has_error()); 119 120 // A can depend on a random file unknown to the build. 121 err = Err(); 122 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, SourceFile("//random.h"), 123 range, &err)); 124 EXPECT_FALSE(err.has_error()); 125 126 // If C is not visible from A, A can't include public headers even if there 127 // is a dependency path. 128 c_.visibility().SetPrivate(c_.label().dir()); 129 err = Err(); 130 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, c_public, range, &err)); 131 EXPECT_TRUE(err.has_error()); 132 } 133 134 TEST_F(HeaderCheckerTest, DoDirectDependentConfigsApply) { 135 // Assume we have a chain A -> B -> C -> D. 136 Target target_a(setup_.settings(), Label(SourceDir("//a/"), "a")); 137 Target target_b(setup_.settings(), Label(SourceDir("//b/"), "b")); 138 Target target_c(setup_.settings(), Label(SourceDir("//c/"), "c")); 139 Target target_d(setup_.settings(), Label(SourceDir("//d/"), "d")); 140 141 // C is a group, and B forwards deps from C, so A should get configs from D. 142 target_a.set_output_type(Target::SOURCE_SET); 143 target_b.set_output_type(Target::SOURCE_SET); 144 target_c.set_output_type(Target::GROUP); 145 target_d.set_output_type(Target::SOURCE_SET); 146 target_b.forward_dependent_configs().push_back( 147 LabelTargetPair(&target_c)); 148 149 // Dependency chain goes from bottom to top. 150 std::vector<const Target*> chain; 151 chain.push_back(&target_d); 152 chain.push_back(&target_c); 153 chain.push_back(&target_b); 154 chain.push_back(&target_a); 155 156 // This chain should be valid. 157 size_t badone = 0; 158 EXPECT_TRUE(HeaderChecker::DoDirectDependentConfigsApply(chain, &badone)); 159 160 // If C is not a group, it shouldn't work anymore. 161 target_c.set_output_type(Target::SOURCE_SET); 162 EXPECT_FALSE(HeaderChecker::DoDirectDependentConfigsApply(chain, &badone)); 163 EXPECT_EQ(1u, badone); 164 165 // Or if B stops forwarding from C, it shouldn't work anymore. 166 target_c.set_output_type(Target::GROUP); 167 badone = 0; 168 target_b.forward_dependent_configs().clear(); 169 EXPECT_FALSE(HeaderChecker::DoDirectDependentConfigsApply(chain, &badone)); 170 EXPECT_EQ(2u, badone); 171 } 172