use crate::e2e::config::E2eConfig;
use crate::e2e::fixture::Fixture;
use anyhow::{Result, bail};
use super::category::{build_cli_command, determine_subcommand};
const LANG: &str = "brew";
pub(super) fn render_snippet_body(fixture: &Fixture, e2e_config: &E2eConfig) -> Result<String> {
let call_config = e2e_config.resolve_call_for_fixture(
fixture.call.as_deref(),
&fixture.id,
&fixture.resolved_category(),
&fixture.tags,
&fixture.input,
);
if let Some(reason) = call_config.unsupported_in.get(LANG) {
bail!(
"brew documentation snippet for fixture `{}` is unsupported: {reason}",
fixture.id
);
}
let top_level_overrides = e2e_config.call.overrides.get(LANG);
let default_subcommand = top_level_overrides
.and_then(|value| value.function.as_ref())
.cloned()
.unwrap_or_else(|| e2e_config.call.function.clone());
let fixture_overrides = call_config.overrides.get(LANG);
let subcommand = match fixture_overrides.and_then(|value| value.function.as_ref()) {
Some(function) => function.clone(),
None => determine_subcommand(&fixture.tags, &default_subcommand),
};
let binary_name = resolve_binary_name(e2e_config, &call_config.module)?;
let static_cli_args: Vec<String> = top_level_overrides
.map(|value| value.cli_args.clone())
.unwrap_or_default();
let cli_flags: std::collections::HashMap<String, String> = top_level_overrides
.map(|value| value.cli_flags.clone())
.unwrap_or_default();
let command = build_cli_command(
fixture,
&binary_name,
&subcommand,
&static_cli_args,
&cli_flags,
fixture.resolved_args(call_config),
)
.join(" ");
Ok(crate::e2e::template_env::render(
"brew/snippet_body.jinja",
minijinja::context! { command => command },
))
}
fn resolve_binary_name(e2e_config: &E2eConfig, call_module: &str) -> Result<String> {
let name = e2e_config
.registry
.packages
.get(LANG)
.and_then(|package| package.name.as_ref())
.cloned()
.or_else(|| {
e2e_config
.packages
.get(LANG)
.and_then(|package| package.name.as_ref())
.cloned()
})
.unwrap_or_else(|| call_module.to_string());
if name.trim().is_empty() {
bail!(
"brew documentation snippet has no configured binary name; set \
`[crates.e2e.registry.packages.brew].name` or `[crates.e2e.call].module`"
);
}
Ok(name)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::config::e2e::{CallOverride, PackageRef};
fn fixture() -> Fixture {
Fixture {
id: "quick_start".into(),
description: "Quick start".into(),
input: serde_json::json!({}),
preserve_input_urls: true,
..Fixture::default()
}
}
fn e2e_with_call(function: &str, module: &str) -> E2eConfig {
let mut e2e = E2eConfig::default();
e2e.call.function = function.into();
e2e.call.module = module.into();
e2e.call.args = vec![crate::core::config::e2e::ArgMapping {
name: "url".into(),
field: "url".into(),
arg_type: "mock_url".into(),
optional: false,
owned: false,
element_type: None,
go_type: None,
vec_inner_is_ref: false,
trait_name: None,
}];
e2e
}
#[test]
fn renders_a_single_line_reader_executable_invocation() {
let mut fixture = fixture();
fixture.input = serde_json::json!({"url": "https://example.com/sample.html"});
let e2e = e2e_with_call("scrape", "mytool");
let body = render_snippet_body(&fixture, &e2e).expect("brew snippet renders");
assert_eq!(body, "mytool scrape 'https://example.com/sample.html'\n");
}
#[test]
fn a_brew_specific_function_override_becomes_the_subcommand() {
let mut fixture = fixture();
fixture.input = serde_json::json!({"url": "https://example.com/sample.html"});
let mut e2e = e2e_with_call("scrape", "mytool");
e2e.call.overrides.insert(
"brew".into(),
CallOverride {
function: Some("crawl".into()),
..CallOverride::default()
},
);
let body = render_snippet_body(&fixture, &e2e).expect("brew snippet renders");
assert!(body.starts_with("mytool crawl "), "{body}");
}
#[test]
fn a_named_calls_brew_override_wins_over_the_top_level_default_subcommand() {
use crate::core::config::e2e::CallConfig;
let mut fixture = fixture();
fixture.call = Some("special".into());
fixture.input = serde_json::json!({"url": "https://example.com/sample.html"});
let mut e2e = e2e_with_call("scrape", "mytool");
let mut special = CallConfig {
function: "special_scrape".into(),
module: "mytool".into(),
args: e2e.call.args.clone(),
..CallConfig::default()
};
special.overrides.insert(
"brew".into(),
CallOverride {
function: Some("crawl".into()),
..CallOverride::default()
},
);
e2e.calls.insert("special".into(), special);
let body = render_snippet_body(&fixture, &e2e).expect("brew snippet renders");
assert!(
body.starts_with("mytool crawl "),
"the named call's own brew override must win over the top-level default: {body}"
);
}
#[test]
fn a_registered_package_name_wins_over_the_call_module() {
let mut fixture = fixture();
fixture.input = serde_json::json!({"url": "https://example.com/sample.html"});
let mut e2e = e2e_with_call("scrape", "mytool");
e2e.registry.packages.insert(
"brew".into(),
PackageRef {
name: Some("published-cli".into()),
..PackageRef::default()
},
);
let body = render_snippet_body(&fixture, &e2e).expect("brew snippet renders");
assert!(body.starts_with("published-cli scrape "), "{body}");
}
#[test]
fn a_published_snippet_never_leaks_mock_harness_scaffolding() {
let mut fixture = fixture();
fixture.input = serde_json::json!({"url": "https://example.com"});
let e2e = e2e_with_call("scrape", "mytool");
let body = render_snippet_body(&fixture, &e2e).expect("brew snippet renders");
assert!(!body.contains("MOCK_SERVER"), "{body}");
crate::e2e::snippets::mock_harness_guard::reject_mock_harness_scaffolding(&body, &fixture, "brew")
.expect("a snippet built on an already-resolved literal must pass the guard");
}
#[test]
fn an_unresolved_url_falls_back_to_the_mock_server_and_the_guard_catches_it() {
let fixture = fixture();
let e2e = e2e_with_call("scrape", "mytool");
let body = render_snippet_body(&fixture, &e2e).expect("brew snippet renders");
assert!(body.contains("MOCK_SERVER"), "{body}");
let error = crate::e2e::snippets::mock_harness_guard::reject_mock_harness_scaffolding(&body, &fixture, "brew")
.expect_err("the guard must reject a body naming the mock-server fallback");
assert!(error.to_string().contains("MOCK_SERVER"), "{error}");
}
#[test]
fn an_unsupported_in_brew_call_is_reported_rather_than_rendered() {
let mut fixture = fixture();
fixture.input = serde_json::json!({"url": "https://example.com/sample.html"});
let mut e2e = e2e_with_call("interact", "mytool");
e2e.call
.unsupported_in
.insert("brew".into(), "requires serializing Vec<PageAction>".into());
let error = render_snippet_body(&fixture, &e2e).expect_err("unsupported call must not render");
assert!(error.to_string().contains("unsupported"), "{error}");
}
#[test]
fn cli_flags_and_static_args_are_appended_in_order() {
let mut fixture = fixture();
fixture.input = serde_json::json!({"url": "https://example.com/sample.html", "format": "markdown"});
let mut e2e = e2e_with_call("scrape", "mytool");
e2e.call.args.push(crate::core::config::e2e::ArgMapping {
name: "format".into(),
field: "format".into(),
arg_type: "string".into(),
optional: false,
owned: false,
element_type: None,
go_type: None,
vec_inner_is_ref: false,
trait_name: None,
});
e2e.call.overrides.insert(
"brew".into(),
CallOverride {
cli_args: vec!["--json".into()],
cli_flags: std::collections::HashMap::from([("format".to_string(), "--format".to_string())]),
..CallOverride::default()
},
);
let body = render_snippet_body(&fixture, &e2e).expect("brew snippet renders");
assert_eq!(
body,
"mytool scrape 'https://example.com/sample.html' --format 'markdown' --json\n"
);
}
}