use serde_json::json;
use super::{deliver_schema, sampling_temperature};
#[test]
fn bedrock_slugs_get_no_temperature() {
for model in ["bedrock/us.anthropic.claude-sonnet-5", "BEDROCK/x"] {
assert_eq!(sampling_temperature(model, 0.2), None, "{model}");
}
for model in [
"openrouter/anthropic/claude-sonnet-5",
"anthropic/claude-sonnet-5",
"gpt-4o-mini",
"my-bedrock-proxy/model",
] {
assert_eq!(sampling_temperature(model, 0.2), Some(0.2), "{model}");
}
}
fn schema() -> serde_json::Value {
json!({"type": "object", "properties": {"findings": {"type": "array"}}})
}
#[test]
fn structured_provider_gets_the_field_and_a_clean_system_turn() {
let (system, directive) = deliver_schema("BASE", "period_findings", schema(), true);
let directive = directive.expect("a structured-output provider gets the real field");
assert_eq!(directive.name, "period_findings");
assert_eq!(directive.schema, schema());
assert!(
directive.strict,
"the passes want the constraint, not best-effort JSON"
);
assert_eq!(
system, "BASE",
"the schema must not also be pasted into the prompt: {system}"
);
}
#[test]
fn unsupported_provider_gets_the_prose_fallback() {
let (system, directive) = deliver_schema("BASE", "period_findings", schema(), false);
assert!(
directive.is_none(),
"a provider without the capability must not be sent the field"
);
assert!(system.starts_with("BASE"), "{system}");
assert!(
system.contains("\"findings\""),
"the schema must still reach the model: {system}"
);
}
#[test]
fn the_schema_is_delivered_exactly_once() {
for structured_output in [true, false] {
let (system, directive) = deliver_schema("BASE", "n", schema(), structured_output);
assert_eq!(
system.contains("\"findings\""),
directive.is_none(),
"exactly one delivery for structured_output={structured_output}: {system}"
);
}
}
fn assert_strict(node: &serde_json::Value, path: &str) {
let Some(map) = node.as_object() else { return };
if let Some(props) = map.get("properties").and_then(|p| p.as_object()) {
assert_eq!(
map.get("additionalProperties"),
Some(&serde_json::Value::Bool(false)),
"{path}: object node must set additionalProperties:false"
);
let required: Vec<&str> = map
.get("required")
.and_then(|r| r.as_array())
.map(|r| r.iter().filter_map(|v| v.as_str()).collect())
.unwrap_or_default();
assert_eq!(
required.len(),
props.len(),
"{path}: required must list every property, got {required:?}"
);
for key in props.keys() {
assert!(
required.contains(&key.as_str()),
"{path}: property {key} missing from required"
);
}
for (key, child) in props {
assert_strict(child, &format!("{path}.{key}"));
}
}
if let Some(items) = map.get("items") {
assert_strict(items, &format!("{path}[]"));
}
match map.get("additionalProperties") {
Some(additional) if additional.is_object() => {
assert_strict(additional, &format!("{path}.*"));
}
_ => {}
}
}
#[test]
fn the_sent_schemas_are_openai_strict_compliant() {
let cases = [
(
crate::profile::batch_reviewer::PERIOD_FINDINGS_SCHEMA_NAME,
crate::profile::batch_reviewer::period_findings_schema(),
),
(
crate::profile::synthesizer::SYNTHESIS_OUTPUT_SCHEMA_NAME,
crate::profile::synthesizer::synthesis_output_schema(),
),
];
for (name, schema) in cases {
let (_, directive) = deliver_schema("BASE", name, schema, true);
let directive = directive.expect("the structured arm yields a directive");
let sent = directive.openai_response_format();
assert_eq!(sent["json_schema"]["strict"], json!(true), "{sent}");
assert_strict(&sent["json_schema"]["schema"], name);
}
}
#[test]
fn nullable_optionals_survive_strict_normalization() {
let (_, directive) = deliver_schema(
"BASE",
crate::profile::batch_reviewer::PERIOD_FINDINGS_SCHEMA_NAME,
crate::profile::batch_reviewer::period_findings_schema(),
true,
);
let sent = directive
.expect("the structured arm yields a directive")
.openai_response_format();
let item = &sent["json_schema"]["schema"]["properties"]["findings"]["items"];
for key in ["suggestion", "file"] {
assert_eq!(
item["properties"][key]["type"],
json!(["string", "null"]),
"{key} must stay nullable on the wire: {item}"
);
}
assert_eq!(
item["properties"]["confidence"]["type"],
json!(["number", "null"]),
"{item}"
);
assert_eq!(
item["properties"]["severity"]["type"],
json!(["string", "null"]),
"{item}"
);
assert_eq!(
item["properties"]["severity"]["enum"],
json!(["low", "medium", "high", "critical", null]),
"a nullable enum must keep its null member, or null is rejected: {item}"
);
assert_eq!(
item["required"],
json!([
"confidence",
"description",
"file",
"kind",
"severity",
"suggestion"
]),
"{item}"
);
}