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 |