Files
clice/tests/unit/command/search_config_tests.cpp
2026-03-26 21:27:18 +08:00

208 lines
8.5 KiB
C++

#include "test/temp_dir.h"
#include "test/test.h"
#include "command/search_config.h"
namespace clice::testing {
namespace {
TEST_SUITE(ExtractSearchConfig) {
TEST_CASE(ReordersDirectoryGroups) {
// TempDir gives cross-platform absolute paths (drive letter on Windows).
TempDir tmp;
std::vector<const char*> args = {"clang++",
"-internal-isystem",
tmp.c_path("stdlib"),
"-internal-isystem",
tmp.c_path("clang"),
"-internal-externc-isystem",
tmp.c_path("sysroot"),
"-I",
tmp.c_path("user"),
"-iquote",
tmp.c_path("quoted"),
"main.cpp"};
auto config = extract_search_config(args, tmp.root.str());
// Expected order: [quoted | user | stdlib, clang, sysroot]
ASSERT_EQ(config.dirs.size(), 5u);
EXPECT_EQ(config.angled_start_idx, 1u);
EXPECT_EQ(config.system_start_idx, 2u);
EXPECT_EQ(config.dirs[0].path, tmp.path("quoted"));
EXPECT_EQ(config.dirs[1].path, tmp.path("user"));
EXPECT_EQ(config.dirs[2].path, tmp.path("stdlib"));
EXPECT_EQ(config.dirs[3].path, tmp.path("clang"));
EXPECT_EQ(config.dirs[4].path, tmp.path("sysroot"));
}
TEST_CASE(PreservesWithinGroupOrder) {
TempDir tmp;
std::vector<const char*> args = {"clang++",
"-I",
tmp.c_path("b"),
"-I",
tmp.c_path("a"),
"-isystem",
tmp.c_path("s2"),
"-isystem",
tmp.c_path("s1"),
"main.cpp"};
auto config = extract_search_config(args, tmp.root.str());
ASSERT_EQ(config.dirs.size(), 4u);
EXPECT_EQ(config.angled_start_idx, 0u);
EXPECT_EQ(config.system_start_idx, 2u);
EXPECT_EQ(config.dirs[0].path, tmp.path("b"));
EXPECT_EQ(config.dirs[1].path, tmp.path("a"));
EXPECT_EQ(config.dirs[2].path, tmp.path("s2"));
EXPECT_EQ(config.dirs[3].path, tmp.path("s1"));
}
TEST_CASE(DeduplicatesAngledSystem) {
TempDir tmp;
std::vector<const char*> args = {"clang++",
"-I",
tmp.c_path("shared"),
"-internal-isystem",
tmp.c_path("shared"),
"-internal-isystem",
tmp.c_path("only_sys"),
"main.cpp"};
auto config = extract_search_config(args, tmp.root.str());
// /shared in both Angled and System → keep Angled copy.
ASSERT_EQ(config.dirs.size(), 2u);
EXPECT_EQ(config.angled_start_idx, 0u);
EXPECT_EQ(config.system_start_idx, 1u);
EXPECT_EQ(config.dirs[0].path, tmp.path("shared"));
EXPECT_EQ(config.dirs[1].path, tmp.path("only_sys"));
}
TEST_CASE(QuotedAngledSamePathKeptInBoth) {
// clang's RemoveDuplicates starts from NumQuoted, so a path in both
// Quoted (-iquote) and Angled (-I) must be kept in both segments.
// This matters for #include <...> lookup and #include_next correctness.
TempDir tmp;
std::vector<const char*> args = {"clang++",
"-iquote",
tmp.c_path("shared"),
"-I",
tmp.c_path("shared"),
"-I",
tmp.c_path("other"),
"main.cpp"};
auto config = extract_search_config(args, tmp.root.str());
// "shared" must appear in both Quoted and Angled segments.
ASSERT_EQ(config.dirs.size(), 3u);
EXPECT_EQ(config.angled_start_idx, 1u);
EXPECT_EQ(config.dirs[0].path, tmp.path("shared")); // Quoted
EXPECT_EQ(config.dirs[1].path, tmp.path("shared")); // Angled (not deduped)
EXPECT_EQ(config.dirs[2].path, tmp.path("other"));
}
TEST_CASE(DeduplicateAdjustsIndices) {
TempDir tmp;
std::vector<const char*> args = {"clang++",
"-iquote",
tmp.c_path("q"),
"-I",
tmp.c_path("dup"),
"-I",
tmp.c_path("a2"),
"-isystem",
tmp.c_path("dup"),
"-isystem",
tmp.c_path("s"),
"main.cpp"};
auto config = extract_search_config(args, tmp.root.str());
// Before dedup: [q | dup, a2 | dup, s] angled=1, system=3
// dup in system removed. system_start_idx stays 3.
ASSERT_EQ(config.dirs.size(), 4u);
EXPECT_EQ(config.angled_start_idx, 1u);
EXPECT_EQ(config.system_start_idx, 3u);
EXPECT_EQ(config.dirs[0].path, tmp.path("q"));
EXPECT_EQ(config.dirs[1].path, tmp.path("dup"));
EXPECT_EQ(config.dirs[2].path, tmp.path("a2"));
EXPECT_EQ(config.dirs[3].path, tmp.path("s"));
}
TEST_CASE(PrefixIncludeOptions) {
TempDir tmp;
// -iprefix sets a prefix; -iwithprefixbefore/iwithprefix append to it.
// The trailing separator in the prefix path ensures correct concatenation.
auto prefix12 = tmp.path("gcc/12/");
auto prefix13 = tmp.path("gcc/13/");
std::vector<const char*> args = {"clang++",
"-iprefix",
prefix12.c_str(),
"-iwithprefixbefore",
"include",
"-iwithprefix",
"lib",
"-iprefix",
prefix13.c_str(),
"-iwithprefix",
"include",
"main.cpp"};
auto config = extract_search_config(args, tmp.root.str());
// -iwithprefixbefore → Angled, -iwithprefix → After
ASSERT_EQ(config.dirs.size(), 3u);
EXPECT_EQ(config.angled_start_idx, 0u);
EXPECT_EQ(config.system_start_idx, 1u);
EXPECT_EQ(config.after_start_idx, 1u);
EXPECT_EQ(config.dirs[0].path, tmp.path("gcc/12/include"));
EXPECT_EQ(config.dirs[1].path, tmp.path("gcc/12/lib"));
EXPECT_EQ(config.dirs[2].path, tmp.path("gcc/13/include"));
}
TEST_CASE(DirafterGroup) {
TempDir tmp;
std::vector<const char*> args = {"clang++",
"-I",
tmp.c_path("user"),
"-isystem",
tmp.c_path("sys"),
"-idirafter",
tmp.c_path("fallback"),
"main.cpp"};
auto config = extract_search_config(args, tmp.root.str());
ASSERT_EQ(config.dirs.size(), 3u);
EXPECT_EQ(config.angled_start_idx, 0u);
EXPECT_EQ(config.system_start_idx, 1u);
EXPECT_EQ(config.after_start_idx, 2u);
EXPECT_EQ(config.dirs[0].path, tmp.path("user"));
EXPECT_EQ(config.dirs[1].path, tmp.path("sys"));
EXPECT_EQ(config.dirs[2].path, tmp.path("fallback"));
}
TEST_CASE(DirafterDeduplication) {
TempDir tmp;
std::vector<const char*> args = {"clang++",
"-I",
tmp.c_path("shared"),
"-idirafter",
tmp.c_path("shared"),
"-idirafter",
tmp.c_path("extra"),
"main.cpp"};
auto config = extract_search_config(args, tmp.root.str());
ASSERT_EQ(config.dirs.size(), 2u);
EXPECT_EQ(config.angled_start_idx, 0u);
EXPECT_EQ(config.after_start_idx, 1u);
EXPECT_EQ(config.dirs[0].path, tmp.path("shared"));
EXPECT_EQ(config.dirs[1].path, tmp.path("extra"));
}
}; // TEST_SUITE(ExtractSearchConfig)
} // namespace
} // namespace clice::testing