| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <vector> | 5 #include <vector> |
| 6 | 6 |
| 7 #include "testing/gtest/include/gtest/gtest.h" | 7 #include "testing/gtest/include/gtest/gtest.h" |
| 8 #include "tools/gn/config.h" |
| 8 #include "tools/gn/header_checker.h" | 9 #include "tools/gn/header_checker.h" |
| 9 #include "tools/gn/scheduler.h" | 10 #include "tools/gn/scheduler.h" |
| 10 #include "tools/gn/target.h" | 11 #include "tools/gn/target.h" |
| 11 #include "tools/gn/test_with_scope.h" | 12 #include "tools/gn/test_with_scope.h" |
| 12 | 13 |
| 13 namespace { | 14 namespace { |
| 14 | 15 |
| 15 class HeaderCheckerTest : public testing::Test { | 16 class HeaderCheckerTest : public testing::Test { |
| 16 public: | 17 public: |
| 17 HeaderCheckerTest() | 18 HeaderCheckerTest() |
| 18 : a_(setup_.settings(), Label(SourceDir("//a/"), "a")), | 19 : a_(setup_.settings(), Label(SourceDir("//a/"), "a")), |
| 19 b_(setup_.settings(), Label(SourceDir("//b/"), "a")), | 20 b_(setup_.settings(), Label(SourceDir("//b/"), "a")), |
| 20 c_(setup_.settings(), Label(SourceDir("//c/"), "c")) { | 21 c_(setup_.settings(), Label(SourceDir("//c/"), "c")), |
| 22 d_(setup_.settings(), Label(SourceDir("//d/"), "d")) { |
| 21 a_.deps().push_back(LabelTargetPair(&b_)); | 23 a_.deps().push_back(LabelTargetPair(&b_)); |
| 22 b_.deps().push_back(LabelTargetPair(&c_)); | 24 b_.deps().push_back(LabelTargetPair(&c_)); |
| 23 | 25 |
| 24 // Start with all public visibility. | 26 // Start with all public visibility. |
| 25 a_.visibility().SetPublic(); | 27 a_.visibility().SetPublic(); |
| 26 b_.visibility().SetPublic(); | 28 b_.visibility().SetPublic(); |
| 27 c_.visibility().SetPublic(); | 29 c_.visibility().SetPublic(); |
| 30 d_.visibility().SetPublic(); |
| 28 | 31 |
| 29 targets_.push_back(&a_); | 32 targets_.push_back(&a_); |
| 30 targets_.push_back(&b_); | 33 targets_.push_back(&b_); |
| 31 targets_.push_back(&c_); | 34 targets_.push_back(&c_); |
| 35 targets_.push_back(&d_); |
| 32 } | 36 } |
| 33 | 37 |
| 34 protected: | 38 protected: |
| 35 Scheduler scheduler_; | 39 Scheduler scheduler_; |
| 36 | 40 |
| 37 TestWithScope setup_; | 41 TestWithScope setup_; |
| 38 | 42 |
| 39 // Some headers that are automatically set up with a dependency chain. | 43 // Some headers that are automatically set up with a dependency chain. |
| 40 // a -> b -> c | 44 // a -> b -> c |
| 41 Target a_; | 45 Target a_; |
| 42 Target b_; | 46 Target b_; |
| 43 Target c_; | 47 Target c_; |
| 48 Target d_; |
| 44 | 49 |
| 45 std::vector<const Target*> targets_; | 50 std::vector<const Target*> targets_; |
| 46 }; | 51 }; |
| 47 | 52 |
| 48 } // namespace | 53 } // namespace |
| 49 | 54 |
| 50 TEST_F(HeaderCheckerTest, IsDependencyOf) { | 55 TEST_F(HeaderCheckerTest, IsDependencyOf) { |
| 51 scoped_refptr<HeaderChecker> checker( | 56 scoped_refptr<HeaderChecker> checker( |
| 52 new HeaderChecker(setup_.build_settings(), targets_)); | 57 new HeaderChecker(setup_.build_settings(), targets_)); |
| 53 | 58 |
| 54 std::vector<const Target*> chain; | 59 std::vector<const Target*> chain; |
| 55 EXPECT_FALSE(checker->IsDependencyOf(&a_, &a_, &chain)); | 60 EXPECT_FALSE(checker->IsDependencyOf(&a_, &a_, false, &chain, NULL)); |
| 56 | 61 |
| 57 chain.clear(); | 62 chain.clear(); |
| 58 EXPECT_TRUE(checker->IsDependencyOf(&b_, &a_, &chain)); | 63 EXPECT_TRUE(checker->IsDependencyOf(&b_, &a_, false, &chain, NULL)); |
| 59 ASSERT_EQ(2u, chain.size()); | 64 ASSERT_EQ(2u, chain.size()); |
| 60 EXPECT_EQ(&b_, chain[0]); | 65 EXPECT_EQ(&b_, chain[0]); |
| 61 EXPECT_EQ(&a_, chain[1]); | 66 EXPECT_EQ(&a_, chain[1]); |
| 62 | 67 |
| 63 chain.clear(); | 68 chain.clear(); |
| 64 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, &chain)); | 69 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, false, &chain, NULL)); |
| 65 ASSERT_EQ(3u, chain.size()); | 70 ASSERT_EQ(3u, chain.size()); |
| 66 EXPECT_EQ(&c_, chain[0]); | 71 EXPECT_EQ(&c_, chain[0]); |
| 67 EXPECT_EQ(&b_, chain[1]); | 72 EXPECT_EQ(&b_, chain[1]); |
| 68 EXPECT_EQ(&a_, chain[2]); | 73 EXPECT_EQ(&a_, chain[2]); |
| 69 | 74 |
| 70 chain.clear(); | 75 chain.clear(); |
| 71 EXPECT_FALSE(checker->IsDependencyOf(&a_, &c_, &chain)); | 76 EXPECT_FALSE(checker->IsDependencyOf(&a_, &c_, false, &chain, NULL)); |
| 72 EXPECT_TRUE(chain.empty()); | 77 EXPECT_TRUE(chain.empty()); |
| 78 |
| 79 // If an a -> c dependency exists, this should be chosen for the chain. |
| 80 chain.clear(); |
| 81 a_.deps().push_back(LabelTargetPair(&c_)); |
| 82 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, false, &chain, NULL)); |
| 83 EXPECT_EQ(&c_, chain[0]); |
| 84 EXPECT_EQ(&a_, chain[1]); |
| 85 } |
| 86 |
| 87 TEST_F(HeaderCheckerTest, IsDependencyOf_ForwardsDirectDependentConfigs) { |
| 88 scoped_refptr<HeaderChecker> checker( |
| 89 new HeaderChecker(setup_.build_settings(), targets_)); |
| 90 |
| 91 // The a -> b -> c chain is found, since no chains that forward direct- |
| 92 // dependent configs exist. |
| 93 std::vector<const Target*> chain; |
| 94 bool direct_dependent_configs_apply = false; |
| 95 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, true, &chain, |
| 96 &direct_dependent_configs_apply)); |
| 97 EXPECT_FALSE(direct_dependent_configs_apply); |
| 98 EXPECT_EQ(3u, chain.size()); |
| 99 EXPECT_EQ(&c_, chain[0]); |
| 100 EXPECT_EQ(&b_, chain[1]); |
| 101 EXPECT_EQ(&a_, chain[2]); |
| 102 |
| 103 // Create a chain a -> d -> c where d forwards direct-dependent configs. |
| 104 // This path should be preferred when dependency chains which forward |
| 105 // direct-dependent configs are preferred. |
| 106 chain.clear(); |
| 107 direct_dependent_configs_apply = false; |
| 108 d_.deps().push_back(LabelTargetPair(&c_)); |
| 109 d_.forward_dependent_configs().push_back(LabelTargetPair(&c_)); |
| 110 a_.deps().push_back(LabelTargetPair(&d_)); |
| 111 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, true, &chain, |
| 112 &direct_dependent_configs_apply)); |
| 113 EXPECT_TRUE(direct_dependent_configs_apply); |
| 114 EXPECT_EQ(3u, chain.size()); |
| 115 EXPECT_EQ(&c_, chain[0]); |
| 116 EXPECT_EQ(&d_, chain[1]); |
| 117 EXPECT_EQ(&a_, chain[2]); |
| 118 |
| 119 // d also forwards direct-dependent configs if it is a group. |
| 120 chain.clear(); |
| 121 direct_dependent_configs_apply = false; |
| 122 d_.set_output_type(Target::GROUP); |
| 123 d_.forward_dependent_configs().clear(); |
| 124 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, true, &chain, |
| 125 &direct_dependent_configs_apply)); |
| 126 EXPECT_TRUE(direct_dependent_configs_apply); |
| 127 EXPECT_EQ(3u, chain.size()); |
| 128 EXPECT_EQ(&c_, chain[0]); |
| 129 EXPECT_EQ(&d_, chain[1]); |
| 130 EXPECT_EQ(&a_, chain[2]); |
| 131 |
| 132 // A direct dependency a -> c carries direct-dependent configs. |
| 133 chain.clear(); |
| 134 direct_dependent_configs_apply = false; |
| 135 a_.deps().push_back(LabelTargetPair(&c_)); |
| 136 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, true, &chain, |
| 137 &direct_dependent_configs_apply)); |
| 138 EXPECT_TRUE(direct_dependent_configs_apply); |
| 139 EXPECT_EQ(2u, chain.size()); |
| 140 EXPECT_EQ(&c_, chain[0]); |
| 141 EXPECT_EQ(&a_, chain[1]); |
| 73 } | 142 } |
| 74 | 143 |
| 75 TEST_F(HeaderCheckerTest, CheckInclude) { | 144 TEST_F(HeaderCheckerTest, CheckInclude) { |
| 76 InputFile input_file(SourceFile("//some_file.cc")); | 145 InputFile input_file(SourceFile("//some_file.cc")); |
| 77 input_file.SetContents(std::string()); | 146 input_file.SetContents(std::string()); |
| 78 LocationRange range; // Dummy value. | 147 LocationRange range; // Dummy value. |
| 79 | 148 |
| 80 // Add a disconnected target d with a header to check that you have to have | 149 // Add a disconnected target d with a header to check that you have to have |
| 81 // to depend on a target listing a header. | 150 // to depend on a target listing a header. |
| 82 Target d(setup_.settings(), Label(SourceDir("//"), "d")); | |
| 83 SourceFile d_header("//d_header.h"); | 151 SourceFile d_header("//d_header.h"); |
| 84 d.sources().push_back(SourceFile(d_header)); | 152 d_.sources().push_back(SourceFile(d_header)); |
| 85 | 153 |
| 86 // Add a header on B and say everything in B is public. | 154 // Add a header on B and say everything in B is public. |
| 87 SourceFile b_public("//b_public.h"); | 155 SourceFile b_public("//b_public.h"); |
| 88 b_.sources().push_back(b_public); | 156 b_.sources().push_back(b_public); |
| 89 c_.set_all_headers_public(true); | 157 c_.set_all_headers_public(true); |
| 90 | 158 |
| 91 // Add a public and private header on C. | 159 // Add a public and private header on C. |
| 92 SourceFile c_public("//c_public.h"); | 160 SourceFile c_public("//c_public.h"); |
| 93 SourceFile c_private("//c_private.h"); | 161 SourceFile c_private("//c_private.h"); |
| 94 c_.sources().push_back(c_private); | 162 c_.sources().push_back(c_private); |
| 95 c_.public_headers().push_back(c_public); | 163 c_.public_headers().push_back(c_public); |
| 96 c_.set_all_headers_public(false); | 164 c_.set_all_headers_public(false); |
| 97 | 165 |
| 98 targets_.push_back(&d); | 166 targets_.push_back(&d_); |
| 99 scoped_refptr<HeaderChecker> checker( | 167 scoped_refptr<HeaderChecker> checker( |
| 100 new HeaderChecker(setup_.build_settings(), targets_)); | 168 new HeaderChecker(setup_.build_settings(), targets_)); |
| 101 | 169 |
| 102 // A file in target A can't include a header from D because A has no | 170 // A file in target A can't include a header from D because A has no |
| 103 // dependency on D. | 171 // dependency on D. |
| 104 Err err; | 172 Err err; |
| 105 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, d_header, range, &err)); | 173 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, d_header, range, &err)); |
| 106 EXPECT_TRUE(err.has_error()); | 174 EXPECT_TRUE(err.has_error()); |
| 107 | 175 |
| 108 // A can include the public header in B. | 176 // A can include the public header in B. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 122 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, SourceFile("//random.h"), | 190 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, SourceFile("//random.h"), |
| 123 range, &err)); | 191 range, &err)); |
| 124 EXPECT_FALSE(err.has_error()); | 192 EXPECT_FALSE(err.has_error()); |
| 125 | 193 |
| 126 // If C is not visible from A, A can't include public headers even if there | 194 // If C is not visible from A, A can't include public headers even if there |
| 127 // is a dependency path. | 195 // is a dependency path. |
| 128 c_.visibility().SetPrivate(c_.label().dir()); | 196 c_.visibility().SetPrivate(c_.label().dir()); |
| 129 err = Err(); | 197 err = Err(); |
| 130 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, c_public, range, &err)); | 198 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, c_public, range, &err)); |
| 131 EXPECT_TRUE(err.has_error()); | 199 EXPECT_TRUE(err.has_error()); |
| 200 c_.visibility().SetPublic(); |
| 201 |
| 202 // If C has direct-dependent configs, then B must forward them to A. |
| 203 // If B is a group, that suffices to forward direct-dependent configs. |
| 204 { |
| 205 Config direct(setup_.settings(), Label(SourceDir("//c/"), "config")); |
| 206 direct.config_values().cflags().push_back("-DSOME_DEFINE"); |
| 207 |
| 208 c_.direct_dependent_configs().push_back(LabelConfigPair(&direct)); |
| 209 err = Err(); |
| 210 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, c_public, range, &err)); |
| 211 EXPECT_TRUE(err.has_error()); |
| 212 |
| 213 b_.forward_dependent_configs().push_back(LabelTargetPair(&c_)); |
| 214 err = Err(); |
| 215 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, c_public, range, &err)); |
| 216 EXPECT_FALSE(err.has_error()); |
| 217 |
| 218 b_.forward_dependent_configs().clear(); |
| 219 b_.set_output_type(Target::GROUP); |
| 220 err = Err(); |
| 221 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, c_public, range, &err)); |
| 222 EXPECT_FALSE(err.has_error()); |
| 223 |
| 224 b_.set_output_type(Target::UNKNOWN); |
| 225 c_.direct_dependent_configs().clear(); |
| 226 } |
| 132 } | 227 } |
| 133 | 228 |
| 134 TEST_F(HeaderCheckerTest, DoDirectDependentConfigsApply) { | 229 TEST_F(HeaderCheckerTest, GetDependentConfigChainProblemIndex) { |
| 135 // Assume we have a chain A -> B -> C -> D. | 230 // Assume we have a chain A -> B -> C -> D. |
| 136 Target target_a(setup_.settings(), Label(SourceDir("//a/"), "a")); | 231 Target target_a(setup_.settings(), Label(SourceDir("//a/"), "a")); |
| 137 Target target_b(setup_.settings(), Label(SourceDir("//b/"), "b")); | 232 Target target_b(setup_.settings(), Label(SourceDir("//b/"), "b")); |
| 138 Target target_c(setup_.settings(), Label(SourceDir("//c/"), "c")); | 233 Target target_c(setup_.settings(), Label(SourceDir("//c/"), "c")); |
| 139 Target target_d(setup_.settings(), Label(SourceDir("//d/"), "d")); | 234 Target target_d(setup_.settings(), Label(SourceDir("//d/"), "d")); |
| 140 | 235 |
| 141 // C is a group, and B forwards deps from C, so A should get configs from D. | 236 // 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); | 237 target_a.set_output_type(Target::SOURCE_SET); |
| 143 target_b.set_output_type(Target::SOURCE_SET); | 238 target_b.set_output_type(Target::SOURCE_SET); |
| 144 target_c.set_output_type(Target::GROUP); | 239 target_c.set_output_type(Target::GROUP); |
| 145 target_d.set_output_type(Target::SOURCE_SET); | 240 target_d.set_output_type(Target::SOURCE_SET); |
| 146 target_b.forward_dependent_configs().push_back( | 241 target_b.forward_dependent_configs().push_back( |
| 147 LabelTargetPair(&target_c)); | 242 LabelTargetPair(&target_c)); |
| 148 | 243 |
| 149 // Dependency chain goes from bottom to top. | 244 // Dependency chain goes from bottom to top. |
| 150 std::vector<const Target*> chain; | 245 std::vector<const Target*> chain; |
| 151 chain.push_back(&target_d); | 246 chain.push_back(&target_d); |
| 152 chain.push_back(&target_c); | 247 chain.push_back(&target_c); |
| 153 chain.push_back(&target_b); | 248 chain.push_back(&target_b); |
| 154 chain.push_back(&target_a); | 249 chain.push_back(&target_a); |
| 155 | 250 |
| 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. | 251 // If C is not a group, it shouldn't work anymore. |
| 161 target_c.set_output_type(Target::SOURCE_SET); | 252 target_c.set_output_type(Target::SOURCE_SET); |
| 162 EXPECT_FALSE(HeaderChecker::DoDirectDependentConfigsApply(chain, &badone)); | 253 EXPECT_EQ(1u, HeaderChecker::GetDependentConfigChainProblemIndex(chain)); |
| 163 EXPECT_EQ(1u, badone); | |
| 164 | 254 |
| 165 // Or if B stops forwarding from C, it shouldn't work anymore. | 255 // Or if B stops forwarding from C, it shouldn't work anymore. |
| 166 target_c.set_output_type(Target::GROUP); | 256 target_c.set_output_type(Target::GROUP); |
| 167 badone = 0; | |
| 168 target_b.forward_dependent_configs().clear(); | 257 target_b.forward_dependent_configs().clear(); |
| 169 EXPECT_FALSE(HeaderChecker::DoDirectDependentConfigsApply(chain, &badone)); | 258 EXPECT_EQ(2u, HeaderChecker::GetDependentConfigChainProblemIndex(chain)); |
| 170 EXPECT_EQ(2u, badone); | |
| 171 } | 259 } |
| OLD | NEW |