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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
//! Shared test infrastructure for serializing tests that touch
//! crate-level global mutable state (errflag, paramtab, lex
//! buffers, zcontext stacks, paramtab_hashed_storage, ShellExecutor
//! singletons, etc.).
//!
//! Many ported subsystems intentionally mirror C's file-static
//! globals via `OnceLock<Mutex<…>>` / `AtomicI32`. Tests against
//! those subsystems share the same singletons. Parallel cargo
//! test execution races on read-modify-write patterns even when
//! each individual test cleans up afterwards, because two tests
//! observe each other's mid-test state.
//!
//! Pattern: tests that touch global state call
//! `let _g = crate::test_util::global_state_lock();` at entry.
//! The MutexGuard is held for the test's lifetime, serializing
//! against every other test that does the same — purely-functional
//! tests still run in parallel.
//!
//! Mutex-poisoning is recovered automatically so a single panicking
//! test doesn't break the whole suite.
use ;
/// Acquire the crate-wide test mutex. Tests that touch global
/// state (errflag, paramtab, lex buffers, zcontext, ShellExecutor,
/// etc.) hold this guard for their duration to serialize against
/// other stateful tests.
/// Load the terminal the capability-reading tests measure in, once per test
/// binary.
///
/// `%B` is `tcstr[TCBOLDFACEBEG]`, `echoti bold` reads the terminfo entry and
/// `gettermcap co` reads the termcap one; all three come from `init_term()`,
/// which fills them from the entry `$TERM` names. A test binary runs none of
/// zsh's startup, and a CI runner has no tty and no `TERM` at all — so every
/// capability came back empty there and `%B` expanded to nothing, while a
/// developer machine's own terminal made the same assertions pass. The terminal
/// is a fact about the environment, so the harness states it rather than
/// inheriting whatever the shell that started `cargo test` was using.
///
/// Three names, in order, because a minimal image carries only the older ones:
/// each of `xterm-256color`, `xterm` and `vt100` gives the capabilities these
/// tests pin (measured: the same `\e[1m`, `\e[4m` and `\e[0m` from all three).
/// If none of them loads there is no terminfo database at all, and the tests
/// that read a capability fail on that, which is what a missing database
/// deserves.
/// Reset the completion-machinery globals a `compadd`-driven completion
/// unit test depends on, so its result reflects the test's own inputs
/// rather than whatever the previous test in the same binary left behind.
///
/// [`global_state_lock`] serialises stateful tests but restores nothing,
/// and the completion subsystem is almost entirely process-wide state:
///
/// * `$PREFIX` / `$SUFFIX` / `$IPREFIX` / `$ISUFFIX`. `addmatches`
/// re-seeds the `compprefix` / `compsuffix` / `compiprefix` /
/// `compisuffix` globals from those parameters whenever `incompfunc`
/// is set (`src/ported/zle/compcore.rs:4334-4347`) and then matches
/// every `CAF_MATCH` candidate against them
/// (`compcore.rs:4360-4373`, `Src/Zle/compcore.c:2253-2300`). A dozen
/// completion tests park a non-empty word there and never clear it
/// (`_absolute_command_paths.rs:168` `"ls"`, `_ldap_filters.rs:267`
/// `"-x"`, `_debbugs_bugnumber.rs:142` `"notabug"`, …); after any of
/// them EVERY candidate a later `compadd` offers fails to match, so
/// `compadd` returns 1 and `_all_labels` / `_wanted` report "no
/// matches" for a tag set that was registered perfectly well.
/// * `comptags[]`, which `bin_comptags` indexes by `locallevel`
/// (`Src/Zle/computil.c:3782` "Array of tag-set infos. Index is the
/// locallevel", ported at `computil.rs:6886`), plus `locallevel`
/// itself — nothing unwinds it when a test panics out of a
/// `doshfunc`-shaped port.
/// * the `zstyle` table, which `_hosts` / `_domains` / `_completers` /
/// `_call_program` all consult for their candidate lists.
/// * the three process-wide `compadd` shadows `_approximate` and
/// `_complete_help` install (`src/ported/zle/complete.rs:975-982`,
/// `:1043-1048`).
///
/// Every half of this is the boot/teardown entry point zsh itself uses,
/// not a bespoke reset: `Src/Zle/complete.c:1788 finish_` zsfree's each
/// `comp*` string global, `Src/Zle/computil.c:5124 setup_` zeroes
/// `comptags[]` and `lasttaglevel`, and `zstyle -d` with no pattern is
/// `zstyletab->emptytable` (`Src/Modules/zutil.c:639-640`).
/// Install one `zstyle` for the duration of a test, the way a user would
/// write it on the command line: `zstyle <context> <style> <value…>`
/// (`Src/Modules/zutil.c:606-616` — the no-flag arm is `setstyle`).
///
/// Completion functions that shell out through `_call_program` take the
/// command line from the `command` style
/// (`Completion/Base/Utility/_call_program:26`, ported at
/// `_call_program.rs:74-101`), so this is the upstream-sanctioned way to
/// give such a port a fixed candidate list instead of whatever the host
/// machine's `ifconfig` / `global` happens to print.