| 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" |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 targets_.push_back(&b_); | 49 targets_.push_back(&b_); |
| 50 targets_.push_back(&c_); | 50 targets_.push_back(&c_); |
| 51 targets_.push_back(&d_); | 51 targets_.push_back(&d_); |
| 52 } | 52 } |
| 53 | 53 |
| 54 protected: | 54 protected: |
| 55 Scheduler scheduler_; | 55 Scheduler scheduler_; |
| 56 | 56 |
| 57 TestWithScope setup_; | 57 TestWithScope setup_; |
| 58 | 58 |
| 59 // Some headers that are automatically set up with a dependency chain. | 59 // Some headers that are automatically set up with a public dependency chain. |
| 60 // a -> b -> c | 60 // a -> b -> c. D is unconnected. |
| 61 Target a_; | 61 Target a_; |
| 62 Target b_; | 62 Target b_; |
| 63 Target c_; | 63 Target c_; |
| 64 Target d_; | 64 Target d_; |
| 65 | 65 |
| 66 std::vector<const Target*> targets_; | 66 std::vector<const Target*> targets_; |
| 67 }; | 67 }; |
| 68 | 68 |
| 69 } // namespace | 69 } // namespace |
| 70 | 70 |
| 71 TEST_F(HeaderCheckerTest, IsDependencyOf) { | 71 TEST_F(HeaderCheckerTest, IsDependencyOf) { |
| 72 scoped_refptr<HeaderChecker> checker( | 72 scoped_refptr<HeaderChecker> checker( |
| 73 new HeaderChecker(setup_.build_settings(), targets_)); | 73 new HeaderChecker(setup_.build_settings(), targets_)); |
| 74 | 74 |
| 75 // Add a target P ("private") that privately depends on C, and hook up the | 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. | 76 // chain so that A -> P -> C. A will depend on C via two different paths. |
| 77 Err err; | 77 Err err; |
| 78 Target p(setup_.settings(), Label(SourceDir("//p/"), "p")); | 78 Target p(setup_.settings(), Label(SourceDir("//p/"), "p")); |
| 79 p.set_output_type(Target::SOURCE_SET); | 79 p.set_output_type(Target::SOURCE_SET); |
| 80 p.SetToolchain(setup_.toolchain(), &err); | 80 p.SetToolchain(setup_.toolchain(), &err); |
| 81 EXPECT_FALSE(err.has_error()); | 81 EXPECT_FALSE(err.has_error()); |
| 82 p.private_deps().push_back(LabelTargetPair(&c_)); | 82 p.private_deps().push_back(LabelTargetPair(&c_)); |
| 83 p.visibility().SetPublic(); | 83 p.visibility().SetPublic(); |
| 84 p.OnResolved(&err); | 84 p.OnResolved(&err); |
| 85 | 85 |
| 86 a_.public_deps().push_back(LabelTargetPair(&p)); | 86 a_.public_deps().push_back(LabelTargetPair(&p)); |
| 87 | 87 |
| 88 // A does not depend on itself. | 88 // A does not depend on itself. |
| 89 bool is_public = false; | 89 bool is_permitted = false; |
| 90 std::vector<const Target*> chain; | 90 HeaderChecker::Chain chain; |
| 91 EXPECT_FALSE(checker->IsDependencyOf(&a_, &a_, &chain, &is_public)); | 91 EXPECT_FALSE(checker->IsDependencyOf(&a_, &a_, &chain, &is_permitted)); |
| 92 | 92 |
| 93 // A depends on B. | 93 // A depends publicly on B. |
| 94 chain.clear(); | 94 chain.clear(); |
| 95 is_public = false; | 95 is_permitted = false; |
| 96 EXPECT_TRUE(checker->IsDependencyOf(&b_, &a_, &chain, &is_public)); | 96 EXPECT_TRUE(checker->IsDependencyOf(&b_, &a_, &chain, &is_permitted)); |
| 97 ASSERT_EQ(2u, chain.size()); | 97 ASSERT_EQ(2u, chain.size()); |
| 98 EXPECT_EQ(&b_, chain[0]); | 98 EXPECT_EQ(HeaderChecker::ChainLink(&b_, true), chain[0]); |
| 99 EXPECT_EQ(&a_, chain[1]); | 99 EXPECT_EQ(HeaderChecker::ChainLink(&a_, true), chain[1]); |
| 100 EXPECT_TRUE(is_public); | 100 EXPECT_TRUE(is_permitted); |
| 101 | 101 |
| 102 // A indirectly depends on C. The "public" dependency path through B should | 102 // A indirectly depends on C. The "public" dependency path through B should |
| 103 // be identified. | 103 // be identified. |
| 104 chain.clear(); | 104 chain.clear(); |
| 105 is_public = false; | 105 is_permitted = false; |
| 106 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, &chain, &is_public)); | 106 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, &chain, &is_permitted)); |
| 107 ASSERT_EQ(3u, chain.size()); | 107 ASSERT_EQ(3u, chain.size()); |
| 108 EXPECT_EQ(&c_, chain[0]); | 108 EXPECT_EQ(HeaderChecker::ChainLink(&c_, true), chain[0]); |
| 109 EXPECT_EQ(&b_, chain[1]); | 109 EXPECT_EQ(HeaderChecker::ChainLink(&b_, true), chain[1]); |
| 110 EXPECT_EQ(&a_, chain[2]); | 110 EXPECT_EQ(HeaderChecker::ChainLink(&a_, true), chain[2]); |
| 111 EXPECT_TRUE(is_public); | 111 EXPECT_TRUE(is_permitted); |
| 112 | 112 |
| 113 // C does not depend on A. | 113 // C does not depend on A. |
| 114 chain.clear(); | 114 chain.clear(); |
| 115 is_public = false; | 115 is_permitted = false; |
| 116 EXPECT_FALSE(checker->IsDependencyOf(&a_, &c_, &chain, &is_public)); | 116 EXPECT_FALSE(checker->IsDependencyOf(&a_, &c_, &chain, &is_permitted)); |
| 117 EXPECT_TRUE(chain.empty()); | 117 EXPECT_TRUE(chain.empty()); |
| 118 EXPECT_FALSE(is_public); | 118 EXPECT_FALSE(is_permitted); |
| 119 | 119 |
| 120 // Add a private A -> C dependency. This should not be detected since it's | 120 // Remove the B -> C public dependency, leaving P's private dep on C the only |
| 121 // private, even though it's shorter than the A -> B -> C one. | 121 // path from A to C. This should now be found. |
| 122 chain.clear(); | 122 chain.clear(); |
| 123 is_public = false; | 123 EXPECT_EQ(&c_, b_.public_deps()[0].ptr); // Validate it's the right one. |
| 124 a_.private_deps().push_back(LabelTargetPair(&c_)); | 124 b_.public_deps().erase(b_.public_deps().begin()); |
| 125 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, &chain, &is_public)); | 125 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, &chain, &is_permitted)); |
| 126 EXPECT_EQ(&c_, chain[0]); | 126 EXPECT_EQ(3u, chain.size()); |
| 127 EXPECT_EQ(&b_, chain[1]); | 127 EXPECT_EQ(HeaderChecker::ChainLink(&c_, false), chain[0]); |
| 128 EXPECT_EQ(&a_, chain[2]); | 128 EXPECT_EQ(HeaderChecker::ChainLink(&p, true), chain[1]); |
| 129 EXPECT_TRUE(is_public); | 129 EXPECT_EQ(HeaderChecker::ChainLink(&a_, true), chain[2]); |
| 130 EXPECT_FALSE(is_permitted); |
| 130 | 131 |
| 131 // Remove the B -> C public dependency, leaving A's private dep on C the only | 132 // P privately depends on C. That dependency should be OK since it's only |
| 132 // path. This should now be found. | 133 // one hop. |
| 133 chain.clear(); | 134 chain.clear(); |
| 134 EXPECT_EQ(&c_, b_.public_deps()[0].ptr); // Validate it's the right one. | 135 is_permitted = false; |
| 135 b_.public_deps().erase(b_.public_deps().begin()); | 136 EXPECT_TRUE(checker->IsDependencyOf(&c_, &p, &chain, &is_permitted)); |
| 136 EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, &chain, &is_public)); | 137 ASSERT_EQ(2u, chain.size()); |
| 137 EXPECT_EQ(&c_, chain[0]); | 138 EXPECT_EQ(HeaderChecker::ChainLink(&c_, false), chain[0]); |
| 138 EXPECT_EQ(&a_, chain[1]); | 139 EXPECT_EQ(HeaderChecker::ChainLink(&p, true), chain[1]); |
| 139 EXPECT_FALSE(is_public); | 140 EXPECT_TRUE(is_permitted); |
| 140 } | 141 } |
| 141 | 142 |
| 142 TEST_F(HeaderCheckerTest, CheckInclude) { | 143 TEST_F(HeaderCheckerTest, CheckInclude) { |
| 143 InputFile input_file(SourceFile("//some_file.cc")); | 144 InputFile input_file(SourceFile("//some_file.cc")); |
| 144 input_file.SetContents(std::string()); | 145 input_file.SetContents(std::string()); |
| 145 LocationRange range; // Dummy value. | 146 LocationRange range; // Dummy value. |
| 146 | 147 |
| 147 // Add a disconnected target d with a header to check that you have to have | 148 // Add a disconnected target d with a header to check that you have to have |
| 148 // to depend on a target listing a header. | 149 // to depend on a target listing a header. |
| 149 SourceFile d_header("//d_header.h"); | 150 SourceFile d_header("//d_header.h"); |
| 150 d_.sources().push_back(SourceFile(d_header)); | 151 d_.sources().push_back(SourceFile(d_header)); |
| 151 | 152 |
| 152 // Add a header on B and say everything in B is public. | 153 // Add a header on B and say everything in B is public. |
| 153 SourceFile b_public("//b_public.h"); | 154 SourceFile b_public("//b_public.h"); |
| 154 b_.sources().push_back(b_public); | 155 b_.sources().push_back(b_public); |
| 155 c_.set_all_headers_public(true); | 156 c_.set_all_headers_public(true); |
| 156 | 157 |
| 157 // Add a public and private header on C. | 158 // Add a public and private header on C. |
| 158 SourceFile c_public("//c_public.h"); | 159 SourceFile c_public("//c_public.h"); |
| 159 SourceFile c_private("//c_private.h"); | 160 SourceFile c_private("//c_private.h"); |
| 160 c_.sources().push_back(c_private); | 161 c_.sources().push_back(c_private); |
| 161 c_.public_headers().push_back(c_public); | 162 c_.public_headers().push_back(c_public); |
| 162 c_.set_all_headers_public(false); | 163 c_.set_all_headers_public(false); |
| 163 | 164 |
| 164 targets_.push_back(&d_); | |
| 165 scoped_refptr<HeaderChecker> checker( | 165 scoped_refptr<HeaderChecker> checker( |
| 166 new HeaderChecker(setup_.build_settings(), targets_)); | 166 new HeaderChecker(setup_.build_settings(), targets_)); |
| 167 | 167 |
| 168 // A file in target A can't include a header from D because A has no | 168 // A file in target A can't include a header from D because A has no |
| 169 // dependency on D. | 169 // dependency on D. |
| 170 Err err; | 170 Err err; |
| 171 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, d_header, range, &err)); | 171 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, d_header, range, &err)); |
| 172 EXPECT_TRUE(err.has_error()); | 172 EXPECT_TRUE(err.has_error()); |
| 173 | 173 |
| 174 // A can include the public header in B. | 174 // A can include the public header in B. |
| 175 err = Err(); | 175 err = Err(); |
| 176 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, b_public, range, &err)); | 176 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, b_public, range, &err)); |
| 177 EXPECT_FALSE(err.has_error()); | 177 EXPECT_FALSE(err.has_error()); |
| 178 | 178 |
| 179 // Check A depending on the public and private headers in C. | 179 // Check A depending on the public and private headers in C. |
| 180 err = Err(); | 180 err = Err(); |
| 181 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, c_public, range, &err)); | 181 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, c_public, range, &err)); |
| 182 EXPECT_FALSE(err.has_error()); | 182 EXPECT_FALSE(err.has_error()); |
| 183 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, c_private, range, &err)); | 183 EXPECT_FALSE(checker->CheckInclude(&a_, input_file, c_private, range, &err)); |
| 184 EXPECT_TRUE(err.has_error()); | 184 EXPECT_TRUE(err.has_error()); |
| 185 | 185 |
| 186 // A can depend on a random file unknown to the build. | 186 // A can depend on a random file unknown to the build. |
| 187 err = Err(); | 187 err = Err(); |
| 188 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, SourceFile("//random.h"), | 188 EXPECT_TRUE(checker->CheckInclude(&a_, input_file, SourceFile("//random.h"), |
| 189 range, &err)); | 189 range, &err)); |
| 190 EXPECT_FALSE(err.has_error()); | 190 EXPECT_FALSE(err.has_error()); |
| 191 } | 191 } |
| 192 | 192 |
| 193 // A public chain of dependencies should always be identified first, even if |
| 194 // it is longer than a private one. |
| 195 TEST_F(HeaderCheckerTest, PublicFirst) { |
| 196 // Now make a A -> Z -> D private dependency chain (one shorter than the |
| 197 // public one to get to D). |
| 198 Target z(setup_.settings(), Label(SourceDir("//a/"), "a")); |
| 199 z.set_output_type(Target::SOURCE_SET); |
| 200 Err err; |
| 201 EXPECT_TRUE(z.SetToolchain(setup_.toolchain(), &err)); |
| 202 z.private_deps().push_back(LabelTargetPair(&d_)); |
| 203 EXPECT_TRUE(z.OnResolved(&err)); |
| 204 targets_.push_back(&z); |
| 205 |
| 206 a_.private_deps().push_back(LabelTargetPair(&z)); |
| 207 |
| 208 // Check that D can be found from A, but since it's private, it will be |
| 209 // marked as not permitted. |
| 210 bool is_permitted = false; |
| 211 HeaderChecker::Chain chain; |
| 212 scoped_refptr<HeaderChecker> checker( |
| 213 new HeaderChecker(setup_.build_settings(), targets_)); |
| 214 EXPECT_TRUE(checker->IsDependencyOf(&d_, &a_, &chain, &is_permitted)); |
| 215 |
| 216 EXPECT_FALSE(is_permitted); |
| 217 ASSERT_EQ(3u, chain.size()); |
| 218 EXPECT_EQ(HeaderChecker::ChainLink(&d_, false), chain[0]); |
| 219 EXPECT_EQ(HeaderChecker::ChainLink(&z, false), chain[1]); |
| 220 EXPECT_EQ(HeaderChecker::ChainLink(&a_, true), chain[2]); |
| 221 |
| 222 // Hook up D to the existing public A -> B -> C chain to make a long one, and |
| 223 // search for D again. |
| 224 c_.public_deps().push_back(LabelTargetPair(&d_)); |
| 225 checker = new HeaderChecker(setup_.build_settings(), targets_); |
| 226 chain.clear(); |
| 227 EXPECT_TRUE(checker->IsDependencyOf(&d_, &a_, &chain, &is_permitted)); |
| 228 |
| 229 // This should have found the long public one. |
| 230 EXPECT_TRUE(is_permitted); |
| 231 ASSERT_EQ(4u, chain.size()); |
| 232 EXPECT_EQ(HeaderChecker::ChainLink(&d_, true), chain[0]); |
| 233 EXPECT_EQ(HeaderChecker::ChainLink(&c_, true), chain[1]); |
| 234 EXPECT_EQ(HeaderChecker::ChainLink(&b_, true), chain[2]); |
| 235 EXPECT_EQ(HeaderChecker::ChainLink(&a_, true), chain[3]); |
| 236 } |
| 237 |
| 193 // Checks that the allow_circular_includes_from list works. | 238 // Checks that the allow_circular_includes_from list works. |
| 194 TEST_F(HeaderCheckerTest, CheckIncludeAllowCircular) { | 239 TEST_F(HeaderCheckerTest, CheckIncludeAllowCircular) { |
| 195 InputFile input_file(SourceFile("//some_file.cc")); | 240 InputFile input_file(SourceFile("//some_file.cc")); |
| 196 input_file.SetContents(std::string()); | 241 input_file.SetContents(std::string()); |
| 197 LocationRange range; // Dummy value. | 242 LocationRange range; // Dummy value. |
| 198 | 243 |
| 199 // Add an include file to A. | 244 // Add an include file to A. |
| 200 SourceFile a_public("//a_public.h"); | 245 SourceFile a_public("//a_public.h"); |
| 201 a_.sources().push_back(a_public); | 246 a_.sources().push_back(a_public); |
| 202 | 247 |
| 203 scoped_refptr<HeaderChecker> checker( | 248 scoped_refptr<HeaderChecker> checker( |
| 204 new HeaderChecker(setup_.build_settings(), targets_)); | 249 new HeaderChecker(setup_.build_settings(), targets_)); |
| 205 | 250 |
| 206 // A depends on B. So B normally can't include headers from A. | 251 // A depends on B. So B normally can't include headers from A. |
| 207 Err err; | 252 Err err; |
| 208 EXPECT_FALSE(checker->CheckInclude(&b_, input_file, a_public, range, &err)); | 253 EXPECT_FALSE(checker->CheckInclude(&b_, input_file, a_public, range, &err)); |
| 209 EXPECT_TRUE(err.has_error()); | 254 EXPECT_TRUE(err.has_error()); |
| 210 | 255 |
| 211 // Add an allow_circular_includes_from on A that lists B. | 256 // Add an allow_circular_includes_from on A that lists B. |
| 212 a_.allow_circular_includes_from().insert(b_.label()); | 257 a_.allow_circular_includes_from().insert(b_.label()); |
| 213 | 258 |
| 214 // Now the include from B to A should be allowed. | 259 // Now the include from B to A should be allowed. |
| 215 err = Err(); | 260 err = Err(); |
| 216 EXPECT_TRUE(checker->CheckInclude(&b_, input_file, a_public, range, &err)); | 261 EXPECT_TRUE(checker->CheckInclude(&b_, input_file, a_public, range, &err)); |
| 217 EXPECT_FALSE(err.has_error()); | 262 EXPECT_FALSE(err.has_error()); |
| 218 } | 263 } |
| OLD | NEW |