use std::collections::HashSet;
use super::test_file::render_test_file;
use crate::core::config::ResolvedCrateConfig;
use crate::e2e::codegen::call_ir::CallIr;
use crate::e2e::config::{CallOverride, E2eConfig};
use crate::e2e::fixture::{Assertion, Fixture};
fn mock_assertion(field: &str, assertion_type: &str, value: serde_json::Value) -> Assertion {
Assertion {
assertion_type: assertion_type.to_string(),
field: Some(field.to_string()),
value: Some(value),
..Default::default()
}
}
fn render(fixture: Fixture, e2e_config: &E2eConfig) -> String {
render_test_file(
"mock_capture",
&[&fixture],
e2e_config,
"chat",
"result",
&[],
"sample",
"sample",
&ResolvedCrateConfig::default(),
&[],
&[],
CallIr::default(),
&[],
)
}
#[test]
fn a_mock_assertion_gets_both_its_call_and_the_helper_definition_in_one_file() {
let fixture = Fixture {
id: "mock_capture_fixture".to_string(),
description: "asserts against the mock server request log".to_string(),
assertions: vec![
mock_assertion("mock.requests.total", "equals", serde_json::json!(1)),
mock_assertion(
r#"mock.requests["POST /v1/chat"]"#,
"greater_than_or_equal",
serde_json::json!(1),
),
],
..Fixture::default()
};
let mut e2e_config = E2eConfig::default();
e2e_config.call.function = "chat".to_string();
let out = render(fixture, &e2e_config);
assert!(
out.contains(
" try testing.expectEqual(@as(u64, 1), alefMockRequestCount(if (std.c.getenv(\"MOCK_SERVER_URL\")) |v| std.mem.span(v) else \"http://localhost:8080\", \"/__alef/requests/total?prefix=\"));"
),
"expected the total-count call, got:\n{out}"
);
assert!(
out.contains(
" try testing.expect(alefMockRequestCount(if (std.c.getenv(\"MOCK_SERVER_URL\")) |v| std.mem.span(v) else \"http://localhost:8080\", \"/__alef/requests/one?key=POST%20%2Fv1%2Fchat\") >= @as(u64, 1));"
),
"expected the bracketed-key call, got:\n{out}"
);
assert!(
out.contains("fn alefMockRequestCount(baseUrl: []const u8, pathAndQuery: []const u8) u64 {"),
"expected the helper definition in the same file as the call, got:\n{out}"
);
}
#[test]
fn a_file_with_no_mock_assertion_defines_no_helper() {
let fixture = Fixture {
id: "no_mock".to_string(),
description: "no mock assertions at all".to_string(),
assertions: vec![Assertion {
assertion_type: "not_error".to_string(),
..Default::default()
}],
..Fixture::default()
};
let mut e2e_config = E2eConfig::default();
e2e_config.call.function = "chat".to_string();
let out = render(fixture, &e2e_config);
assert!(
!out.contains("alefMockRequestCount"),
"a file with no mock.* assertion must not reference or define the helper, got:\n{out}"
);
}
#[test]
fn a_mock_only_assertion_on_the_json_struct_path_still_renders_and_binds_nothing_unused() {
let fixture = Fixture {
id: "mock_only_json_struct".to_string(),
description: "asserts only against the mock server request log".to_string(),
assertions: vec![mock_assertion("mock.requests.total", "count_min", serde_json::json!(1))],
..Fixture::default()
};
let mut e2e_config = E2eConfig::default();
e2e_config.call.function = "chat".to_string();
e2e_config.result_fields = HashSet::from(["summary".to_string()]);
e2e_config.call.overrides.insert(
"zig".to_string(),
CallOverride {
result_is_json_struct: true,
..CallOverride::default()
},
);
let out = render(fixture, &e2e_config);
assert!(
out.contains(">= @as(u64, 1)"),
"expected the mock assertion to render even though it is the fixture's only assertion, got:\n{out}"
);
assert!(
!out.contains("_parsed"),
"a mock-only fixture must not bind the unused JSON-parse locals, got:\n{out}"
);
assert!(
!out.contains("std.heap.DebugAllocator"),
"a mock-only fixture must not bind the unused GPA allocator, got:\n{out}"
);
}
#[test]
fn a_mock_only_assertion_on_the_bytes_result_path_still_renders() {
let fixture = Fixture {
id: "mock_only_bytes".to_string(),
description: "asserts only against the mock server request log".to_string(),
assertions: vec![mock_assertion("mock.requests.total", "count_min", serde_json::json!(1))],
..Fixture::default()
};
let mut e2e_config = E2eConfig::default();
e2e_config.call.function = "speech".to_string();
e2e_config.call.overrides.insert(
"zig".to_string(),
CallOverride {
result_is_bytes: true,
client_factory: Some("Client.create".to_string()),
..CallOverride::default()
},
);
let out = render(fixture, &e2e_config);
assert!(
out.contains(">= @as(u64, 1)"),
"expected the mock assertion to render on the bytes-result path, got:\n{out}"
);
assert!(
!out.contains("not implemented for zig bytes"),
"must not fall through to the bytes-assertion catch-all, got:\n{out}"
);
}