-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathtest_toolchain_detect.cpp
More file actions
170 lines (147 loc) · 5.76 KB
/
test_toolchain_detect.cpp
File metadata and controls
170 lines (147 loc) · 5.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <gtest/gtest.h>
import std;
import mcpp.platform.env;
import mcpp.toolchain.detect;
import mcpp.toolchain.probe;
using namespace mcpp::toolchain;
namespace {
struct TempDirGuard {
std::filesystem::path root;
~TempDirGuard() {
std::error_code ec;
std::filesystem::remove_all(root, ec);
}
};
std::filesystem::path make_fake_clang() {
auto dir = std::filesystem::temp_directory_path()
/ std::format("mcpp_fake_clang_{}", std::random_device{}());
std::filesystem::create_directories(dir);
auto clang = dir / "clang++";
std::ofstream os(clang);
os << R"(#!/usr/bin/env bash
case "$1" in
--version)
cat <<'OUT'
clang version 20.1.7 (https://github.com/llvm/llvm-project 6146a88f60492b520a36f8f8f3231e15f3cc6082)
Target: x86_64-unknown-linux-gnu
Configuration file: /home/user/.mcpp/registry/data/xpkgs/xim-x-gcc-runtime/15.1.0/lib64
OUT
;;
-dumpmachine)
echo x86_64-unknown-linux-gnu
;;
-print-sysroot)
;;
*)
exit 0
;;
esac
)";
os.close();
std::filesystem::permissions(
clang,
std::filesystem::perms::owner_exec
| std::filesystem::perms::owner_read
| std::filesystem::perms::owner_write);
return clang;
}
std::filesystem::path make_hostile_ld_dir() {
auto dir = std::filesystem::temp_directory_path()
/ std::format("mcpp_hostile_ld_{}", std::random_device{}());
std::filesystem::create_directories(dir);
std::ofstream(dir / "libc.so.6").close();
return dir;
}
} // namespace
#if !defined(_WIN32)
// Uses a fake shell script as a compiler — POSIX only.
TEST(ToolchainDetect, ClangVersionOutputIsNotMisclassifiedByGccPaths) {
auto clang = make_fake_clang();
TempDirGuard cleanup{clang.parent_path()};
auto tc = detect(clang);
ASSERT_TRUE(tc.has_value()) << tc.error().message;
EXPECT_EQ(tc->compiler, CompilerId::Clang);
EXPECT_EQ(tc->version, "20.1.7");
EXPECT_EQ(tc->targetTriple, "x86_64-unknown-linux-gnu");
EXPECT_EQ(tc->stdlibId, "libc++");
EXPECT_FALSE(tc->hasImportStd);
}
#endif // !defined(_WIN32)
#if defined(__linux__)
TEST(ToolchainDetect, IgnoresTargetRuntimeLibraryPathDuringProbe) {
auto clang = make_fake_clang();
TempDirGuard cleanup_clang{clang.parent_path()};
auto hostile = make_hostile_ld_dir();
TempDirGuard cleanup_ld{hostile};
mcpp::platform::env::ScopedEnv ld("LD_LIBRARY_PATH", hostile.string());
auto tc = detect(clang);
ASSERT_TRUE(tc.has_value()) << tc.error().message;
EXPECT_EQ(tc->compiler, CompilerId::Clang);
EXPECT_EQ(tc->targetTriple, "x86_64-unknown-linux-gnu");
}
#endif // defined(__linux__)
// ─── normalize_driver_output: path-free semantic identity ─────────────
//
// Background: the toolchain fingerprint used to hash the compiler binary
// content (hash_file). When the same xim-x-gcc package is installed under
// two different prefixes (~/.mcpp/... vs ~/.xlings/.../xim-x-mcpp/...),
// the on-disk binaries can have different MD5s (build metadata, strip,
// etc.) yet behave identically. We now use a normalized `--version`
// string as the path-free identity instead.
TEST(NormalizeDriverOutput, TrimsWhitespaceAndCollapsesBlankLines) {
std::string raw =
" g++ (xim-x-gcc 16.1.0) 16.1.0\n"
"\n"
"Copyright (C) 2023 Free Software Foundation, Inc. \n"
"\n\n"
"This is free software; ...\n";
auto out = normalize_driver_output(raw);
EXPECT_EQ(out,
"g++ (xim-x-gcc 16.1.0) 16.1.0\n"
"Copyright (C) 2023 Free Software Foundation, Inc.\n"
"This is free software; ...");
}
TEST(NormalizeDriverOutput, IsStableAcrossInstallPrefixes) {
// Same gcc package, two different install locations on disk.
// --version output is identical regardless of where the binary lives,
// so normalized identity must be identical too.
std::string from_a =
"g++ (xim-x-gcc 16.1.0) 16.1.0\n"
"Copyright (C) 2023 Free Software Foundation, Inc.\n";
std::string from_b =
"g++ (xim-x-gcc 16.1.0) 16.1.0\n"
"Copyright (C) 2023 Free Software Foundation, Inc.\n";
EXPECT_EQ(normalize_driver_output(from_a), normalize_driver_output(from_b));
}
TEST(NormalizeDriverOutput, ReplacesLocalInstallPaths) {
std::string a =
"clang version 20.1.7\n"
"Configuration file: /home/speak/.mcpp/registry/data/xpkgs/llvm/bin/clang.cfg\n";
std::string b =
"clang version 20.1.7\n"
"Configuration file: /home/speak/.xlings/data/xpkgs/llvm/bin/clang.cfg\n";
EXPECT_EQ(normalize_driver_output(a), normalize_driver_output(b));
EXPECT_EQ(normalize_driver_output(a).find("/home/"), std::string::npos);
}
TEST(NormalizeDriverOutput, DistinguishesDifferentVersions) {
std::string a = "g++ (xim-x-gcc 16.1.0) 16.1.0\n";
std::string b = "g++ (xim-x-gcc 15.1.0) 15.1.0\n";
EXPECT_NE(normalize_driver_output(a), normalize_driver_output(b));
}
TEST(NormalizeDriverOutput, EmptyInputProducesEmpty) {
EXPECT_EQ(normalize_driver_output(""), "");
EXPECT_EQ(normalize_driver_output("\n\n\n"), "");
}
#if !defined(_WIN32)
// ─── detect() populates driverIdent ─────────────────────────────────
TEST(ToolchainDetect, PopulatesDriverIdentFromVersionOutput) {
auto clang = make_fake_clang();
TempDirGuard cleanup{clang.parent_path()};
auto tc = detect(clang);
ASSERT_TRUE(tc.has_value()) << tc.error().message;
EXPECT_FALSE(tc->driverIdent.empty())
<< "detect() should populate Toolchain::driverIdent from --version output";
EXPECT_NE(tc->driverIdent.find("clang version 20.1.7"), std::string::npos)
<< "driverIdent should contain the --version header: " << tc->driverIdent;
}
#endif // !defined(_WIN32)