Repository navigation
Expand file tree
/
Copy pathcli.test.ts
More file actions
235 lines (215 loc) · 8.76 KB
/
Copy pathcli.test.ts
File metadata and controls
235 lines (215 loc) · 8.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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
import assert from "node:assert/strict";
import test from "node:test";
import {
isMsvcToolchainSpec,
hostDefaultToolchains,
mcppCommandArguments,
normalizeToolchainSpec,
parseToolchainList,
toolchainInstallKind,
toolchainSpecTargetHint,
} from "../src/cli";
const plainOutput = [
"Toolchains:",
" * llvm 22.1.8 (default)",
" gcc 16.1.0",
"",
"Targets:",
" * aarch64-macos host llvm 22.1.8 installed",
"",
"Available toolchains:",
" llvm 20.1.7",
"",
].join("\n");
test("解析已安装、默认和可安装项", () => {
const inventory = parseToolchainList(plainOutput);
assert.equal(inventory.recognized, true);
assert.equal(inventory.projectOverridesGlobal, false);
assert.equal(inventory.globalDefaultSpec, "llvm@22.1.8");
assert.equal(inventory.effective?.spec, "llvm@22.1.8");
assert.deepEqual(
inventory.installed.map((item) => item.spec),
["llvm@22.1.8", "gcc@16.1.0"],
);
assert.deepEqual(
inventory.available.map((item) => item.spec),
["llvm@20.1.7"],
);
});
test("项目覆盖时分开记录有效项和全局默认", () => {
const output = [
"Toolchains:",
" * llvm 22.1.8 (default)",
" gcc 16.1.0",
" (* = effective toolchain from project mcpp.toml [toolchain]; global default is 'gcc@16.1.0')",
].join("\n");
const inventory = parseToolchainList(output);
assert.equal(inventory.projectOverridesGlobal, true);
assert.equal(inventory.effective?.spec, "llvm@22.1.8");
assert.equal(inventory.globalDefaultSpec, "gcc@16.1.0");
});
test("支持系统 MSVC 和合法的空安装状态", () => {
const system = parseToolchainList([
"System:",
" * msvc 17.10 C:\\\\Program Files\\\\MSVC\\\\cl.exe",
].join("\n"));
assert.equal(system.effective?.spec, "msvc");
assert.equal(system.installed[0]?.source, "system");
const empty = parseToolchainList(
"(no toolchains installed - run mcpp build to auto-install the default)\n",
);
assert.equal(empty.recognized, true);
assert.deepEqual(empty.installed, []);
});
test("解析 mcpp 实际的可安装标题、斜线版本和 msvc@system", () => {
const inventory = parseToolchainList([
"Toolchains:",
" * msvc 17.10 (default)",
" (* = effective toolchain from project mcpp.toml [toolchain]; global default is 'msvc@system')",
"",
"Available toolchains (run `mcpp toolchain install <family> <version>`):",
" gcc 15.1.0 / 13.3.0 / 11.5.0 / 9.4.0",
].join("\n"));
assert.equal(inventory.globalDefaultSpec, "msvc@system");
assert.deepEqual(
inventory.available.map((item) => item.spec),
["gcc@15.1.0", "gcc@13.3.0", "gcc@11.5.0", "gcc@9.4.0"],
);
});
test("解析独立的 target 轴和默认 target", () => {
const inventory = parseToolchainList([
"Toolchains:",
" * gcc 16.1.0 (default)",
"",
"Targets:",
" TARGET NOTE TOOLCHAIN STATUS",
" * x86_64-linux-musl static gcc 16.1.0 installed",
" aarch64-linux-musl static, cross gcc 16.1.0 available",
" riscv64-linux-musl static, cross — planned",
].join("\n"));
assert.deepEqual(
inventory.targets.map((target) => [
target.target,
target.toolchainSpec,
target.status,
target.effective,
]),
[
["x86_64-linux-musl", "gcc@16.1.0", "installed", true],
["aarch64-linux-musl", "gcc@16.1.0", "available", false],
["riscv64-linux-musl", undefined, "planned", false],
],
);
assert.equal(inventory.effectiveTarget, "x86_64-linux-musl");
});
test("全局默认明确为 none 时不回退成有效工具链", () => {
const inventory = parseToolchainList([
"Toolchains:",
" * llvm 22.1.8 (default)",
" (* = effective toolchain from project mcpp.toml [toolchain]; global default is '<none>')",
].join("\n"));
assert.equal(inventory.globalDefaultSpec, undefined);
assert.equal(inventory.projectOverridesGlobal, true);
});
test("未知输出不伪造工具链", () => {
const inventory = parseToolchainList("unexpected output\n");
assert.equal(inventory.recognized, false);
assert.deepEqual(inventory.installed, []);
assert.equal(inventory.rawOutput, "unexpected output\n");
const unknownSection = parseToolchainList([
"Metadata:",
" global default is 'gcc@16.1.0'",
].join("\n"));
assert.equal(unknownSection.recognized, false);
assert.equal(unknownSection.globalDefaultSpec, undefined);
});
test("规范化输入并构造参数数组", () => {
assert.equal(normalizeToolchainSpec(" llvm@20 "), "llvm@20");
assert.equal(normalizeToolchainSpec("gcc 16.1.0"), "gcc@16.1.0");
assert.equal(normalizeToolchainSpec("MSVC 17.10"), "msvc@17.10");
assert.equal(normalizeToolchainSpec("gcc@16.1.0-musl"), "gcc@16.1.0-musl");
assert.equal(normalizeToolchainSpec("musl-gcc 16"), "musl-gcc@16");
assert.equal(normalizeToolchainSpec("mingw@16.1.0"), "mingw@16.1.0");
assert.equal(normalizeToolchainSpec("clang@19"), "clang@19");
assert.equal(normalizeToolchainSpec("gcc; rm -rf /"), undefined);
assert.deepEqual(
mcppCommandArguments("toolchain", "default", "llvm@22.1.8"),
["toolchain", "default", "llvm@22.1.8"],
);
assert.deepEqual(mcppCommandArguments("build"), ["build"]);
});
test("保留 mcpp 支持的省略版本和 namespace 输入", () => {
const inputs = [
"gcc",
"llvm",
"clang",
"musl-gcc",
"mingw",
"xim:gcc@16",
];
assert.deepEqual(inputs.map(normalizeToolchainSpec), inputs);
assert.equal(normalizeToolchainSpec("xim:gcc 16"), "xim:gcc@16");
assert.equal(normalizeToolchainSpec("xim:gcc@system"), "xim:gcc@system");
assert.equal(normalizeToolchainSpec("future@preview"), "future@preview");
assert.equal(isMsvcToolchainSpec("xim:msvc@system"), true);
});
test("识别系统项和隐含 target 别名", () => {
assert.equal(isMsvcToolchainSpec("msvc"), true);
assert.equal(isMsvcToolchainSpec("msvc@system"), true);
assert.equal(isMsvcToolchainSpec("llvm@20"), false);
assert.equal(toolchainSpecTargetHint("gcc@16-musl"), "musl");
assert.equal(toolchainSpecTargetHint("musl-gcc@16"), "musl");
assert.equal(toolchainSpecTargetHint("mingw@16"), "windows-gnu");
assert.equal(toolchainSpecTargetHint("clang@19"), undefined);
});
test("安装流程区分 host、target 和系统检测但都交给 mcpp", () => {
assert.equal(toolchainInstallKind("llvm@20"), "managed-host");
assert.equal(toolchainInstallKind("clang@19"), "managed-host");
assert.equal(toolchainInstallKind("mingw@16"), "managed-target");
assert.equal(toolchainInstallKind("aarch64-linux-musl-gcc@16"), "managed-target");
assert.equal(toolchainInstallKind("msvc"), "system-detect");
assert.equal(toolchainInstallKind("msvc@19.44"), "system-detect");
});
test("覆盖 mcpp 兼容层的扩展 target 别名", () => {
assert.equal(toolchainSpecTargetHint("mingw-gcc@16"), "windows-gnu");
assert.equal(toolchainSpecTargetHint("mingw-cross-gcc@16"), "windows-gnu");
assert.equal(toolchainSpecTargetHint("x86_64-w64-mingw32-gcc@16"), "windows-gnu");
assert.equal(toolchainSpecTargetHint("aarch64-linux-musl-gcc@16"), "musl");
assert.equal(toolchainSpecTargetHint("aarch64-linux-gnu-gcc@16"), "target");
});
test("全局默认选择只暴露 host target 的已安装 payload", () => {
const targetOnly = parseToolchainList([
"Toolchains:",
" * gcc 16.1.0 (default)",
"",
"Targets:",
" TARGET NOTE TOOLCHAIN STATUS",
" * x86_64-linux-musl static gcc 16.1.0 installed",
].join("\n"));
assert.deepEqual(hostDefaultToolchains(targetOnly), []);
const hostAndTarget = parseToolchainList([
"Toolchains:",
" gcc 16.1.0",
"",
"Targets:",
" TARGET NOTE TOOLCHAIN STATUS",
" x86_64-linux-gnu host gcc 16.1.0 installed",
" x86_64-linux-musl static gcc 16.1.0 installed",
].join("\n"));
assert.deepEqual(hostDefaultToolchains(hostAndTarget).map((item) => item.spec), ["gcc@16.1.0"]);
});
test("Windows 上 GCC 的 host 默认使用已安装的 MinGW payload", () => {
const windowsInventory = parseToolchainList([
"Toolchains:",
" gcc 16.1.0",
"",
"Targets:",
" TARGET NOTE TOOLCHAIN STATUS",
" x86_64-windows-gnu PE, static gcc 16.1.0 installed",
" x86_64-windows-msvc host, PE — available",
].join("\n"));
assert.deepEqual(
hostDefaultToolchains(windowsInventory).map((item) => item.spec),
["gcc@16.1.0"],
);
});