Index: tools/gn/target_unittest.cc |
diff --git a/tools/gn/target_unittest.cc b/tools/gn/target_unittest.cc |
index 9bf0c30df28b3d6dfbe046be3f067c574c7c93cd..25e3aabc4578cf4278958d5ebffedf673132ebfb 100644 |
--- a/tools/gn/target_unittest.cc |
+++ b/tools/gn/target_unittest.cc |
@@ -14,37 +14,47 @@ |
// deps. |
TEST(Target, GroupDeps) { |
TestWithScope setup; |
+ Err err; |
+ |
+ // Used as the origin for the not-automatically-set deps. |
+ IdentifierNode origin; |
// Two low-level targets. |
Target x(setup.settings(), Label(SourceDir("//component/"), "x")); |
x.set_output_type(Target::STATIC_LIBRARY); |
x.SetToolchain(setup.toolchain()); |
- x.OnResolved(); |
+ ASSERT_TRUE(x.OnResolved(&err)); |
Target y(setup.settings(), Label(SourceDir("//component/"), "y")); |
y.set_output_type(Target::STATIC_LIBRARY); |
y.SetToolchain(setup.toolchain()); |
- y.OnResolved(); |
+ ASSERT_TRUE(y.OnResolved(&err)); |
// Make a group for both x and y. |
Target g(setup.settings(), Label(SourceDir("//group/"), "g")); |
g.set_output_type(Target::GROUP); |
+ g.visibility().SetPublic(); |
g.deps().push_back(LabelTargetPair(&x)); |
+ g.deps()[0].origin = &origin; |
g.deps().push_back(LabelTargetPair(&y)); |
+ g.deps()[1].origin = &origin; |
// Random placeholder target so we can see the group's deps get inserted at |
// the right place. |
Target b(setup.settings(), Label(SourceDir("//app/"), "b")); |
b.set_output_type(Target::STATIC_LIBRARY); |
b.SetToolchain(setup.toolchain()); |
- b.OnResolved(); |
+ b.visibility().SetPublic(); |
+ ASSERT_TRUE(b.OnResolved(&err)); |
// Make a target depending on the group and "b". OnResolved will expand. |
Target a(setup.settings(), Label(SourceDir("//app/"), "a")); |
a.set_output_type(Target::EXECUTABLE); |
a.deps().push_back(LabelTargetPair(&g)); |
+ a.deps()[0].origin = &origin; |
a.deps().push_back(LabelTargetPair(&b)); |
+ a.deps()[1].origin = &origin; |
a.SetToolchain(setup.toolchain()); |
- a.OnResolved(); |
+ ASSERT_TRUE(a.OnResolved(&err)); |
// The group's deps should be inserted after the group itself in the deps |
// list, so we should get "g, x, y, b" |
@@ -53,12 +63,20 @@ TEST(Target, GroupDeps) { |
EXPECT_EQ(&x, a.deps()[1].ptr); |
EXPECT_EQ(&y, a.deps()[2].ptr); |
EXPECT_EQ(&b, a.deps()[3].ptr); |
+ |
+ // The "regular" deps on a should have the origin set. The automatically |
+ // expanded ones will have a null origin so we know they are generated. |
+ EXPECT_EQ(&origin, a.deps()[0].origin); |
+ EXPECT_EQ(NULL, a.deps()[1].origin); |
+ EXPECT_EQ(NULL, a.deps()[2].origin); |
+ EXPECT_EQ(&origin, a.deps()[3].origin); |
} |
// Tests that lib[_dir]s are inherited across deps boundaries for static |
// libraries but not executables. |
TEST(Target, LibInheritance) { |
TestWithScope setup; |
+ Err err; |
const std::string lib("foo"); |
const SourceDir libdir("/foo_dir/"); |
@@ -69,7 +87,7 @@ TEST(Target, LibInheritance) { |
z.config_values().libs().push_back(lib); |
z.config_values().lib_dirs().push_back(libdir); |
z.SetToolchain(setup.toolchain()); |
- z.OnResolved(); |
+ ASSERT_TRUE(z.OnResolved(&err)); |
// All lib[_dir]s should be set when target is resolved. |
ASSERT_EQ(1u, z.all_libs().size()); |
@@ -87,7 +105,7 @@ TEST(Target, LibInheritance) { |
shared.config_values().lib_dirs().push_back(second_libdir); |
shared.deps().push_back(LabelTargetPair(&z)); |
shared.SetToolchain(setup.toolchain()); |
- shared.OnResolved(); |
+ ASSERT_TRUE(shared.OnResolved(&err)); |
ASSERT_EQ(2u, shared.all_libs().size()); |
EXPECT_EQ(second_lib, shared.all_libs()[0]); |
@@ -101,7 +119,7 @@ TEST(Target, LibInheritance) { |
exec.set_output_type(Target::EXECUTABLE); |
exec.deps().push_back(LabelTargetPair(&shared)); |
exec.SetToolchain(setup.toolchain()); |
- exec.OnResolved(); |
+ ASSERT_TRUE(exec.OnResolved(&err)); |
EXPECT_EQ(0u, exec.all_libs().size()); |
EXPECT_EQ(0u, exec.all_lib_dirs().size()); |
} |
@@ -110,6 +128,7 @@ TEST(Target, LibInheritance) { |
// forward_dependent_configs_from |
TEST(Target, DependentConfigs) { |
TestWithScope setup; |
+ Err err; |
// Set up a dependency chain of a -> b -> c |
Target a(setup.settings(), Label(SourceDir("//foo/"), "a")); |
@@ -136,9 +155,9 @@ TEST(Target, DependentConfigs) { |
Config direct(setup.settings(), Label(SourceDir("//foo/"), "direct")); |
c.direct_dependent_configs().push_back(LabelConfigPair(&direct)); |
- c.OnResolved(); |
- b.OnResolved(); |
- a.OnResolved(); |
+ ASSERT_TRUE(c.OnResolved(&err)); |
+ ASSERT_TRUE(b.OnResolved(&err)); |
+ ASSERT_TRUE(a.OnResolved(&err)); |
// B should have gotten both dependent configs from C. |
ASSERT_EQ(2u, b.configs().size()); |
@@ -163,8 +182,8 @@ TEST(Target, DependentConfigs) { |
b_fwd.deps().push_back(LabelTargetPair(&c)); |
b_fwd.forward_dependent_configs().push_back(LabelTargetPair(&c)); |
- b_fwd.OnResolved(); |
- a_fwd.OnResolved(); |
+ ASSERT_TRUE(b_fwd.OnResolved(&err)); |
+ ASSERT_TRUE(a_fwd.OnResolved(&err)); |
// A_fwd should now have both configs. |
ASSERT_EQ(2u, a_fwd.configs().size()); |
@@ -178,6 +197,7 @@ TEST(Target, DependentConfigs) { |
// group's deps' dependent configs. |
TEST(Target, ForwardDependentConfigsFromGroups) { |
TestWithScope setup; |
+ Err err; |
Target a(setup.settings(), Label(SourceDir("//foo/"), "a")); |
a.set_output_type(Target::EXECUTABLE); |
@@ -198,9 +218,9 @@ TEST(Target, ForwardDependentConfigsFromGroups) { |
// A forwards the dependent configs from B. |
a.forward_dependent_configs().push_back(LabelTargetPair(&b)); |
- c.OnResolved(); |
- b.OnResolved(); |
- a.OnResolved(); |
+ ASSERT_TRUE(c.OnResolved(&err)); |
+ ASSERT_TRUE(b.OnResolved(&err)); |
+ ASSERT_TRUE(a.OnResolved(&err)); |
// The config should now be on A, and in A's direct dependent configs. |
ASSERT_EQ(1u, a.configs().size()); |
@@ -211,6 +231,7 @@ TEST(Target, ForwardDependentConfigsFromGroups) { |
TEST(Target, InheritLibs) { |
TestWithScope setup; |
+ Err err; |
// Create a dependency chain: |
// A (executable) -> B (shared lib) -> C (static lib) -> D (source set) |
@@ -230,10 +251,10 @@ TEST(Target, InheritLibs) { |
b.deps().push_back(LabelTargetPair(&c)); |
c.deps().push_back(LabelTargetPair(&d)); |
- d.OnResolved(); |
- c.OnResolved(); |
- b.OnResolved(); |
- a.OnResolved(); |
+ ASSERT_TRUE(d.OnResolved(&err)); |
+ ASSERT_TRUE(c.OnResolved(&err)); |
+ ASSERT_TRUE(b.OnResolved(&err)); |
+ ASSERT_TRUE(a.OnResolved(&err)); |
// C should have D in its inherited libs. |
const UniqueVector<const Target*>& c_inherited = c.inherited_libraries(); |
@@ -255,13 +276,14 @@ TEST(Target, InheritLibs) { |
TEST(Target, GetComputedOutputName) { |
TestWithScope setup; |
+ Err err; |
// Basic target with no prefix (executable type tool in the TestWithScope has |
// no prefix) or output name. |
Target basic(setup.settings(), Label(SourceDir("//foo/"), "bar")); |
basic.set_output_type(Target::EXECUTABLE); |
basic.SetToolchain(setup.toolchain()); |
- basic.OnResolved(); |
+ ASSERT_TRUE(basic.OnResolved(&err)); |
EXPECT_EQ("bar", basic.GetComputedOutputName(false)); |
EXPECT_EQ("bar", basic.GetComputedOutputName(true)); |
@@ -270,7 +292,7 @@ TEST(Target, GetComputedOutputName) { |
with_name.set_output_type(Target::EXECUTABLE); |
with_name.set_output_name("myoutput"); |
with_name.SetToolchain(setup.toolchain()); |
- with_name.OnResolved(); |
+ ASSERT_TRUE(with_name.OnResolved(&err)); |
EXPECT_EQ("myoutput", with_name.GetComputedOutputName(false)); |
EXPECT_EQ("myoutput", with_name.GetComputedOutputName(true)); |
@@ -279,7 +301,7 @@ TEST(Target, GetComputedOutputName) { |
Target with_prefix(setup.settings(), Label(SourceDir("//foo/"), "bar")); |
with_prefix.set_output_type(Target::STATIC_LIBRARY); |
with_prefix.SetToolchain(setup.toolchain()); |
- with_prefix.OnResolved(); |
+ ASSERT_TRUE(with_prefix.OnResolved(&err)); |
EXPECT_EQ("bar", with_prefix.GetComputedOutputName(false)); |
EXPECT_EQ("libbar", with_prefix.GetComputedOutputName(true)); |
@@ -289,7 +311,94 @@ TEST(Target, GetComputedOutputName) { |
dup_prefix.set_output_type(Target::STATIC_LIBRARY); |
dup_prefix.set_output_name("libbar"); |
dup_prefix.SetToolchain(setup.toolchain()); |
- dup_prefix.OnResolved(); |
+ ASSERT_TRUE(dup_prefix.OnResolved(&err)); |
EXPECT_EQ("libbar", dup_prefix.GetComputedOutputName(false)); |
EXPECT_EQ("libbar", dup_prefix.GetComputedOutputName(true)); |
} |
+ |
+// Test visibility failure case. |
+TEST(Target, VisibilityFails) { |
+ TestWithScope setup; |
+ Err err; |
+ |
+ Target b(setup.settings(), Label(SourceDir("//private/"), "b")); |
+ b.set_output_type(Target::STATIC_LIBRARY); |
+ b.SetToolchain(setup.toolchain()); |
+ b.visibility().SetPrivate(b.label().dir()); |
+ ASSERT_TRUE(b.OnResolved(&err)); |
+ |
+ // Make a target depending on "b". The dependency must have an origin to mark |
+ // it as user-set so we check visibility. This check should fail. |
+ Target a(setup.settings(), Label(SourceDir("//app/"), "a")); |
+ a.set_output_type(Target::EXECUTABLE); |
+ a.deps().push_back(LabelTargetPair(&b)); |
+ IdentifierNode origin; // Dummy origin. |
+ a.deps()[0].origin = &origin; |
+ a.SetToolchain(setup.toolchain()); |
+ ASSERT_FALSE(a.OnResolved(&err)); |
+} |
+ |
+// Tests that A -> Group -> B where the group is visible from A but B isn't, |
+// passes visibility even though the group's deps get expanded into A. |
+TEST(Target, VisibilityGroup) { |
+ TestWithScope setup; |
+ Err err; |
+ |
+ IdentifierNode origin; // Dummy origin. |
+ |
+ // B has private visibility. This lets the group see it since the group is in |
+ // the same directory. |
+ Target b(setup.settings(), Label(SourceDir("//private/"), "b")); |
+ b.set_output_type(Target::STATIC_LIBRARY); |
+ b.SetToolchain(setup.toolchain()); |
+ b.visibility().SetPrivate(b.label().dir()); |
+ ASSERT_TRUE(b.OnResolved(&err)); |
+ |
+ // The group has public visibility and depends on b. |
+ Target g(setup.settings(), Label(SourceDir("//private/"), "g")); |
+ g.set_output_type(Target::GROUP); |
+ g.SetToolchain(setup.toolchain()); |
+ g.deps().push_back(LabelTargetPair(&b)); |
+ g.deps()[0].origin = &origin; |
+ g.visibility().SetPublic(); |
+ ASSERT_TRUE(b.OnResolved(&err)); |
+ |
+ // Make a target depending on "g". This should succeed. |
+ Target a(setup.settings(), Label(SourceDir("//app/"), "a")); |
+ a.set_output_type(Target::EXECUTABLE); |
+ a.deps().push_back(LabelTargetPair(&g)); |
+ a.deps()[0].origin = &origin; |
+ a.SetToolchain(setup.toolchain()); |
+ ASSERT_TRUE(a.OnResolved(&err)); |
+} |
+ |
+// Verifies that only testonly targets can depend on other testonly targets. |
+// Many of the above dependency checking cases covered the non-testonly |
+// case. |
+TEST(Target, Testonly) { |
+ TestWithScope setup; |
+ Err err; |
+ |
+ // "testlib" is a test-only library. |
+ Target testlib(setup.settings(), Label(SourceDir("//test/"), "testlib")); |
+ testlib.set_testonly(true); |
+ testlib.set_output_type(Target::STATIC_LIBRARY); |
+ testlib.SetToolchain(setup.toolchain()); |
+ ASSERT_TRUE(testlib.OnResolved(&err)); |
+ |
+ // "test" is a test-only executable depending on testlib, this is OK. |
+ Target test(setup.settings(), Label(SourceDir("//test/"), "test")); |
+ test.set_testonly(true); |
+ test.set_output_type(Target::EXECUTABLE); |
+ test.deps().push_back(LabelTargetPair(&testlib)); |
+ test.SetToolchain(setup.toolchain()); |
+ ASSERT_TRUE(test.OnResolved(&err)); |
+ |
+ // "product" is a non-test depending on testlib. This should fail. |
+ Target product(setup.settings(), Label(SourceDir("//app/"), "product")); |
+ product.set_testonly(false); |
+ product.set_output_type(Target::EXECUTABLE); |
+ product.deps().push_back(LabelTargetPair(&testlib)); |
+ product.SetToolchain(setup.toolchain()); |
+ ASSERT_FALSE(product.OnResolved(&err)); |
+} |