use picojson::{Event, ParseError, PullParser, SliceParser, String};
#[test]
fn test_malformed_json_missing_quotes() {
let json = r#"{name: "value"}"#; let mut parser = SliceParser::new(json);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
match parser.next_event() {
Err(ParseError::TokenizerError(_)) => {
}
other => panic!("Expected TokenizerError for unquoted key, got: {:?}", other),
}
}
#[test]
fn test_malformed_json_unterminated_string() {
let json = r#"{"unterminated": "missing quote}"#; let mut parser = SliceParser::new(json);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(
parser.next_event(),
Ok(Event::Key(String::Borrowed("unterminated")))
);
match parser.next_event() {
Err(ParseError::TokenizerError(_)) => {
}
other => panic!(
"Expected TokenizerError for unterminated string, got: {:?}",
other
),
}
}
#[test]
fn test_malformed_json_invalid_escape() {
let json = r#"{"bad_escape": "invalid\x"}"#; let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(json, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(
parser.next_event(),
Ok(Event::Key(String::Borrowed("bad_escape")))
);
match parser.next_event() {
Err(ParseError::InvalidEscapeSequence) => {
}
Err(ParseError::TokenizerError(_)) => {
}
other => panic!("Expected escape sequence error, got: {:?}", other),
}
}
#[test]
fn test_malformed_json_invalid_unicode_escape() {
let json = r#"{"bad_unicode": "test\uXYZ"}"#; let mut scratch = [0u8; 1024];
let mut parser = SliceParser::with_buffer(json, &mut scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(
parser.next_event(),
Ok(Event::Key(String::Borrowed("bad_unicode")))
);
match parser.next_event() {
Err(ParseError::InvalidUnicodeHex) => {
}
Err(ParseError::TokenizerError(_)) => {
}
other => panic!("Expected Unicode hex error, got: {:?}", other),
}
}
#[test]
fn test_buffer_overflow_error() {
let json = r#"{"large_string": "This is a very long string with escapes\nand more escapes\tand even more content that might overflow a small buffer"}"#;
let mut small_scratch = [0u8; 10]; let mut parser = SliceParser::with_buffer(json, &mut small_scratch);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(
parser.next_event(),
Ok(Event::Key(String::Borrowed("large_string")))
);
match parser.next_event() {
Err(ParseError::ScratchBufferFull) => {
}
other => panic!("Expected ScratchBufferFull error, got: {:?}", other),
}
}
#[test]
fn test_empty_input_error() {
let json = "";
let mut parser = SliceParser::new(json);
match parser.next_event() {
Ok(Event::EndDocument) => {
}
Err(ParseError::EndOfData) => {
}
Err(ParseError::TokenizerError(_)) => {
}
other => panic!("Unexpected result for empty input: {:?}", other),
}
}
#[test]
fn test_incomplete_json_error() {
let json = r#"{"incomplete""#; let mut parser = SliceParser::new(json);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(
parser.next_event(),
Ok(Event::Key(String::Borrowed("incomplete")))
);
match parser.next_event() {
Err(ParseError::TokenizerError(_)) => {
}
Err(ParseError::EndOfData) => {
}
Ok(Event::EndDocument) => {
}
other => panic!(
"Expected error or EndDocument for incomplete JSON, got: {:?}",
other
),
}
}
#[test]
fn test_malformed_json_unexpected_comma() {
let json = r#"{"key": "value",}"#; let mut parser = SliceParser::new(json);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
assert_eq!(
parser.next_event(),
Ok(Event::String(String::Borrowed("value")))
);
match parser.next_event() {
Ok(Event::EndObject) => {
}
Err(ParseError::TokenizerError(_)) => {
}
other => panic!(
"Expected EndObject or TokenizerError for trailing comma, got: {:?}",
other
),
}
}
#[test]
fn test_malformed_json_invalid_number() {
let json = r#"{"number": 123.456.789}"#; let mut parser = SliceParser::new(json);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(
parser.next_event(),
Ok(Event::Key(String::Borrowed("number")))
);
match parser.next_event() {
Err(ParseError::TokenizerError(_)) => {
}
other => panic!(
"Expected TokenizerError for invalid number, got: {:?}",
other
),
}
}
#[test]
fn test_error_includes_line_and_column_info() {
let json = "{\n \"key\": \"value\"\n invalid\n}";
let mut parser = SliceParser::new(json);
assert_eq!(parser.next_event(), Ok(Event::StartObject));
assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
assert_eq!(
parser.next_event(),
Ok(Event::String(String::Borrowed("value")))
);
match parser.next_event() {
Err(e) => {
let err_msg = format!("{}", e);
assert!(
err_msg.contains("line") && err_msg.contains("column"),
"Error message should contain line and column info, got: {}",
err_msg
);
assert!(
err_msg.contains("line 3"),
"Expected line 3, got: {}",
err_msg
);
}
other => panic!("Expected error for invalid JSON, got: {:?}", other),
}
}
#[test]
fn test_multiline_error_tracking() {
let json = "[\n 1,\n 2,\n true,\n]"; let mut parser = SliceParser::new(json);
let err = loop {
match parser.next_event() {
Ok(Event::StartArray) | Ok(Event::Bool(_)) | Ok(Event::Number(_)) => continue,
Err(e) => break e,
other => panic!("Expected trailing comma error, got: {:?}", other),
}
};
let err_msg = format!("{}", err);
assert!(
err_msg.contains("line 4"),
"Expected line 4 in error message, got: {}",
err_msg
);
assert!(
err_msg.contains("column 7"),
"Expected column 7 in error message, got: {}",
err_msg
);
}