use super::*;
use crate::e2e::config::{CallConfig, CallOverride};
#[test]
fn client_factory_snippet_never_points_the_reader_at_the_mock_server() {
let fixture = Fixture {
id: "rate_limit_429".into(),
description: "Rate limited".into(),
input: serde_json::Value::Null,
..Fixture::default()
};
let mut call = CallConfig {
function: "chat".into(),
result_var: "result".into(),
..CallConfig::default()
};
call.overrides.insert(
"kotlin".into(),
CallOverride {
client_factory: Some("create_client".into()),
..CallOverride::default()
},
);
let body = render_snippet_body(
&fixture,
&E2eConfig {
call,
..E2eConfig::default()
},
&ResolvedCrateConfig::default(),
&[],
&[],
false,
)
.expect("snippet renders");
assert!(!body.contains("MOCK_SERVER"), "mock-server env var leaked:\n{body}");
assert!(!body.contains("mockServer"), "mock-server property leaked:\n{body}");
assert!(
!body.contains("/fixtures/rate_limit_429"),
"mock-server fixture route leaked:\n{body}"
);
assert!(!body.contains("\"test-key\""), "literal credential leaked:\n{body}");
assert!(
body.contains("System.getenv(\"API_KEY\")"),
"credential is not read from the environment:\n{body}"
);
assert!(
body.contains("createClient(apiKey = apiKey)"),
"an unconfigured project must construct the client without a mock base URL:\n{body}"
);
}
fn client_release_snippet(expects_error: bool) -> String {
let mut fixture = Fixture {
id: "rate_limit_429".into(),
description: "Rated limited".into(),
input: serde_json::Value::Null,
..Fixture::default()
};
if expects_error {
fixture.assertions = serde_json::from_value(serde_json::json!([{"type": "error"}])).expect("assertions");
}
let mut call = CallConfig {
function: "chat".into(),
result_var: "result".into(),
..CallConfig::default()
};
call.overrides.insert(
"kotlin".into(),
CallOverride {
client_factory: Some("create_client".into()),
..CallOverride::default()
},
);
let config = ResolvedCrateConfig {
name: "sample".into(),
..ResolvedCrateConfig::default()
};
render_snippet_body(
&fixture,
&E2eConfig {
call,
..E2eConfig::default()
},
&config,
&[],
&[],
false,
)
.expect("snippet renders")
}
#[test]
fn client_factory_snippet_releases_the_client_in_a_use_block() {
let body = client_release_snippet(false);
assert!(
body.contains("Sample.createClient(apiKey = apiKey).use { client -> client.chat() }"),
"the client must be released via a `use` block around the call:\n{body}"
);
assert!(
!body.contains("client.close()"),
"no bare close() call must remain:\n{body}"
);
}
#[test]
fn client_factory_snippet_releases_the_client_on_the_error_path() {
let body = client_release_snippet(true);
let try_open = body
.find(" try {")
.expect("expects-error snippet still opens a try block");
let use_block = body
.find("Sample.createClient(apiKey = apiKey).use { client -> client.chat() }")
.expect("client construction moves inside the try, unchanged in shape");
let catch_clause = body.find("catch (error: Exception)").expect("catch clause present");
assert!(
try_open < use_block && use_block < catch_clause,
"the use block must sit inside the try that the catch closes:\n{body}"
);
assert!(
!body.contains("client.close()"),
"no bare close() call must remain:\n{body}"
);
}
#[test]
fn snippet_without_a_client_factory_is_unchanged() {
let fixture: Fixture = serde_json::from_value(serde_json::json!({
"id": "invalid_input", "description": "Reject invalid input", "input": null,
"assertions": [{"type": "error"}]
}))
.expect("fixture");
let mut e2e = E2eConfig::default();
e2e.call.function = "process".into();
let config = ResolvedCrateConfig {
name: "sample".into(),
..ResolvedCrateConfig::default()
};
let body = render_snippet_body(&fixture, &e2e, &config, &[], &[], false).expect("snippet renders");
assert!(
!body.contains(".use {"),
"a snippet that constructs no client must emit no use block:\n{body}"
);
assert!(
!body.contains("close()"),
"a snippet that constructs no client must emit no close call:\n{body}"
);
assert!(
body.contains(" val result = Sample.process()"),
"the plain call must be unchanged:\n{body}"
);
}
#[test]
fn a_snippet_renders_the_base_url_the_fixture_documents() {
let fixture: Fixture = serde_json::from_value(serde_json::json!({
"id": "custom_base_url",
"description": "Custom base URL",
"input": null,
"docs": {
"topic": "configuration",
"client": {"base_url": "https://llm.internal.example.com/v1"}
}
}))
.expect("fixture");
let mut call = CallConfig {
function: "chat".into(),
result_var: "result".into(),
..CallConfig::default()
};
call.overrides.insert(
"kotlin".into(),
CallOverride {
client_factory: Some("create_client".into()),
..CallOverride::default()
},
);
let body = render_snippet_body(
&fixture,
&E2eConfig {
call,
..E2eConfig::default()
},
&ResolvedCrateConfig::default(),
&[],
&[],
false,
)
.expect("snippet renders");
assert!(
body.contains("createClient(apiKey = apiKey, baseUrl = \"https://llm.internal.example.com/v1\")"),
"the snippet for a custom-base-url topic must show the custom base URL:\n{body}"
);
}
#[test]
fn a_fixture_without_a_docs_client_keeps_the_bare_client_construction_call() {
let fixture = Fixture {
id: "rate_limit_429".into(),
description: "Rate limited".into(),
input: serde_json::Value::Null,
..Fixture::default()
};
let mut call = CallConfig {
function: "chat".into(),
result_var: "result".into(),
..CallConfig::default()
};
call.overrides.insert(
"kotlin".into(),
CallOverride {
client_factory: Some("create_client".into()),
..CallOverride::default()
},
);
let body = render_snippet_body(
&fixture,
&E2eConfig {
call,
..E2eConfig::default()
},
&ResolvedCrateConfig::default(),
&[],
&[],
false,
)
.expect("snippet renders");
assert!(
body.contains("createClient(apiKey = apiKey)"),
"an unconfigured project must construct the client without a base URL:\n{body}"
);
assert!(
!body.contains("baseUrl"),
"no docs client must mean no baseUrl argument:\n{body}"
);
}