blob: eadcb3e6c856bdb3efab0affd26c185fd036ece3 [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 <algorithm>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "gn/filesystem_utils.h"
#include "gn/functions.h"
#include "gn/input_file.h"
#include "gn/parse_tree.h"
#include "gn/test_with_scheduler.h"
#include "gn/test_with_scope.h"
#include "util/test/test.h"
class ExpandDirectoryTest : public TestWithScheduler {
protected:
ExpandDirectoryTest() {
CHECK(temp_dir_.CreateUniqueTempDir());
setup.build_settings()->SetRootPath(temp_dir_.GetPath());
}
base::ScopedTempDir temp_dir_;
TestWithScope setup;
std::unique_ptr<FunctionCallNode> SetupDefaultDirAndFunction(
InputFile* input_file,
base::FilePath dir) {
auto file1 = dir.AppendASCII("file1.txt");
auto file2 = dir.AppendASCII("file2.txt");
auto sub_dir = dir.AppendASCII("sub");
auto file3 = sub_dir.AppendASCII("file3.txt");
EXPECT_TRUE(base::CreateDirectory(sub_dir));
EXPECT_TRUE(WriteFile(file1, "content1", nullptr));
EXPECT_TRUE(WriteFile(file2, "content2", nullptr));
EXPECT_TRUE(WriteFile(file3, "content3", nullptr));
Location location(input_file, 1, 1);
Token token(location, Token::IDENTIFIER, "expand_directory");
auto function = std::make_unique<FunctionCallNode>();
function->set_function(token);
auto args = std::make_unique<ListNode>();
args->set_begin_token(token);
args->set_end(std::make_unique<EndNode>(token));
function->set_args(std::move(args));
auto allowlist = std::make_unique<SourceFileSet>();
allowlist->insert(input_file->name());
setup.build_settings()->set_expand_directory_allowlist(
std::move(allowlist));
return function;
}
};
TEST_F(ExpandDirectoryTest, Recursive) {
auto dir_path = temp_dir_.GetPath().AppendASCII("foo").AppendASCII("bar");
auto input_file = InputFile(SourceFile("//BUILD.gn"));
auto function = SetupDefaultDirAndFunction(&input_file, dir_path);
Err err;
Value result = functions::RunExpandDirectory(
setup.scope(), function.get(),
{Value(nullptr, "//foo/bar"), Value(nullptr, true)}, &err);
ASSERT_SUCCESS(err);
ASSERT_EQ(result.type(), Value::LIST);
ASSERT_EQ(result.list_value().size(), 3);
EXPECT_EQ(result.list_value()[0].string_value(), "//foo/bar/file1.txt");
EXPECT_EQ(result.list_value()[1].string_value(), "//foo/bar/file2.txt");
EXPECT_EQ(result.list_value()[2].string_value(), "//foo/bar/sub/file3.txt");
std::vector<base::FilePath> deps = scheduler().GetGenDependencies();
EXPECT_TRUE(std::ranges::find(deps, dir_path) != deps.end())
<< FilePathToUTF8(dir_path);
auto sub = dir_path.AppendASCII("sub");
EXPECT_TRUE(std::ranges::find(deps, sub) != deps.end())
<< FilePathToUTF8(sub);
}
TEST_F(ExpandDirectoryTest, NonRecursive) {
auto dir_path = temp_dir_.GetPath().AppendASCII("foo").AppendASCII("bar");
auto input_file = InputFile(SourceFile("//foo/BUILD.gn"));
auto function = SetupDefaultDirAndFunction(&input_file, dir_path);
setup.scope()->set_source_dir(SourceDir("//foo/"));
Err err;
Value result = functions::RunExpandDirectory(
setup.scope(), function.get(),
{Value(nullptr, "bar"), Value(nullptr, false)}, &err);
ASSERT_SUCCESS(err);
ASSERT_EQ(result.type(), Value::LIST);
ASSERT_EQ(result.list_value().size(), 2);
EXPECT_EQ(result.list_value()[0].string_value(), "//foo/bar/file1.txt");
EXPECT_EQ(result.list_value()[1].string_value(), "//foo/bar/file2.txt");
std::vector<base::FilePath> deps = scheduler().GetGenDependencies();
EXPECT_TRUE(std::ranges::find(deps, dir_path) != deps.end());
EXPECT_TRUE(std::ranges::find(deps, dir_path.AppendASCII("sub")) ==
deps.end());
}
TEST_F(ExpandDirectoryTest, EmptyDir) {
std::string dir_str = FilePathToUTF8(temp_dir_.GetPath());
FunctionCallNode function;
Err err;
Value result = functions::RunExpandDirectory(
setup.scope(), &function, {Value(nullptr, dir_str), Value(nullptr, true)},
&err);
ASSERT_SUCCESS(err);
ASSERT_EQ(result.type(), Value::LIST);
ASSERT_EQ(result.list_value().size(), 0);
}
TEST_F(ExpandDirectoryTest, NonExistentDir) {
base::FilePath non_existent = temp_dir_.GetPath().AppendASCII("non_existent");
FunctionCallNode function;
Err err;
Value result = functions::RunExpandDirectory(
setup.scope(), &function,
{Value(nullptr, FilePathToUTF8(non_existent)), Value(nullptr, true)},
&err);
EXPECT_TRUE(err.has_error());
}
TEST_F(ExpandDirectoryTest, Allowlist) {
InputFile input_file(SourceFile("//BUILD.gn"));
Location location(&input_file, 1, 1);
Token token(location, Token::IDENTIFIER, "expand_directory");
FunctionCallNode function;
function.set_function(token);
auto args = std::make_unique<ListNode>();
args->set_begin_token(token);
args->set_end(std::make_unique<EndNode>(token));
function.set_args(std::move(args));
// No allowlist
{
Err err;
Value result = functions::RunExpandDirectory(
setup.scope(), &function,
{Value(nullptr, FilePathToUTF8(temp_dir_.GetPath())),
Value(nullptr, true)},
&err);
EXPECT_TRUE(err.has_error());
}
// Empty allowlist
auto allowlist_owned = std::make_unique<SourceFileSet>();
auto allowlist = allowlist_owned.get();
setup.build_settings()->set_expand_directory_allowlist(
std::move(allowlist_owned));
allowlist->insert(SourceFile("//foo.gni"));
{
Err err;
Value result = functions::RunExpandDirectory(
setup.scope(), &function,
{Value(nullptr, FilePathToUTF8(temp_dir_.GetPath())),
Value(nullptr, true)},
&err);
EXPECT_TRUE(err.has_error());
}
}