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 |