@@ -53,6 +53,8 @@ pub (crate) fn escape_double_quoted(input: &str) -> String {
5353 '/' => { escaped. push ( '\\' ) ; escaped. push ( '/' ) ; }
5454 '\u{0008}' => { escaped. push ( '\\' ) ; escaped. push ( 'b' ) ; }
5555 '\u{000c}' => { escaped. push ( '\\' ) ; escaped. push ( 'f' ) ; }
56+ '\u{2028}' => { escaped. push_str ( "\\ u2028" ) ; }
57+ '\u{2029}' => { escaped. push_str ( "\\ u2029" ) ; }
5658 _ => escaped. push ( c) ,
5759 }
5860 }
@@ -65,14 +67,16 @@ pub (crate) fn escape_single_quoted(input: &str) -> String {
6567 let mut escaped = String :: with_capacity ( input. len ( ) * 2 ) ;
6668 for c in input. chars ( ) {
6769 match c {
68- '\'' => { escaped. push ( '\\' ) ; escaped. push ( '" ' ) ; }
70+ '\'' => { escaped. push ( '\\' ) ; escaped. push ( '\' ' ) ; }
6971 '\\' => { escaped. push ( '\\' ) ; escaped. push ( '\\' ) ; }
7072 '\n' => { escaped. push ( '\\' ) ; escaped. push ( 'n' ) ; }
7173 '\r' => { escaped. push ( '\\' ) ; escaped. push ( 'r' ) ; }
7274 '\t' => { escaped. push ( '\\' ) ; escaped. push ( 't' ) ; }
7375 '/' => { escaped. push ( '\\' ) ; escaped. push ( '/' ) ; }
7476 '\u{0008}' => { escaped. push ( '\\' ) ; escaped. push ( 'b' ) ; }
7577 '\u{000c}' => { escaped. push ( '\\' ) ; escaped. push ( 'f' ) ; }
78+ '\u{2028}' => { escaped. push_str ( "\\ u2028" ) ; }
79+ '\u{2029}' => { escaped. push_str ( "\\ u2029" ) ; }
7680 _ => escaped. push ( c) ,
7781 }
7882 }
@@ -176,3 +180,151 @@ pub (crate) const MAX_DEPTH: usize = 2000;
176180
177181#[ cfg( feature = "unlimited_depth" ) ]
178182pub ( crate ) const MAX_DEPTH : usize = usize:: MAX ;
183+
184+ #[ cfg( test) ]
185+ mod tests {
186+ use super :: * ;
187+
188+ #[ test]
189+ fn test_escape_single_quote_bug ( ) {
190+ let input = "Hello'World" ;
191+ let result = escape_single_quoted ( input) ;
192+ let expected = "Hello\\ 'World" ;
193+ assert_eq ! ( result, expected, "Single quote should be escaped as \\ ' not \\ \" " ) ;
194+ }
195+
196+ #[ test]
197+ fn test_escape_double_quoted_comprehensive ( ) {
198+ let input = "Hello\" World\n \t \r \\ " ;
199+ let result = escape_double_quoted ( input) ;
200+ let expected = "Hello\\ \" World\\ n\\ t\\ r\\ \\ " ;
201+ assert_eq ! ( result, expected) ;
202+ }
203+
204+ #[ test]
205+ fn test_escape_single_quoted_comprehensive ( ) {
206+ let input = "Hello'World\n \t \r \\ " ;
207+ let result = escape_single_quoted ( input) ;
208+ let expected = "Hello\\ 'World\\ n\\ t\\ r\\ \\ " ;
209+ assert_eq ! ( result, expected) ;
210+ }
211+
212+ #[ test]
213+ fn test_unescape_basic_escapes ( ) {
214+ let input = "Hello\\ nWorld\\ t\\ r\\ \\ " ;
215+ let result = unescape ( input) . unwrap ( ) ;
216+ let expected = "Hello\n World\t \r \\ " ;
217+ assert_eq ! ( result, expected) ;
218+ }
219+
220+ #[ test]
221+ fn test_unescape_quotes ( ) {
222+ let input = "He said \\ \" Hello\\ \" and she said \\ 'Hi\\ '" ;
223+ let result = unescape ( input) . unwrap ( ) ;
224+ let expected = "He said \" Hello\" and she said 'Hi'" ;
225+ assert_eq ! ( result, expected) ;
226+ }
227+
228+ #[ test]
229+ fn test_unescape_unicode_valid ( ) {
230+ let input = "Unicode: \\ u0041\\ u0042\\ u2764" ;
231+ let result = unescape ( input) . unwrap ( ) ;
232+ let expected = "Unicode: AB❤" ;
233+ assert_eq ! ( result, expected) ;
234+ }
235+
236+ #[ test]
237+ fn test_unescape_hex_valid ( ) {
238+ let input = "Hex: \\ x41\\ x42\\ x21" ;
239+ let result = unescape ( input) . unwrap ( ) ;
240+ let expected = "Hex: AB!" ;
241+ assert_eq ! ( result, expected) ;
242+ }
243+
244+ #[ test]
245+ fn test_unescape_invalid_unicode_short ( ) {
246+ let input = "Invalid: \\ u12G" ; // Invalid hex digit
247+ let result = unescape ( input) ;
248+ assert ! ( result. is_err( ) , "Should fail on invalid unicode escape" ) ;
249+ }
250+
251+ #[ test]
252+ fn test_unescape_invalid_unicode_incomplete ( ) {
253+ let input = "Incomplete: \\ u123" ; // Too few digits
254+ let result = unescape ( input) ;
255+ assert ! ( result. is_err( ) , "Should fail on incomplete unicode escape" ) ;
256+ }
257+
258+ #[ test]
259+ fn test_unescape_invalid_hex_char ( ) {
260+ let input = "Invalid hex: \\ xZZ" ;
261+ let result = unescape ( input) ;
262+ assert ! ( result. is_err( ) , "Should fail on invalid hex escape" ) ;
263+ }
264+
265+ #[ test]
266+ fn test_unescape_invalid_hex_incomplete ( ) {
267+ let input = "Incomplete hex: \\ x1" ;
268+ let result = unescape ( input) ;
269+ assert ! ( result. is_err( ) , "Should fail on incomplete hex escape" ) ;
270+ }
271+
272+ #[ test]
273+ fn test_unescape_unknown_escape ( ) {
274+ let input = "Unknown: \\ z" ;
275+ let result = unescape ( input) ;
276+ assert ! ( result. is_err( ) , "Should fail on unknown escape sequence" ) ;
277+ }
278+
279+ #[ test]
280+ fn test_unescape_incomplete_escape_at_end ( ) {
281+ let input = "Incomplete: \\ " ;
282+ let result = unescape ( input) ;
283+ assert ! ( result. is_err( ) , "Should fail on incomplete escape at end" ) ;
284+ }
285+
286+ #[ test]
287+ fn test_unescape_line_continuation ( ) {
288+ let input = "Line\\ ncontinuation" ;
289+ let result = unescape ( input) . unwrap ( ) ;
290+ let expected = "Line\n continuation" ;
291+ assert_eq ! ( result, expected) ;
292+ }
293+
294+ #[ test]
295+ fn test_unescape_all_special_chars ( ) {
296+ let input = "\\ a\\ b\\ f\\ n\\ r\\ t\\ v\\ 0\\ \\ \\ '\\ \" " ;
297+ let result = unescape ( input) . unwrap ( ) ;
298+ let expected = "\x07 \x08 \x0C \n \r \t \x0B \0 \\ '\" " ;
299+ assert_eq ! ( result, expected) ;
300+ }
301+
302+ #[ test]
303+ fn test_unescape_unicode_line_separators ( ) {
304+ let input = "\\ u2028\\ u2029" ; // Line separator, Paragraph separator
305+ let result = unescape ( input) . unwrap ( ) ;
306+ let expected = "\u{2028} \u{2029} " ;
307+ assert_eq ! ( result, expected) ;
308+ }
309+
310+ #[ test]
311+ fn test_read_hex_digits_valid ( ) {
312+ let mut chars = "ABCD" . chars ( ) . peekable ( ) ;
313+ let result = read_hex_digits ( & mut chars, 4 , "\\ u" ) . unwrap ( ) ;
314+ assert_eq ! ( result, 0xABCD ) ;
315+ }
316+
317+ #[ test]
318+ fn test_read_hex_digits_invalid_char ( ) {
319+ let mut chars = "12G4" . chars ( ) . peekable ( ) ;
320+ let result = read_hex_digits ( & mut chars, 4 , "\\ u" ) ;
321+ assert ! ( result. is_err( ) , "Should fail on invalid hex character" ) ;
322+ }
323+
324+ #[ test]
325+ fn test_read_hex_digits_incomplete ( ) {
326+ let mut chars = "12" . chars ( ) . peekable ( ) ;
327+ let result = read_hex_digits ( & mut chars, 4 , "\\ u" ) ;
328+ assert ! ( result. is_err( ) , "Should fail on incomplete hex sequence" ) ;
329+ }
330+ }
0 commit comments