use super::super::*;
use serde_json::json;
fn minimax_body() -> String {
[
"<think>",
"The user wants a review. Looking at the code:",
"```python",
"def f(x):",
" return x / 0",
"```",
"That divides by zero, so I should report it.",
"</think>",
"```json",
r#"{"issues": [{"line": 2, "message": "division by zero"}], "summary": "one issue"}"#,
"```",
]
.join("\n")
}
#[test]
fn a_leading_think_block_is_stripped_before_the_fence_ladder() {
let extracted = extract_json(&minimax_body()).expect("the answer parses");
let value = match extracted {
Extracted::Complete(value) => value,
Extracted::Truncated(value) => panic!("expected Complete, got Truncated({value})"),
};
assert_eq!(value["issues"].as_array().expect("issues").len(), 1);
assert_eq!(value["issues"][0]["message"], json!("division by zero"));
}
#[test]
fn the_reasoning_text_never_reaches_the_parsed_value() {
let value = match extract_json(&minimax_body()).expect("parses") {
Extracted::Complete(value) => value,
other => panic!("expected Complete, got {other:?}"),
};
assert_eq!(value["summary"], json!("one issue"));
assert!(
!value.to_string().contains("The user wants a review"),
"reasoning leaked into the value: {value}"
);
}
#[test]
fn a_think_tag_that_is_not_at_the_start_is_left_alone() {
let input = r#"{"issues": [{"line": 1, "message": "remove the <think>debug</think> marker"}]}"#;
let value = match extract_json(input).expect("parses") {
Extracted::Complete(value) => value,
other => panic!("expected Complete, got {other:?}"),
};
assert_eq!(
value["issues"][0]["message"],
json!("remove the <think>debug</think> marker")
);
}
#[test]
fn an_unterminated_think_block_yields_no_json() {
let input = "<think>reasoning that never ends\n{\"issues\": []}";
assert_eq!(
extract_json(input),
None,
"an unterminated block is unparseable, not silently recovered"
);
}
#[test]
fn a_response_with_no_think_block_passes_through_byte_for_byte() {
let clean = "```json\n{\"issues\": [], \"summary\": \"clean\"}\n```";
let value = match extract_json(clean).expect("parses") {
Extracted::Complete(value) => value,
other => panic!("expected Complete, got {other:?}"),
};
assert_eq!(value, json!({ "issues": [], "summary": "clean" }));
}
#[test]
fn whitespace_before_the_opening_tag_is_tolerated() {
let input = "\n <think>brief</think>\n{\"issues\": []}";
let value = match extract_json(input).expect("parses") {
Extracted::Complete(value) => value,
other => panic!("expected Complete, got {other:?}"),
};
assert_eq!(value["issues"], json!([]));
}
#[test]
fn a_stripped_response_with_nothing_after_it_is_unparseable() {
assert_eq!(extract_json("<think>all budget spent</think>"), None);
}
#[test]
fn truncation_recovery_still_applies_after_a_strip() {
let input = "<think>reasoning</think>\n{\"issues\": [{\"line\": 1,";
match extract_json(input) {
Some(Extracted::Truncated(value)) => assert_eq!(value["issues"][0]["line"], json!(1)),
other => panic!("expected Truncated, got {other:?}"),
}
}
#[test]
fn a_json_response_quoting_a_code_fence_is_not_mangled_by_it() {
let body = concat!(
r#"{"issues": [{"line": 86, "severity": "high", "category": "bug", "#,
r#""message": "a fenced block like ```json {\"a\": 1} ``` inside a string"}], "#,
r#""summary": "one issue"}"#
);
let value = match extract_json(body).expect("valid JSON is the answer") {
Extracted::Complete(value) => value,
other => panic!("expected Complete, got {other:?}"),
};
assert_eq!(value["summary"], json!("one issue"));
assert!(
value["issues"][0]["message"]
.as_str()
.expect("message")
.contains("```json"),
"the fence inside the string survives untouched: {value}"
);
}
#[test]
fn a_fenced_response_still_wins_when_the_content_itself_is_not_json() {
let body = "Here is my review:\n```json\n{\"issues\": [], \"summary\": \"clean\"}\n```\nHope that helps.";
let value = match extract_json(body).expect("the fence carries the answer") {
Extracted::Complete(value) => value,
other => panic!("expected Complete, got {other:?}"),
};
assert_eq!(value["summary"], json!("clean"));
}
#[test]
fn a_reasoning_block_is_still_stripped_before_the_direct_parse() {
let body = "<think>deliberating</think>{\"issues\": [], \"summary\": \"clean\"}";
let value = match extract_json(body).expect("parses") {
Extracted::Complete(value) => value,
other => panic!("expected Complete, got {other:?}"),
};
assert_eq!(value["summary"], json!("clean"));
}