blob: 2a1de7415779d5534c63d43e326c68df8cc4f577 [file]
// Copyright 2026 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gn/binary_target_generator.h"
#include "gn/err.h"
#include "gn/label_pattern.h"
#include "gn/scheduler.h"
#include "gn/target.h"
#include "gn/test_with_scheduler.h"
#include "gn/test_with_scope.h"
#include "util/test/test.h"
using BinaryTargetGeneratorTest = TestWithScheduler;
TEST_F(BinaryTargetGeneratorTest, NonModuleTarget) {
TestWithScope setup;
Scope::ItemVector items_;
setup.scope()->set_item_collector(&items_);
setup.scope()->set_source_dir(SourceDir("//test/"));
TestParseInput input(
R"(static_library("foo") {
generate_modulemap = "textual"
sources = [ "//foo.c" ]
})");
ASSERT_SUCCESS(input);
Err err;
input.parsed()->Execute(setup.scope(), &err);
ASSERT_SUCCESS(err);
ASSERT_EQ(1u, items_.size());
Target* target = items_[0]->AsTarget();
ASSERT_TRUE(target);
EXPECT_TRUE(target->module_type().none());
}
TEST_F(BinaryTargetGeneratorTest, GeneratedModuleMapAllPublic) {
TestWithScope setup;
Scope::ItemVector items_;
setup.scope()->set_item_collector(&items_);
setup.scope()->set_source_dir(SourceDir("//test/"));
TestParseInput input(
R"(static_library("foo") {
generate_modulemap = "textual"
sources = [ "//foo.cc", "//foo.h" ]
})");
ASSERT_SUCCESS(input);
Err err;
input.parsed()->Execute(setup.scope(), &err);
ASSERT_SUCCESS(err);
ASSERT_EQ(1u, items_.size());
Target* target = items_[0]->AsTarget();
ASSERT_TRUE(target);
EXPECT_TRUE(target->module_type().test(Target::HAS_MODULEMAP));
EXPECT_TRUE(target->module_type().test(Target::MODULEMAP_IS_GENERATED));
EXPECT_TRUE(target->module_type().test(Target::MODULEMAP_IS_TEXTUAL));
}
TEST_F(BinaryTargetGeneratorTest, GeneratedModuleMap) {
TestWithScope setup;
Scope::ItemVector items_;
setup.scope()->set_item_collector(&items_);
setup.scope()->set_source_dir(SourceDir("//test/"));
TestParseInput input(
R"(static_library("foo") {
generate_modulemap = "textual"
sources = [ "//foo.cc" ]
public = ["//foo.h"]
})");
ASSERT_SUCCESS(input);
Err err;
input.parsed()->Execute(setup.scope(), &err);
ASSERT_SUCCESS(err);
ASSERT_EQ(1u, items_.size());
Target* target = items_[0]->AsTarget();
ASSERT_TRUE(target);
EXPECT_TRUE(target->module_type().test(Target::HAS_MODULEMAP));
EXPECT_TRUE(target->module_type().test(Target::MODULEMAP_IS_GENERATED));
EXPECT_TRUE(target->module_type().test(Target::MODULEMAP_IS_TEXTUAL));
}
TEST_F(BinaryTargetGeneratorTest, CheckIncludesStrict) {
TestWithScope setup;
Scope::ItemVector items_;
setup.scope()->set_item_collector(&items_);
setup.scope()->set_source_dir(SourceDir("//test/"));
// Check default value is false.
{
TestParseInput input(
R"(static_library("foo") {
sources = [ "//foo.cc" ]
})");
ASSERT_SUCCESS(input);
Err err;
input.parsed()->Execute(setup.scope(), &err);
ASSERT_SUCCESS(err);
ASSERT_EQ(1u, items_.size());
Target* target = items_[0]->AsTarget();
ASSERT_TRUE(target);
EXPECT_FALSE(target->check_includes_strict());
items_.clear();
}
// Check overriding to true.
{
TestParseInput input(
R"(static_library("bar") {
sources = [ "//bar.cc" ]
check_includes_strict = true
})");
ASSERT_SUCCESS(input);
Err err;
input.parsed()->Execute(setup.scope(), &err);
ASSERT_SUCCESS(err);
ASSERT_EQ(1u, items_.size());
Target* target = items_[0]->AsTarget();
ASSERT_TRUE(target);
EXPECT_TRUE(target->check_includes_strict());
items_.clear();
}
}
TEST_F(BinaryTargetGeneratorTest, AllowCircularIncludesAllowlist) {
TestWithScope setup;
Scope::ItemVector items_;
setup.scope()->set_item_collector(&items_);
setup.scope()->set_source_dir(SourceDir("//test/"));
// Create a dep for foo to reference.
Target* dep =
new Target(setup.settings(), Label(SourceDir("//test/"), "dep"));
dep->set_output_type(Target::SOURCE_SET);
dep->visibility().SetPublic();
Err err_setup;
dep->SetToolchain(setup.toolchain(), &err_setup);
dep->OnResolved(&err_setup);
items_.push_back(std::unique_ptr<Item>(dep));
TestParseInput input(
R"(static_library("foo") {
sources = [ "//foo.cc" ]
deps = [ ":dep" ]
allow_circular_includes_from = [ ":dep" ]
})");
ASSERT_FALSE(input.has_error());
// No allowlist -> allowed
{
Err err;
input.parsed()->Execute(setup.scope(), &err);
EXPECT_FALSE(err.has_error()) << err.message();
}
// In allowlist -> Allowed
{
auto allowlist = std::make_unique<std::vector<LabelPattern>>();
allowlist->push_back(LabelPattern(LabelPattern::MATCH, SourceDir("//test/"),
"foo", Label()));
setup.build_settings()->set_allow_circular_includes_from_allowlist(
std::move(allowlist));
Err err;
input.parsed()->Execute(setup.scope(), &err);
EXPECT_FALSE(err.has_error()) << err.message();
}
// Pattern in allowlist -> Allowed
{
auto allowlist = std::make_unique<std::vector<LabelPattern>>();
allowlist->push_back(LabelPattern(LabelPattern::DIRECTORY,
SourceDir("//test/"), "", Label()));
setup.build_settings()->set_allow_circular_includes_from_allowlist(
std::move(allowlist));
Err err;
input.parsed()->Execute(setup.scope(), &err);
EXPECT_FALSE(err.has_error()) << err.message();
}
// Not in allowlist -> Denied
{
auto allowlist = std::make_unique<std::vector<LabelPattern>>();
allowlist->push_back(LabelPattern(LabelPattern::MATCH,
SourceDir("//other/"), "other", Label()));
setup.build_settings()->set_allow_circular_includes_from_allowlist(
std::move(allowlist));
Err err;
input.parsed()->Execute(setup.scope(), &err);
EXPECT_TRUE(err.has_error());
}
}