alef 0.25.37

Opinionated polyglot binding generator for Rust libraries
Documentation
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
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
use crate::core::hash::{self, CommentStyle};
use std::collections::HashMap;
use std::fmt::Write as FmtWrite;

/// Emit a bash snippet that exports every `[e2e.env]` entry using `setdefault`
/// semantics: each var is only set when not already present in the parent
/// environment. Returns an empty string when the map is empty. Keys are sorted
/// alphabetically for deterministic output.
pub(super) fn render_env_block(env: &HashMap<String, String>) -> String {
    if env.is_empty() {
        return String::new();
    }
    let mut keys: Vec<&String> = env.keys().collect();
    keys.sort();
    let mut out = String::new();
    let _ = writeln!(out, "# Suite-level environment defaults from [e2e.env]. Each entry");
    let _ = writeln!(out, "# uses setdefault semantics: only applied when not already set.");
    for key in keys {
        let value = &env[key];
        let _ = writeln!(out, ": \"${{{key}:={value}}}\"");
        let _ = writeln!(out, "export {key}");
    }
    let _ = writeln!(out);
    out
}

/// Render the main `run_tests.sh` runner script.
pub(super) fn render_run_tests(categories: &[String], env: &HashMap<String, String>, binary_name: &str) -> String {
    let mut out = String::new();
    let _ = writeln!(out, "#!/usr/bin/env bash");
    out.push_str(&hash::header(CommentStyle::Hash));
    let _ = writeln!(out, "# shellcheck disable=SC1091");
    let _ = writeln!(out, "set -euo pipefail");
    let _ = writeln!(out);
    let env_block = render_env_block(env);
    if !env_block.is_empty() {
        out.push_str(&env_block);
    }
    let _ = writeln!(out, "# Auto-spawn mock-server if MOCK_SERVER_URL is not pre-set.");
    let _ = writeln!(
        out,
        "# Mirrors the C test_app Makefile's run_with_mock_server macro: builds the"
    );
    let _ = writeln!(
        out,
        "# fixture-driven mock-server from ../rust/ on demand, launches it in the"
    );
    let _ = writeln!(
        out,
        "# background, harvests MOCK_SERVER_URL + MOCK_SERVERS from its stdout, and"
    );
    let _ = writeln!(
        out,
        "# tears it down on exit. Without this the `task test-apps:smoke:brew` entry"
    );
    let _ = writeln!(
        out,
        "# point — which just calls `bash run_tests.sh` — fails at the require-check"
    );
    let _ = writeln!(
        out,
        "# above because nothing else in the smoke task spawns a mock-server."
    );
    let _ = writeln!(out, "if [ -z \"${{MOCK_SERVER_URL:-}}\" ]; then");
    let _ = writeln!(
        out,
        "  MOCK_SERVER_BIN=\"${{MOCK_SERVER_BIN:-../rust/target/release/mock-server}}\""
    );
    let _ = writeln!(
        out,
        "  MOCK_SERVER_MANIFEST=\"${{MOCK_SERVER_MANIFEST:-../rust/Cargo.toml}}\""
    );
    let _ = writeln!(out, "  FIXTURES_DIR=\"${{FIXTURES_DIR:-../../fixtures}}\"");
    let _ = writeln!(out, "  if [ ! -x \"$MOCK_SERVER_BIN\" ]; then");
    let _ = writeln!(
        out,
        "    echo \"Building mock-server from $MOCK_SERVER_MANIFEST...\" >&2"
    );
    let _ = writeln!(
        out,
        "    cargo build --release --manifest-path \"$MOCK_SERVER_MANIFEST\" --bin mock-server >&2"
    );
    let _ = writeln!(out, "  fi");
    let _ = writeln!(out, "  rm -f mock_server.stdout");
    let _ = writeln!(out, "  : > mock_server.stdout");
    let _ = writeln!(
        out,
        "  \"$MOCK_SERVER_BIN\" \"$FIXTURES_DIR\" >mock_server.stdout 2>&1 &"
    );
    let _ = writeln!(out, "  __MOCK_PID=$!");
    let _ = writeln!(
        out,
        "  trap '[ -n \"${{__MOCK_PID:-}}\" ] && kill \"$__MOCK_PID\" 2>/dev/null || true' EXIT"
    );
    let _ = writeln!(out, "  for _i in $(seq 1 200); do");
    let _ = writeln!(
        out,
        "    if grep -q '^MOCK_SERVER_URL=' mock_server.stdout 2>/dev/null; then"
    );
    let _ = writeln!(out, "      break");
    let _ = writeln!(out, "    fi");
    let _ = writeln!(out, "    sleep 0.05");
    let _ = writeln!(out, "  done");
    let _ = writeln!(
        out,
        "  if ! grep -q '^MOCK_SERVER_URL=' mock_server.stdout 2>/dev/null; then"
    );
    let _ = writeln!(
        out,
        "    echo 'error: mock-server did not emit MOCK_SERVER_URL within 10s' >&2"
    );
    let _ = writeln!(out, "    cat mock_server.stdout >&2 || true");
    let _ = writeln!(out, "    exit 1");
    let _ = writeln!(out, "  fi");
    let _ = writeln!(
        out,
        "  MOCK_SERVER_URL=\"$(grep '^MOCK_SERVER_URL=' mock_server.stdout | tail -1 | cut -d= -f2-)\""
    );
    let _ = writeln!(out, "  export MOCK_SERVER_URL");
    let _ = writeln!(
        out,
        "  if grep -q '^MOCK_SERVERS=' mock_server.stdout 2>/dev/null; then"
    );
    let _ = writeln!(
        out,
        "    MOCK_SERVERS=\"$(grep '^MOCK_SERVERS=' mock_server.stdout | tail -1 | cut -d= -f2-)\""
    );
    let _ = writeln!(out, "    export MOCK_SERVERS");
    let _ = writeln!(out, "  fi");
    let _ = writeln!(out, "fi");
    let _ = writeln!(out);
    let _ = writeln!(out, "# MOCK_SERVER_URL must be set to the base URL of the mock server.");
    let _ = writeln!(out, ": \"${{MOCK_SERVER_URL:?MOCK_SERVER_URL is required}}\"");
    let _ = writeln!(out);
    let _ = writeln!(out, "# Verify that jq is available.");
    let _ = writeln!(out, "if ! command -v jq &>/dev/null; then");
    let _ = writeln!(out, "  echo 'error: jq is required but not found in PATH' >&2");
    let _ = writeln!(out, "  exit 1");
    let _ = writeln!(out, "fi");
    let _ = writeln!(out);
    // The brew test_app exercises the formula-installed CLI binary; emit a
    // pre-flight check so the failure is reported as "install via brew" rather
    // than a stream of opaque `command not found` errors from each category
    // test script. CLI binary name is the resolved package name for the brew
    // language entry; require exactly that binary on PATH so another installed
    // CLI cannot mask a missing configured binary.
    let _ = writeln!(out, "# Verify the brew-installed CLI is on PATH.");
    let _ = writeln!(out, "if ! command -v {binary_name} &>/dev/null; then");
    let _ = writeln!(
        out,
        "  echo 'error: brew test_app requires the Homebrew formula to be installed' >&2"
    );
    let _ = writeln!(out, "  echo '       run: brew install {binary_name}' >&2");
    let _ = writeln!(out, "  exit 1");
    let _ = writeln!(out, "fi");
    let _ = writeln!(out);
    let _ = writeln!(out, "PASS=0");
    let _ = writeln!(out, "FAIL=0");
    let _ = writeln!(out);

    // Helper functions.
    let _ = writeln!(out, "assert_equals() {{");
    let _ = writeln!(out, "  local actual=\"$1\" expected=\"$2\" label=\"$3\"");
    let _ = writeln!(out, "  if [ \"$actual\" != \"$expected\" ]; then");
    let _ = writeln!(
        out,
        "    echo \"FAIL [$label]: expected '$expected', got '$actual'\" >&2"
    );
    let _ = writeln!(out, "    return 1");
    let _ = writeln!(out, "  fi");
    let _ = writeln!(out, "}}");
    let _ = writeln!(out);
    let _ = writeln!(out, "assert_contains() {{");
    let _ = writeln!(out, "  local actual=\"$1\" expected=\"$2\" label=\"$3\"");
    let _ = writeln!(out, "  if [[ \"$actual\" != *\"$expected\"* ]]; then");
    let _ = writeln!(out, "    echo \"FAIL [$label]: expected to contain '$expected'\" >&2");
    let _ = writeln!(out, "    return 1");
    let _ = writeln!(out, "  fi");
    let _ = writeln!(out, "}}");
    let _ = writeln!(out);
    let _ = writeln!(out, "assert_not_empty() {{");
    let _ = writeln!(out, "  local actual=\"$1\" label=\"$2\"");
    let _ = writeln!(out, "  if [ -z \"$actual\" ]; then");
    let _ = writeln!(out, "    echo \"FAIL [$label]: expected non-empty value\" >&2");
    let _ = writeln!(out, "    return 1");
    let _ = writeln!(out, "  fi");
    let _ = writeln!(out, "}}");
    let _ = writeln!(out);
    let _ = writeln!(out, "assert_count_min() {{");
    let _ = writeln!(out, "  local count=\"$1\" min=\"$2\" label=\"$3\"");
    let _ = writeln!(out, "  if [ \"$count\" -lt \"$min\" ]; then");
    let _ = writeln!(
        out,
        "    echo \"FAIL [$label]: expected at least $min elements, got $count\" >&2"
    );
    let _ = writeln!(out, "    return 1");
    let _ = writeln!(out, "  fi");
    let _ = writeln!(out, "}}");
    let _ = writeln!(out);
    let _ = writeln!(out, "assert_greater_than() {{");
    let _ = writeln!(out, "  local val=\"$1\" threshold=\"$2\" label=\"$3\"");
    let _ = writeln!(out, "  if [ \"$(echo \"$val > $threshold\" | bc -l)\" != \"1\" ]; then");
    let _ = writeln!(out, "    echo \"FAIL [$label]: expected $val > $threshold\" >&2");
    let _ = writeln!(out, "    return 1");
    let _ = writeln!(out, "  fi");
    let _ = writeln!(out, "}}");
    let _ = writeln!(out);
    let _ = writeln!(out, "assert_greater_than_or_equal() {{");
    let _ = writeln!(out, "  local actual=\"$1\" expected=\"$2\" label=\"$3\"");
    let _ = writeln!(out, "  if [ \"$actual\" -lt \"$expected\" ]; then");
    let _ = writeln!(out, "    echo \"FAIL [$label]: expected $actual >= $expected\" >&2");
    let _ = writeln!(out, "    return 1");
    let _ = writeln!(out, "  fi");
    let _ = writeln!(out, "}}");
    let _ = writeln!(out);
    let _ = writeln!(out, "assert_is_empty() {{");
    let _ = writeln!(out, "  local actual=\"$1\" label=\"$2\"");
    let _ = writeln!(out, "  if [ -n \"$actual\" ]; then");
    let _ = writeln!(
        out,
        "    echo \"FAIL [$label]: expected empty value, got '$actual'\" >&2"
    );
    let _ = writeln!(out, "    return 1");
    let _ = writeln!(out, "  fi");
    let _ = writeln!(out, "}}");
    let _ = writeln!(out);
    let _ = writeln!(out, "assert_less_than() {{");
    let _ = writeln!(out, "  local actual=\"$1\" expected=\"$2\" label=\"$3\"");
    let _ = writeln!(out, "  if [ \"$actual\" -ge \"$expected\" ]; then");
    let _ = writeln!(out, "    echo \"FAIL [$label]: expected $actual < $expected\" >&2");
    let _ = writeln!(out, "    return 1");
    let _ = writeln!(out, "  fi");
    let _ = writeln!(out, "}}");
    let _ = writeln!(out);
    let _ = writeln!(out, "assert_less_than_or_equal() {{");
    let _ = writeln!(out, "  local actual=\"$1\" expected=\"$2\" label=\"$3\"");
    let _ = writeln!(out, "  if [ \"$actual\" -gt \"$expected\" ]; then");
    let _ = writeln!(out, "    echo \"FAIL [$label]: expected $actual <= $expected\" >&2");
    let _ = writeln!(out, "    return 1");
    let _ = writeln!(out, "  fi");
    let _ = writeln!(out, "}}");
    let _ = writeln!(out);
    let _ = writeln!(out, "assert_not_contains() {{");
    let _ = writeln!(out, "  local actual=\"$1\" expected=\"$2\" label=\"$3\"");
    let _ = writeln!(out, "  if [[ \"$actual\" == *\"$expected\"* ]]; then");
    let _ = writeln!(
        out,
        "    echo \"FAIL [$label]: expected not to contain '$expected'\" >&2"
    );
    let _ = writeln!(out, "    return 1");
    let _ = writeln!(out, "  fi");
    let _ = writeln!(out, "}}");
    let _ = writeln!(out);

    // Source per-category files.
    let script_dir = r#"SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)""#;
    let _ = writeln!(out, "{script_dir}");
    let _ = writeln!(out);
    for category in categories {
        let _ = writeln!(out, "# shellcheck source=test_{category}.sh");
        let _ = writeln!(out, "source \"$SCRIPT_DIR/test_{category}.sh\"");
    }
    let _ = writeln!(out);

    // Run each test function and track pass/fail.
    let _ = writeln!(out, "run_test() {{");
    let _ = writeln!(out, "  local name=\"$1\"");
    let _ = writeln!(out, "  if \"$name\"; then");
    let _ = writeln!(out, "    echo \"PASS: $name\"");
    let _ = writeln!(out, "    PASS=$((PASS + 1))");
    let _ = writeln!(out, "  else");
    let _ = writeln!(out, "    echo \"FAIL: $name\"");
    let _ = writeln!(out, "    FAIL=$((FAIL + 1))");
    let _ = writeln!(out, "  fi");
    let _ = writeln!(out, "}}");
    let _ = writeln!(out);

    // Gather all test function names from category files then call them.
    // We enumerate them at code-generation time so the runner doesn't need
    // introspection at runtime.
    let _ = writeln!(out, "# Run all generated test functions.");
    for category in categories {
        let _ = writeln!(out, "# Category: {category}");
        // We emit a placeholder comment — the actual list is per-category.
        // The run_test calls are emitted inline below based on known IDs.
        let _ = writeln!(out, "run_tests_{category}");
    }
    let _ = writeln!(out);
    let _ = writeln!(out, "echo \"\"");
    let _ = writeln!(out, "echo \"Results: $PASS passed, $FAIL failed\"");
    let _ = writeln!(out, "[ \"$FAIL\" -eq 0 ]");
    out
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Every leading-whitespace prefix in an emitted shell line must be a
    /// multiple of 2 spaces. shfmt's default indent step rewrites any other
    /// indent step, which then causes the alef-emitted scripts to be rewritten
    /// by pre-commit hooks on every project run.
    fn assert_shfmt_canonical_indent(script: &str, context: &str) {
        for (lineno, line) in script.lines().enumerate() {
            let leading_spaces = line.chars().take_while(|c| *c == ' ').count();
            assert!(
                leading_spaces.is_multiple_of(2),
                "{context}: line {lineno} has {leading_spaces}-space indent (must be a multiple of 2 for shfmt compatibility): {line:?}",
            );
        }
    }

    #[test]
    fn render_run_tests_uses_two_space_indent() {
        let categories = vec!["auth".to_string(), "crawl".to_string()];
        let script = render_run_tests(&categories, &HashMap::new(), "sample-cli");
        assert_shfmt_canonical_indent(&script, "render_run_tests");
        assert!(
            script.lines().any(|l| l.starts_with("  ") && !l.starts_with("   ")),
            "render_run_tests should emit at least one 2-space-indented line; got:\n{script}",
        );
    }

    #[test]
    fn render_env_block_emits_setdefault_with_sorted_keys() {
        let mut env = HashMap::new();
        env.insert("E2E_ALLOW_PRIVATE_NETWORK".to_string(), "true".to_string());
        env.insert("ALEF_FOO".to_string(), "bar".to_string());
        let block = render_env_block(&env);
        assert!(block.contains(": \"${ALEF_FOO:=bar}\""), "got: {block}");
        assert!(
            block.contains(": \"${E2E_ALLOW_PRIVATE_NETWORK:=true}\""),
            "got: {block}"
        );
        assert!(block.contains("export ALEF_FOO"), "got: {block}");
        assert!(block.contains("export E2E_ALLOW_PRIVATE_NETWORK"), "got: {block}");
        let alef_pos = block.find("ALEF_FOO").unwrap();
        let e2e_pos = block.find("E2E_ALLOW_PRIVATE_NETWORK").unwrap();
        assert!(alef_pos < e2e_pos, "keys must be sorted alphabetically; got: {block}");
    }

    #[test]
    fn render_env_block_empty_when_no_env_configured() {
        let env = HashMap::new();
        assert_eq!(render_env_block(&env), "");
    }

    #[test]
    fn render_run_tests_omits_env_block_when_env_empty() {
        let categories = vec!["smoke".to_string()];
        let script = render_run_tests(&categories, &HashMap::new(), "sample-cli");
        assert!(
            !script.contains("Suite-level environment defaults"),
            "no env block when env empty; got: {script}"
        );
    }

    /// Regression: the brew test_app must check that the formula-installed CLI is
    /// on PATH before invoking it from category tests. Without this preflight the
    /// failure surfaces as a cascade of `sample-cli: command not found` lines from
    /// each test, drowning the actionable signal (run `brew install …`).
    #[test]
    fn render_run_tests_emits_brew_cli_preflight_check() {
        let categories = vec!["smoke".to_string()];
        let script = render_run_tests(&categories, &HashMap::new(), "sample-cli");
        assert!(
            script.contains("Verify the brew-installed CLI is on PATH"),
            "expected brew CLI preflight check; got:\n{script}"
        );
        assert!(
            script.contains("brew install sample-cli"),
            "expected install instruction in brew CLI preflight; got:\n{script}"
        );
        // The check must require only the configured binary name so another
        // installed CLI cannot mask a missing configured binary.
        assert!(
            script.contains("if ! command -v sample-cli &>/dev/null; then"),
            "expected single-binary preflight; got:\n{script}"
        );
        assert!(
            !script.contains("command -v sibling-cli "),
            "preflight must not OR with sibling CLI; got:\n{script}"
        );
    }

    #[test]
    fn render_run_tests_preflight_uses_parameterized_binary_name() {
        let categories = vec!["smoke".to_string()];
        let script = render_run_tests(&categories, &HashMap::new(), "mytool");
        assert!(
            script.contains("if ! command -v mytool &>/dev/null; then"),
            "expected preflight to use parameterized binary; got:\n{script}"
        );
        assert!(
            script.contains("brew install mytool"),
            "expected install hint to use parameterized binary; got:\n{script}"
        );
        assert!(
            !script.contains("sample-cli") && !script.contains("sibling-cli"),
            "preflight must not leak hardcoded sibling names; got:\n{script}"
        );
    }

    #[test]
    fn render_run_tests_includes_env_block_when_env_configured() {
        let mut env = HashMap::new();
        env.insert("E2E_ALLOW_PRIVATE_NETWORK".to_string(), "true".to_string());
        let categories = vec!["smoke".to_string()];
        let script = render_run_tests(&categories, &env, "sample-cli");
        assert!(
            script.contains(": \"${E2E_ALLOW_PRIVATE_NETWORK:=true}\""),
            "got: {script}"
        );
        assert!(script.contains("export E2E_ALLOW_PRIVATE_NETWORK"), "got: {script}");
        // Env block must precede the MOCK_SERVER_URL bootstrap so the binding's
        // first call already sees the configured environment.
        let env_pos = script.find("${E2E_ALLOW_PRIVATE_NETWORK").unwrap();
        let mock_pos = script.find("MOCK_SERVER_URL").unwrap();
        assert!(env_pos < mock_pos, "env block must precede mock-server bootstrap");
    }
}