@@ -53,6 +53,8 @@ pub (crate) fn escape_double_quoted(input: &str) -> String {
53
53
'/' => { escaped. push ( '\\' ) ; escaped. push ( '/' ) ; }
54
54
'\u{0008}' => { escaped. push ( '\\' ) ; escaped. push ( 'b' ) ; }
55
55
'\u{000c}' => { escaped. push ( '\\' ) ; escaped. push ( 'f' ) ; }
56
+ '\u{2028}' => { escaped. push_str ( "\\ u2028" ) ; }
57
+ '\u{2029}' => { escaped. push_str ( "\\ u2029" ) ; }
56
58
_ => escaped. push ( c) ,
57
59
}
58
60
}
@@ -65,14 +67,16 @@ pub (crate) fn escape_single_quoted(input: &str) -> String {
65
67
let mut escaped = String :: with_capacity ( input. len ( ) * 2 ) ;
66
68
for c in input. chars ( ) {
67
69
match c {
68
- '\'' => { escaped. push ( '\\' ) ; escaped. push ( '" ' ) ; }
70
+ '\'' => { escaped. push ( '\\' ) ; escaped. push ( '\' ' ) ; }
69
71
'\\' => { escaped. push ( '\\' ) ; escaped. push ( '\\' ) ; }
70
72
'\n' => { escaped. push ( '\\' ) ; escaped. push ( 'n' ) ; }
71
73
'\r' => { escaped. push ( '\\' ) ; escaped. push ( 'r' ) ; }
72
74
'\t' => { escaped. push ( '\\' ) ; escaped. push ( 't' ) ; }
73
75
'/' => { escaped. push ( '\\' ) ; escaped. push ( '/' ) ; }
74
76
'\u{0008}' => { escaped. push ( '\\' ) ; escaped. push ( 'b' ) ; }
75
77
'\u{000c}' => { escaped. push ( '\\' ) ; escaped. push ( 'f' ) ; }
78
+ '\u{2028}' => { escaped. push_str ( "\\ u2028" ) ; }
79
+ '\u{2029}' => { escaped. push_str ( "\\ u2029" ) ; }
76
80
_ => escaped. push ( c) ,
77
81
}
78
82
}
@@ -176,3 +180,151 @@ pub (crate) const MAX_DEPTH: usize = 2000;
176
180
177
181
#[ cfg( feature = "unlimited_depth" ) ]
178
182
pub ( 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