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 TEST_F(HeaderCheckerTest, GetDependentConfigChainProblemIndex) {
230 // Assume we have a chain A -> B -> C -> D.
231 Target target_a(setup_.settings(), Label(SourceDir("//a/"), "a"));
232 Target target_b(setup_.settings(), Label(SourceDir("//b/"), "b"));
233 Target target_c(setup_.settings(), Label(SourceDir("//c/"), "c"));
234 Target target_d(setup_.settings(), Label(SourceDir("//d/"), "d"));
236 // C is a group, and B forwards deps from C, so A should get configs from D.
237 target_a.set_output_type(Target::SOURCE_SET);
238 target_b.set_output_type(Target::SOURCE_SET);
239 target_c.set_output_type(Target::GROUP);
240 target_d.set_output_type(Target::SOURCE_SET);
241 target_b.forward_dependent_configs().push_back(
242 LabelTargetPair(&target_c));
244 // Dependency chain goes from bottom to top.
245 std::vector<const Target*> chain;
246 chain.push_back(&target_d);
247 chain.push_back(&target_c);
248 chain.push_back(&target_b);
249 chain.push_back(&target_a);
251 // If C is not a group, it shouldn't work anymore.
252 target_c.set_output_type(Target::SOURCE_SET);
253 EXPECT_EQ(1u, HeaderChecker::GetDependentConfigChainProblemIndex(chain));
255 // Or if B stops forwarding from C, it shouldn't work anymore.
256 target_c.set_output_type(Target::GROUP);
257 target_b.forward_dependent_configs().clear();
258 EXPECT_EQ(2u, HeaderChecker::GetDependentConfigChainProblemIndex(chain));