alef 0.66.0

Opinionated polyglot binding generator for Rust libraries
Documentation
//! Regression coverage for the C engine-factory URL construction gap: batch/list fixtures
//! (URLs living in a `batch_urls`/`urls` list, no scalar `url` key) fell through to the raw
//! `getenv("MOCK_SERVER_URL")` scaffolding branch even when `preserve_input_urls` was set,
//! because the emitter only ever consulted `input.url`. That scaffolding is exactly what
//! `reject_mock_harness_scaffolding` (`src/e2e/snippets/mock_harness_guard.rs`) exists to
//! catch in a published documentation snippet.
//!
//! ~keep New submodule of `call_patterns` rather than growing `call_patterns.rs` itself,
//! `test_function.rs`, or `snippet_regressions.rs` (the latter two already over the repo's
//! 1,000-line cap; see `file-modularization` in CLAUDE.md).

use std::collections::{HashMap, HashSet};

use crate::e2e::codegen::c::assertions::{EffectiveConfigSource, FieldConfigSources};
use crate::e2e::field_access::FieldResolver;
use crate::e2e::fixture::Fixture;

fn permissive_resolver() -> FieldResolver {
    FieldResolver::new(
        &HashMap::new(),
        &HashSet::new(),
        &HashSet::new(),
        &HashSet::new(),
        &HashSet::new(),
    )
}

fn global_sources() -> FieldConfigSources {
    FieldConfigSources {
        result_fields: EffectiveConfigSource::Global,
        fields: EffectiveConfigSource::Global,
    }
}

/// A batch-shaped, doc-snippet fixture: no `url` key, its addresses live under `batch_urls`,
/// and `preserve_input_urls` is set (the flag that means "this is the subject of the test /
/// documentation, do not substitute the mock server address" -- see `preserved_url_literal`'s
/// doc comment in `src/e2e/codegen/mod.rs`).
fn batch_fixture() -> Fixture {
    Fixture {
        id: "batch_crawl_basic".into(),
        description: "Crawl a batch of seed URLs".into(),
        input: serde_json::json!({"batch_urls": ["/seed1", "/seed2"]}),
        preserve_input_urls: true,
        ..Fixture::default()
    }
}

/// Drives the real production function directly (not a hand-rolled mirror of intended
/// behaviour) against a batch-shaped fixture, and asserts the rendered C body never falls
/// back to the raw mock-harness scaffolding the guard exists to reject.
///
/// Before the fix: `resolve_field(&fixture.input, "input.url")` resolves to `Null` for this
/// fixture (there is no `url` key), so `preserved_url_literal` returns `None` regardless of
/// `preserve_input_urls`, and the emitter falls unconditionally into the
/// `getenv("MOCK_SERVER_URL")` branch -- this test FAILS against that code.
///
/// After the fix: the batch/list field is consulted via the shared
/// `resolve_urls_field`/`preserved_url_list` seam (the same helpers every other backend's
/// `mock_url_list` handling already uses), the first list entry becomes the engine-factory
/// pattern's single positional `url`, and the raw scaffolding branch is never reached.
#[test]
fn batch_url_list_fixture_does_not_fall_back_to_raw_mock_scaffolding() {
    let fixture = batch_fixture();
    let mut out = String::new();

    super::render_engine_factory_test_function(
        &mut out,
        &fixture,
        "sample",
        "batch_scrape",
        "result",
        &permissive_resolver(),
        &HashMap::new(),
        &HashSet::new(),
        "BatchCrawlResults",
        "CrawlConfig",
        false,
        Some("char*"),
        &[],
        &global_sources(),
    )
    .expect("engine-factory batch fixture renders");

    assert!(
        !out.contains("getenv(\"MOCK_SERVER_URL\")"),
        "batch fixture must not fall back to raw mock-harness scaffolding \
         (this is exactly what `reject_mock_harness_scaffolding` rejects in a doc snippet):\n{out}"
    );
    assert!(
        out.contains("snprintf(url, sizeof(url), \"%s\", \"/seed1\");"),
        "expected the first batch_urls entry to become the preserved literal url:\n{out}"
    );
}

/// Control: the same batch-shaped fixture WITHOUT `preserve_input_urls` set must keep using
/// the mock-server scaffolding -- proves the fix is conditioned on the existing preservation
/// flag, not a blanket "always prefer batch_urls" change that would silently unplug the C e2e
/// suite's normal (non-doc) test generation for every batch fixture.
#[test]
fn batch_url_list_fixture_without_preserve_flag_still_uses_mock_server() {
    let mut fixture = batch_fixture();
    fixture.preserve_input_urls = false;
    let mut out = String::new();

    super::render_engine_factory_test_function(
        &mut out,
        &fixture,
        "sample",
        "batch_scrape",
        "result",
        &permissive_resolver(),
        &HashMap::new(),
        &HashSet::new(),
        "BatchCrawlResults",
        "CrawlConfig",
        false,
        Some("char*"),
        &[],
        &global_sources(),
    )
    .expect("engine-factory batch fixture renders");

    assert!(
        out.contains("getenv(\"MOCK_SERVER_URL\")"),
        "without preserve_input_urls the mock-server scaffolding must still be emitted:\n{out}"
    );
    assert!(
        !out.contains("/seed1"),
        "the batch literal must not leak when preservation is off:\n{out}"
    );
}