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
3 // found in the LICENSE file.
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "tools/gn/config.h"
9 #include "tools/gn/header_checker.h"
10 #include "tools/gn/scheduler.h"
11 #include "tools/gn/target.h"
12 #include "tools/gn/test_with_scope.h"
16 class HeaderCheckerTest
: public testing::Test
{
19 : a_(setup_
.settings(), Label(SourceDir("//a/"), "a")),
20 b_(setup_
.settings(), Label(SourceDir("//b/"), "a")),
21 c_(setup_
.settings(), Label(SourceDir("//c/"), "c")),
22 d_(setup_
.settings(), Label(SourceDir("//d/"), "d")) {
23 a_
.deps().push_back(LabelTargetPair(&b_
));
24 b_
.deps().push_back(LabelTargetPair(&c_
));
26 // Start with all public visibility.
27 a_
.visibility().SetPublic();
28 b_
.visibility().SetPublic();
29 c_
.visibility().SetPublic();
30 d_
.visibility().SetPublic();
32 targets_
.push_back(&a_
);
33 targets_
.push_back(&b_
);
34 targets_
.push_back(&c_
);
35 targets_
.push_back(&d_
);
43 // Some headers that are automatically set up with a dependency chain.
50 std::vector
<const Target
*> targets_
;
55 TEST_F(HeaderCheckerTest
, IsDependencyOf
) {
56 scoped_refptr
<HeaderChecker
> checker(
57 new HeaderChecker(setup_
.build_settings(), targets_
));
59 std::vector
<const Target
*> chain
;
60 EXPECT_FALSE(checker
->IsDependencyOf(&a_
, &a_
, false, &chain
, NULL
));
63 EXPECT_TRUE(checker
->IsDependencyOf(&b_
, &a_
, false, &chain
, NULL
));
64 ASSERT_EQ(2u, chain
.size());
65 EXPECT_EQ(&b_
, chain
[0]);
66 EXPECT_EQ(&a_
, chain
[1]);
69 EXPECT_TRUE(checker
->IsDependencyOf(&c_
, &a_
, false, &chain
, NULL
));
70 ASSERT_EQ(3u, chain
.size());
71 EXPECT_EQ(&c_
, chain
[0]);
72 EXPECT_EQ(&b_
, chain
[1]);
73 EXPECT_EQ(&a_
, chain
[2]);
76 EXPECT_FALSE(checker
->IsDependencyOf(&a_
, &c_
, false, &chain
, NULL
));
77 EXPECT_TRUE(chain
.empty());
79 // If an a -> c dependency exists, this should be chosen for the chain.
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]);
87 TEST_F(HeaderCheckerTest
, IsDependencyOf_ForwardsDirectDependentConfigs
) {
88 scoped_refptr
<HeaderChecker
> checker(
89 new HeaderChecker(setup_
.build_settings(), targets_
));
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]);
100 EXPECT_EQ(&b_
, chain
[1]);
101 EXPECT_EQ(&a_
, chain
[2]);
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.
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(
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]);
119 // d also forwards direct-dependent configs if it is a group.
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]);
132 // A direct dependency a -> c carries direct-dependent configs.
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]);
141 EXPECT_EQ(&a_
, chain
[1]);
144 TEST_F(HeaderCheckerTest
, CheckInclude
) {
145 InputFile
input_file(SourceFile("//some_file.cc"));
146 input_file
.SetContents(std::string());
147 LocationRange range
; // Dummy value.
149 // Add a disconnected target d with a header to check that you have to have
150 // to depend on a target listing a header.
151 SourceFile
d_header("//d_header.h");
152 d_
.sources().push_back(SourceFile(d_header
));
154 // Add a header on B and say everything in B is public.
155 SourceFile
b_public("//b_public.h");
156 b_
.sources().push_back(b_public
);
157 c_
.set_all_headers_public(true);
159 // Add a public and private header on C.
160 SourceFile
c_public("//c_public.h");
161 SourceFile
c_private("//c_private.h");
162 c_
.sources().push_back(c_private
);
163 c_
.public_headers().push_back(c_public
);
164 c_
.set_all_headers_public(false);
166 targets_
.push_back(&d_
);
167 scoped_refptr
<HeaderChecker
> checker(
168 new HeaderChecker(setup_
.build_settings(), targets_
));
170 // A file in target A can't include a header from D because A has no
173 EXPECT_FALSE(checker
->CheckInclude(&a_
, input_file
, d_header
, range
, &err
));
174 EXPECT_TRUE(err
.has_error());
176 // A can include the public header in B.
178 EXPECT_TRUE(checker
->CheckInclude(&a_
, input_file
, b_public
, range
, &err
));
179 EXPECT_FALSE(err
.has_error());
181 // Check A depending on the public and private headers in C.
183 EXPECT_TRUE(checker
->CheckInclude(&a_
, input_file
, c_public
, range
, &err
));
184 EXPECT_FALSE(err
.has_error());
185 EXPECT_FALSE(checker
->CheckInclude(&a_
, input_file
, c_private
, range
, &err
));
186 EXPECT_TRUE(err
.has_error());
188 // A can depend on a random file unknown to the build.
190 EXPECT_TRUE(checker
->CheckInclude(&a_
, input_file
, SourceFile("//random.h"),
192 EXPECT_FALSE(err
.has_error());
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());
198 EXPECT_FALSE(checker
->CheckInclude(&a_
, input_file
, c_public
, range
, &err
));
199 EXPECT_TRUE(err
.has_error());
200 c_
.visibility().SetPublic();
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.
205 Config
direct(setup_
.settings(), Label(SourceDir("//c/"), "config"));
206 direct
.config_values().cflags().push_back("-DSOME_DEFINE");
208 c_
.direct_dependent_configs().push_back(LabelConfigPair(&direct
));
210 EXPECT_FALSE(checker
->CheckInclude(&a_
, input_file
, c_public
, range
, &err
));
211 EXPECT_TRUE(err
.has_error());
213 b_
.forward_dependent_configs().push_back(LabelTargetPair(&c_
));
215 EXPECT_TRUE(checker
->CheckInclude(&a_
, input_file
, c_public
, range
, &err
));
216 EXPECT_FALSE(err
.has_error());
218 b_
.forward_dependent_configs().clear();
219 b_
.set_output_type(Target::GROUP
);
221 EXPECT_TRUE(checker
->CheckInclude(&a_
, input_file
, c_public
, range
, &err
));
222 EXPECT_FALSE(err
.has_error());
224 b_
.set_output_type(Target::UNKNOWN
);
225 c_
.direct_dependent_configs().clear();
229 // Checks that the allow_circular_includes_from list works.
230 TEST_F(HeaderCheckerTest
, CheckIncludeAllowCircular
) {
231 InputFile
input_file(SourceFile("//some_file.cc"));
232 input_file
.SetContents(std::string());
233 LocationRange range
; // Dummy value.
235 // Add an include file to A.
236 SourceFile
a_public("//a_public.h");
237 a_
.sources().push_back(a_public
);
239 scoped_refptr
<HeaderChecker
> checker(
240 new HeaderChecker(setup_
.build_settings(), targets_
));
242 // A depends on B. So B normally can't include headers from A.
244 EXPECT_FALSE(checker
->CheckInclude(&b_
, input_file
, a_public
, range
, &err
));
245 EXPECT_TRUE(err
.has_error());
247 // Add an allow_circular_includes_from on A that lists B.
248 a_
.allow_circular_includes_from().insert(b_
.label());
250 // Now the include from B to A should be allowed.
252 EXPECT_TRUE(checker
->CheckInclude(&b_
, input_file
, a_public
, range
, &err
));
253 EXPECT_FALSE(err
.has_error());
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"));
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
));
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
);
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
));
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
));