| 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/config.h" |
| 9 #include "tools/gn/header_checker.h" | 9 #include "tools/gn/header_checker.h" |
| 10 #include "tools/gn/scheduler.h" | 10 #include "tools/gn/scheduler.h" |
| 11 #include "tools/gn/target.h" | 11 #include "tools/gn/target.h" |
| 12 #include "tools/gn/test_with_scope.h" | 12 #include "tools/gn/test_with_scope.h" |
| 13 | 13 |
| 14 namespace { | 14 namespace { |
| 15 | 15 |
| 16 class HeaderCheckerTest : public testing::Test { | 16 class HeaderCheckerTest : public testing::Test { |
| 17 public: | 17 public: |
| 18 HeaderCheckerTest() | 18 HeaderCheckerTest() |
| 19 : a_(setup_.settings(), Label(SourceDir("//a/"), "a")), | 19 : a_(setup_.settings(), Label(SourceDir("//a/"), "a")), |
| 20 b_(setup_.settings(), Label(SourceDir("//b/"), "a")), | 20 b_(setup_.settings(), Label(SourceDir("//b/"), "b")), |
| 21 c_(setup_.settings(), Label(SourceDir("//c/"), "c")), | 21 c_(setup_.settings(), Label(SourceDir("//c/"), "c")), |
| 22 d_(setup_.settings(), Label(SourceDir("//d/"), "d")) { | 22 d_(setup_.settings(), Label(SourceDir("//d/"), "d")) { |
| 23 a_.deps().push_back(LabelTargetPair(&b_)); | 23 a_.set_output_type(Target::SOURCE_SET); |
| 24 b_.deps().push_back(LabelTargetPair(&c_)); | 24 b_.set_output_type(Target::SOURCE_SET); |
| 25 c_.set_output_type(Target::SOURCE_SET); |
| 26 d_.set_output_type(Target::SOURCE_SET); |
| 27 |
| 28 Err err; |
| 29 a_.SetToolchain(setup_.toolchain(), &err); |
| 30 b_.SetToolchain(setup_.toolchain(), &err); |
| 31 c_.SetToolchain(setup_.toolchain(), &err); |
| 32 d_.SetToolchain(setup_.toolchain(), &err); |
| 33 |
| 34 a_.public_deps().push_back(LabelTargetPair(&b_)); |
| 35 b_.public_deps().push_back(LabelTargetPair(&c_)); |
| 25 | 36 |
| 26 // Start with all public visibility. | 37 // Start with all public visibility. |
| 27 a_.visibility().SetPublic(); | 38 a_.visibility().SetPublic(); |
| 28 b_.visibility().SetPublic(); | 39 b_.visibility().SetPublic(); |
| 29 c_.visibility().SetPublic(); | 40 c_.visibility().SetPublic(); |
| 30 d_.visibility().SetPublic(); | 41 d_.visibility().SetPublic(); |
| 31 | 42 |
| 43 d_.OnResolved(&err); |
| 44 c_.OnResolved(&err); |
| 45 b_.OnResolved(&err); |
| 46 a_.OnResolved(&err); |
| 47 |
| 32 targets_.push_back(&a_); | 48 targets_.push_back(&a_); |
| 33 targets_.push_back(&b_); | 49 targets_.push_back(&b_); |
| 34 targets_.push_back(&c_); | 50 targets_.push_back(&c_); |
| 35 targets_.push_back(&d_); | 51 targets_.push_back(&d_); |
| 36 } | 52 } |
| 37 | 53 |
| 38 protected: | 54 protected: |
| 39 Scheduler scheduler_; | 55 Scheduler scheduler_; |
| 40 | 56 |
| 41 TestWithScope setup_; | 57 TestWithScope setup_; |
| 42 | 58 |
| 43 // Some headers that are automatically set up with a dependency chain. | 59 // Some headers that are automatically set up with a dependency chain. |
| 44 // a -> b -> c | 60 // a -> b -> c |
| 45 Target a_; | 61 Target a_; |
| 46 Target b_; | 62 Target b_; |
| 47 Target c_; | 63 Target c_; |
| 48 Target d_; | 64 Target d_; |
| 49 | 65 |
| 50 std::vector<const Target*> targets_; | 66 std::vector<const Target*> targets_; |
| 51 }; | 67 }; |
| 52 | 68 |
| 53 } // namespace | 69 } // namespace |
| 54 | 70 |
| 55 TEST_F(HeaderCheckerTest, IsDependencyOf) { | 71 TEST_F(HeaderCheckerTest, IsDependencyOf) { |
| 56 scoped_refptr<HeaderChecker> checker( | 72 scoped_refptr<HeaderChecker> checker( |
| 57 new HeaderChecker(setup_.build_settings(), targets_)); | 73 new HeaderChecker(setup_.build_settings(), targets_)); |
| 58 | 74 |
| 75 // Add a target P ("private") that privately depends on C, and hook up the |
| 76 // chain so that A -> P -> C. A will depend on C via two different paths. |
| 77 Err err; |
| 78 Target p(setup_.settings(), Label(SourceDir("//p/"), "p")); |
| 79 p.set_output_type(Target::SOURCE_SET); |
| 80 p.SetToolchain(setup_.toolchain(), &err); |
| 81 EXPECT_FALSE(err.has_error()); |
| 82 p.private_deps().push_back(LabelTargetPair(&c_)); |
| 83 p.visibility().SetPublic(); |
| 84 p.OnResolved(&err); |
| 85 |
| 86 a_.public_deps().push_back(LabelTargetPair(&p)); |
| 87 |
| 88 // A does not depend on itself. |
| 89 bool is_public = false; |
| 59 std::vector<const Target*> chain; | 90 std::vector<const Target*> chain; |
| 60 EXPECT_FALSE(checker->IsDependencyOf(&a_, &a_, false, &chain, NULL)); | 91 EXPECT_FALSE(checker->IsDependencyOf(&a_, &a_, &chain, &is_public)); |
| 61 | 92 |
| 93 // A depends on B. |
| 62 chain.clear(); | 94 chain.clear(); |
| 63 EXPECT_TRUE(checker->IsDependencyOf(&b_, &a_, false, &chain, NULL)); | 95 is_public = false; |
| 96 EXPECT_TRUE(checker->IsDependencyOf(&b_, &a_, &chain, &is_public)); |
| 64 ASSERT_EQ(2u, chain.size()); | 97 ASSERT_EQ(2u, chain.size()); |
| 65 EXPECT_EQ(&b_, chain[0]); | 98 EXPECT_EQ(&b_, chain[0]); |
| 66 EXPECT_EQ(&a_, chain[1]); | 99 EXPECT_EQ(&a_, chain[1]); |
| 100 EXPECT_TRUE(is_public); |
| 67 | 101 |
| 102 // A indirectly depends on C. The "public" dependency path through B should |
| 103 // be identified. |
| 68 chain.clear(); | 104 chain.clear(); |
| 69 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, false, &chain, NULL)); | 105 is_public = false; |
| 106 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, &chain, &is_public)); |
| 70 ASSERT_EQ(3u, chain.size()); | 107 ASSERT_EQ(3u, chain.size()); |
| 71 EXPECT_EQ(&c_, chain[0]); | 108 EXPECT_EQ(&c_, chain[0]); |
| 72 EXPECT_EQ(&b_, chain[1]); | 109 EXPECT_EQ(&b_, chain[1]); |
| 73 EXPECT_EQ(&a_, chain[2]); | 110 EXPECT_EQ(&a_, chain[2]); |
| 111 EXPECT_TRUE(is_public); |
| 74 | 112 |
| 113 // C does not depend on A. |
| 75 chain.clear(); | 114 chain.clear(); |
| 76 EXPECT_FALSE(checker->IsDependencyOf(&a_, &c_, false, &chain, NULL)); | 115 is_public = false; |
| 116 EXPECT_FALSE(checker->IsDependencyOf(&a_, &c_, &chain, &is_public)); |
| 77 EXPECT_TRUE(chain.empty()); | 117 EXPECT_TRUE(chain.empty()); |
| 118 EXPECT_FALSE(is_public); |
| 78 | 119 |
| 79 // If an a -> c dependency exists, this should be chosen for the chain. | 120 // Add a private A -> C dependency. This should not be detected since it's |
| 121 // private, even though it's shorter than the A -> B -> C one. |
| 80 chain.clear(); | 122 chain.clear(); |
| 81 a_.deps().push_back(LabelTargetPair(&c_)); | 123 is_public = false; |
| 82 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, false, &chain, NULL)); | 124 a_.private_deps().push_back(LabelTargetPair(&c_)); |
| 83 EXPECT_EQ(&c_, chain[0]); | 125 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, &chain, &is_public)); |
| 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( | |
| 96 &c_, &a_, true, &chain, &direct_dependent_configs_apply)); | |
| 97 EXPECT_FALSE(direct_dependent_configs_apply); | |
| 98 EXPECT_EQ(3u, chain.size()); | |
| 99 EXPECT_EQ(&c_, chain[0]); | 126 EXPECT_EQ(&c_, chain[0]); |
| 100 EXPECT_EQ(&b_, chain[1]); | 127 EXPECT_EQ(&b_, chain[1]); |
| 101 EXPECT_EQ(&a_, chain[2]); | 128 EXPECT_EQ(&a_, chain[2]); |
| 129 EXPECT_TRUE(is_public); |
| 102 | 130 |
| 103 // Create a chain a -> d -> c where d forwards direct-dependent configs. | 131 // Remove the B -> C public dependency, leaving A's private dep on C the only |
| 104 // This path should be preferred when dependency chains which forward | 132 // path. This should now be found. |
| 105 // direct-dependent configs are preferred. | |
| 106 chain.clear(); | 133 chain.clear(); |
| 107 direct_dependent_configs_apply = false; | 134 EXPECT_EQ(&c_, b_.public_deps()[0].ptr); // Validate it's the right one. |
| 108 d_.deps().push_back(LabelTargetPair(&c_)); | 135 b_.public_deps().erase(b_.public_deps().begin()); |
| 109 d_.forward_dependent_configs().push_back(LabelTargetPair(&c_)); | 136 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, &chain, &is_public)); |
| 110 a_.deps().push_back(LabelTargetPair(&d_)); | |
| 111 EXPECT_TRUE(checker->IsDependencyOf( | |
| 112 &c_, &a_, true, &chain, &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( | |
| 125 &c_, &a_, true, &chain, &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( | |
| 137 &c_, &a_, true, &chain, &direct_dependent_configs_apply)); | |
| 138 EXPECT_TRUE(direct_dependent_configs_apply); | |
| 139 EXPECT_EQ(2u, chain.size()); | |
| 140 EXPECT_EQ(&c_, chain[0]); | 137 EXPECT_EQ(&c_, chain[0]); |
| 141 EXPECT_EQ(&a_, chain[1]); | 138 EXPECT_EQ(&a_, chain[1]); |
| 139 EXPECT_FALSE(is_public); |
| 142 } | 140 } |
| 143 | 141 |
| 144 TEST_F(HeaderCheckerTest, CheckInclude) { | 142 TEST_F(HeaderCheckerTest, CheckInclude) { |
| 145 InputFile input_file(SourceFile("//some_file.cc")); | 143 InputFile input_file(SourceFile("//some_file.cc")); |
| 146 input_file.SetContents(std::string()); | 144 input_file.SetContents(std::string()); |
| 147 LocationRange range; // Dummy value. | 145 LocationRange range; // Dummy value. |
| 148 | 146 |
| 149 // Add a disconnected target d with a header to check that you have to have | 147 // Add a disconnected target d with a header to check that you have to have |
| 150 // to depend on a target listing a header. | 148 // to depend on a target listing a header. |
| 151 SourceFile d_header("//d_header.h"); | 149 SourceFile d_header("//d_header.h"); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, c_public, range, &err)); | 181 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, c_public, range, &err)); |
| 184 EXPECT_FALSE(err.has_error()); | 182 EXPECT_FALSE(err.has_error()); |
| 185 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, c_private, range, &err)); | 183 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, c_private, range, &err)); |
| 186 EXPECT_TRUE(err.has_error()); | 184 EXPECT_TRUE(err.has_error()); |
| 187 | 185 |
| 188 // A can depend on a random file unknown to the build. | 186 // A can depend on a random file unknown to the build. |
| 189 err = Err(); | 187 err = Err(); |
| 190 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, SourceFile("//random.h"), | 188 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, SourceFile("//random.h"), |
| 191 range, &err)); | 189 range, &err)); |
| 192 EXPECT_FALSE(err.has_error()); | 190 EXPECT_FALSE(err.has_error()); |
| 193 | |
| 194 // If C is not visible from A, A can't include public headers even if there | |
| 195 // is a dependency path. | |
| 196 c_.visibility().SetPrivate(c_.label().dir()); | |
| 197 err = Err(); | |
| 198 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, c_public, range, &err)); | |
| 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 } | |
| 227 } | 191 } |
| 228 | 192 |
| 229 // Checks that the allow_circular_includes_from list works. | 193 // Checks that the allow_circular_includes_from list works. |
| 230 TEST_F(HeaderCheckerTest, CheckIncludeAllowCircular) { | 194 TEST_F(HeaderCheckerTest, CheckIncludeAllowCircular) { |
| 231 InputFile input_file(SourceFile("//some_file.cc")); | 195 InputFile input_file(SourceFile("//some_file.cc")); |
| 232 input_file.SetContents(std::string()); | 196 input_file.SetContents(std::string()); |
| 233 LocationRange range; // Dummy value. | 197 LocationRange range; // Dummy value. |
| 234 | 198 |
| 235 // Add an include file to A. | 199 // Add an include file to A. |
| 236 SourceFile a_public("//a_public.h"); | 200 SourceFile a_public("//a_public.h"); |
| 237 a_.sources().push_back(a_public); | 201 a_.sources().push_back(a_public); |
| 238 | 202 |
| 239 scoped_refptr<HeaderChecker> checker( | 203 scoped_refptr<HeaderChecker> checker( |
| 240 new HeaderChecker(setup_.build_settings(), targets_)); | 204 new HeaderChecker(setup_.build_settings(), targets_)); |
| 241 | 205 |
| 242 // A depends on B. So B normally can't include headers from A. | 206 // A depends on B. So B normally can't include headers from A. |
| 243 Err err; | 207 Err err; |
| 244 EXPECT_FALSE(checker->CheckInclude(&b_, input_file, a_public, range, &err)); | 208 EXPECT_FALSE(checker->CheckInclude(&b_, input_file, a_public, range, &err)); |
| 245 EXPECT_TRUE(err.has_error()); | 209 EXPECT_TRUE(err.has_error()); |
| 246 | 210 |
| 247 // Add an allow_circular_includes_from on A that lists B. | 211 // Add an allow_circular_includes_from on A that lists B. |
| 248 a_.allow_circular_includes_from().insert(b_.label()); | 212 a_.allow_circular_includes_from().insert(b_.label()); |
| 249 | 213 |
| 250 // Now the include from B to A should be allowed. | 214 // Now the include from B to A should be allowed. |
| 251 err = Err(); | 215 err = Err(); |
| 252 EXPECT_TRUE(checker->CheckInclude(&b_, input_file, a_public, range, &err)); | 216 EXPECT_TRUE(checker->CheckInclude(&b_, input_file, a_public, range, &err)); |
| 253 EXPECT_FALSE(err.has_error()); | 217 EXPECT_FALSE(err.has_error()); |
| 254 } | 218 } |
| 255 | |
| 256 TEST_F(HeaderCheckerTest, GetDependentConfigChainProblemIndex) { | |
| 257 // Assume we have a chain A -> B -> C -> D. | |
| 258 Target target_a(setup_.settings(), Label(SourceDir("//a/"), "a")); | |
| 259 Target target_b(setup_.settings(), Label(SourceDir("//b/"), "b")); | |
| 260 Target target_c(setup_.settings(), Label(SourceDir("//c/"), "c")); | |
| 261 Target target_d(setup_.settings(), Label(SourceDir("//d/"), "d")); | |
| 262 | |
| 263 // C is a group, and B forwards deps from C, so A should get configs from D. | |
| 264 target_a.set_output_type(Target::SOURCE_SET); | |
| 265 target_b.set_output_type(Target::SOURCE_SET); | |
| 266 target_c.set_output_type(Target::GROUP); | |
| 267 target_d.set_output_type(Target::SOURCE_SET); | |
| 268 target_b.forward_dependent_configs().push_back( | |
| 269 LabelTargetPair(&target_c)); | |
| 270 | |
| 271 // Dependency chain goes from bottom to top. | |
| 272 std::vector<const Target*> chain; | |
| 273 chain.push_back(&target_d); | |
| 274 chain.push_back(&target_c); | |
| 275 chain.push_back(&target_b); | |
| 276 chain.push_back(&target_a); | |
| 277 | |
| 278 // If C is not a group, it shouldn't work anymore. | |
| 279 target_c.set_output_type(Target::SOURCE_SET); | |
| 280 EXPECT_EQ(1u, HeaderChecker::GetDependentConfigChainProblemIndex(chain)); | |
| 281 | |
| 282 // Or if B stops forwarding from C, it shouldn't work anymore. | |
| 283 target_c.set_output_type(Target::GROUP); | |
| 284 target_b.forward_dependent_configs().clear(); | |
| 285 EXPECT_EQ(2u, HeaderChecker::GetDependentConfigChainProblemIndex(chain)); | |
| 286 } | |
| OLD | NEW |