@@ -51,3 +51,46 @@ fn test_string_with_colon_at_start() {
5151 let expected = serde_json:: json!( ":" ) ;
5252 assert_eq ! ( actual, expected) ;
5353}
54+
55+ #[ test]
56+ fn test_multibyte_unicode_missing_end_quote ( ) {
57+ // Triggers index out of bounds in insert_before_last_whitespace_str.
58+ // The output buffer contains multi-byte UTF-8 characters (é = 2 bytes each),
59+ // so self.output.len() (byte count) > chars.len() (char count).
60+ // When the repair path calls insert_before_last_whitespace_str with trailing
61+ // whitespace, it initialises `index` from the byte length and then indexes
62+ // into a Vec<char> at that byte-length position, panicking.
63+ let fixture = r#""café "# ;
64+ let actual = json_repair :: < serde_json:: Value > ( fixture) . unwrap ( ) ;
65+ let expected = serde_json:: json!( "café" ) ;
66+ assert_eq ! ( actual, expected) ;
67+ }
68+
69+ #[ test]
70+ fn test_multibyte_unicode_missing_comma_in_object ( ) {
71+ // Triggers index out of bounds in insert_before_last_whitespace_str (line 459).
72+ // parse_string first collects `"é,"` and hits the inner `"test"`. The
73+ // prev_non_whitespace char is `,`, so it retries with stop_at_index=2
74+ // (the comma position). On retry it collects str_content = `"é` (3 bytes,
75+ // 2 chars) and hits stop_at_index, calling insert_before_last_whitespace_str.
76+ // That function sets index = text.len() = 3 (byte count) and then accesses
77+ // chars[index - 1] = chars[2] on a Vec<char> of length 2 — panic.
78+ let fixture = "\" é,\" test\" " ;
79+ let actual = json_repair :: < serde_json:: Value > ( fixture) . unwrap ( ) ;
80+ let expected = serde_json:: json!( [ "é" , "test" ] ) ;
81+ assert_eq ! ( actual, expected) ;
82+ }
83+
84+ #[ test]
85+ fn test_multibyte_unicode_missing_closing_brace ( ) {
86+ // Triggers index out of bounds in insert_before_last_whitespace_str (line 384).
87+ // A string with a multi-byte character followed by trailing whitespace and
88+ // no closing quote hits the "end of text, missing end quote" repair path.
89+ // str_content = `"🎉 ` (6 bytes, 3 chars). insert_before_last_whitespace_str
90+ // sets index = text.len() = 6 and accesses chars[5] on a Vec<char> of
91+ // length 3 — panic.
92+ let fixture = "\" 🎉 " ;
93+ let actual = json_repair :: < serde_json:: Value > ( fixture) . unwrap ( ) ;
94+ let expected = serde_json:: json!( "🎉" ) ;
95+ assert_eq ! ( actual, expected) ;
96+ }
0 commit comments