1
use ron::{
2
    error::{Position, Span, SpannedError},
3
    Error,
4
};
5
use serde::Deserialize;
6

            
7
#[derive(Debug, Deserialize, PartialEq)]
8
struct BytesStruct {
9
    small: Vec<u8>,
10
    #[serde(with = "serde_bytes")]
11
    large: Vec<u8>,
12
}
13

            
14
#[test]
15
4
fn v_9_deprecated_base64_bytes_support() {
16
    #![allow(deprecated)]
17

            
18
    // Requires padding of the base64 data
19
4
    assert_eq!(
20
4
        Ok(BytesStruct {
21
4
            small: vec![1, 2],
22
4
            large: vec![1, 2, 3, 4]
23
4
        }),
24
4
        ron::from_str("BytesStruct( small:[1, 2], large:\"AQIDBA==\" )"),
25
    );
26

            
27
    // Requires no padding of the base64 data
28
4
    assert_eq!(
29
4
        Ok(BytesStruct {
30
4
            small: vec![1, 2],
31
4
            large: vec![1, 2, 3, 4, 5, 6]
32
4
        }),
33
4
        ron::from_str("BytesStruct( small:[1, 2], large:r\"AQIDBAUG\" )"),
34
    );
35

            
36
    // Parsing an escaped byte string is also possible
37
4
    assert_eq!(
38
4
        Ok(BytesStruct {
39
4
            small: vec![1, 2],
40
4
            large: vec![1, 2, 3, 4, 5, 6]
41
4
        }),
42
4
        ron::from_str("BytesStruct( small:[1, 2], large:\"\\x41Q\\x49DBA\\x55G\" )"),
43
    );
44

            
45
    // Invalid base64
46
4
    assert_eq!(
47
        Err(SpannedError {
48
            code: Error::Base64Error(base64::DecodeError::InvalidByte(0, b'_')),
49
            span: Span {
50
                start: Position { line: 1, col: 35 },
51
                end: Position { line: 1, col: 40 }
52
            }
53
        }),
54
4
        ron::from_str::<BytesStruct>("BytesStruct( small:[1, 2], large:\"_+!!\" )"),
55
    );
56

            
57
    // Invalid last base64 symbol
58
4
    assert_eq!(
59
        Err(SpannedError {
60
            code: Error::Base64Error(base64::DecodeError::InvalidLastSymbol(1, b'x')),
61
            span: Span {
62
                start: Position { line: 1, col: 35 },
63
                end: Position { line: 1, col: 40 }
64
            }
65
        }),
66
4
        ron::from_str::<BytesStruct>("BytesStruct( small:[1, 2], large:\"/x==\" )"),
67
    );
68

            
69
    // Missing padding
70
4
    assert_eq!(
71
        Err(SpannedError {
72
            code: Error::Base64Error(base64::DecodeError::InvalidPadding),
73
            span: Span {
74
                start: Position { line: 1, col: 35 },
75
                end: Position { line: 1, col: 42 }
76
            }
77
        }),
78
4
        ron::from_str::<BytesStruct>("BytesStruct( small:[1, 2], large:\"AQIDBA\" )"),
79
    );
80

            
81
    // Too much padding
82
4
    assert_eq!(
83
        Err(SpannedError {
84
            code: Error::Base64Error(base64::DecodeError::InvalidByte(6, b'=')),
85
            span: Span {
86
                start: Position { line: 1, col: 35 },
87
                end: Position { line: 1, col: 45 }
88
            }
89
        }),
90
4
        ron::from_str::<BytesStruct>("BytesStruct( small:[1, 2], large:\"AQIDBA===\" )"),
91
    );
92
4
}
93

            
94
#[test]
95
4
fn rusty_byte_string() {
96
4
    assert_eq!(
97
4
        Ok(BytesStruct {
98
4
            small: vec![1, 2],
99
4
            large: vec![1, 2, 0, 4]
100
4
        }),
101
4
        ron::from_str("BytesStruct( small:[1, 2], large: b\"\\x01\\u{2}\\0\\x04\" )"),
102
    );
103

            
104
4
    assert_eq!(
105
4
        ron::from_str::<String>("\"Hello \\x01 \\u{2}!\"").unwrap(),
106
        "Hello \x01 \u{2}!",
107
    );
108
4
    assert_eq!(
109
4
        &*ron::from_str::<bytes::Bytes>("b\"Hello \\x01 \\u{2}!\"").unwrap(),
110
        b"Hello \x01 \x02!",
111
    );
112

            
113
4
    rusty_byte_string_roundtrip(b"hello", "b\"hello\"", "b\"hello\"");
114
4
    rusty_byte_string_roundtrip(b"\"", "b\"\\\"\"", "br#\"\"\"#");
115
4
    rusty_byte_string_roundtrip(b"\"#", "b\"\\\"#\"", "br##\"\"#\"##");
116
4
    rusty_byte_string_roundtrip(b"\n", "b\"\\n\"", "b\"\n\"");
117

            
118
4
    assert_eq!(
119
4
        ron::from_str::<bytes::Bytes>("b\"\\xf\"").unwrap_err(),
120
        SpannedError {
121
            code: Error::InvalidEscape("Non-hex digit found"),
122
            span: Span {
123
                start: Position { line: 1, col: 3 },
124
                end: Position { line: 1, col: 7 },
125
            }
126
        },
127
    );
128
4
    assert_eq!(
129
4
        ron::from_str::<bytes::Bytes>("b\"\\xf🦀\"").unwrap_err(),
130
        SpannedError {
131
            code: Error::InvalidEscape("Non-hex digit found"),
132
            span: Span {
133
                start: Position { line: 1, col: 3 },
134
                end: Position { line: 1, col: 7 },
135
            }
136
        },
137
    );
138
4
    let err = ron::from_str::<bytes::Bytes>("br#q\"").unwrap_err();
139
4
    assert_eq!(
140
        err,
141
        SpannedError {
142
            code: Error::ExpectedByteString,
143
            span: Span {
144
                start: Position { line: 1, col: 3 },
145
                end: Position { line: 1, col: 4 },
146
            }
147
        },
148
    );
149
4
    assert_eq!(format!("{}", err.code), "Expected byte string",);
150
4
    assert_eq!(
151
4
        ron::from_str::<bytes::Bytes>("br#\"q").unwrap_err(),
152
        SpannedError {
153
            code: Error::ExpectedStringEnd,
154
            span: Span {
155
                start: Position { line: 1, col: 4 },
156
                end: Position { line: 1, col: 5 },
157
            }
158
        },
159
    );
160
4
    assert_eq!(
161
4
        ron::from_str::<String>("r#q\"").unwrap_err(),
162
        SpannedError {
163
            code: Error::ExpectedString,
164
            span: Span {
165
                start: Position { line: 1, col: 2 },
166
                end: Position { line: 1, col: 3 },
167
            }
168
        },
169
    );
170
4
    assert_eq!(
171
4
        ron::from_str::<String>("r#\"q").unwrap_err(),
172
        SpannedError {
173
            code: Error::ExpectedStringEnd,
174
            span: Span {
175
                start: Position { line: 1, col: 3 },
176
                end: Position { line: 1, col: 4 },
177
            }
178
        },
179
    );
180
4
}
181

            
182
16
fn rusty_byte_string_roundtrip(bytes: &[u8], ron: &str, ron_raw: &str) {
183
16
    let ser_list = ron::to_string(bytes).unwrap();
184
16
    let de_list: Vec<u8> = ron::from_str(&ser_list).unwrap();
185
16
    assert_eq!(de_list, bytes);
186

            
187
16
    let ser = ron::to_string(&bytes::Bytes::copy_from_slice(bytes)).unwrap();
188
16
    assert_eq!(ser, ron);
189

            
190
16
    let ser_non_raw = ron::ser::to_string_pretty(
191
16
        &bytes::Bytes::copy_from_slice(bytes),
192
16
        ron::ser::PrettyConfig::default(),
193
    )
194
16
    .unwrap();
195
16
    assert_eq!(ser_non_raw, ron);
196

            
197
16
    let ser_raw = ron::ser::to_string_pretty(
198
16
        &bytes::Bytes::copy_from_slice(bytes),
199
16
        ron::ser::PrettyConfig::default().escape_strings(false),
200
    )
201
16
    .unwrap();
202
16
    assert_eq!(ser_raw, ron_raw);
203

            
204
16
    let de: bytes::Bytes = ron::from_str(&ser).unwrap();
205
16
    assert_eq!(de, bytes);
206

            
207
16
    let de_raw: bytes::Bytes = ron::from_str(&ser_raw).unwrap();
208
16
    assert_eq!(de_raw, bytes);
209
16
}
210

            
211
#[test]
212
4
fn fuzzer_failures() {
213
4
    assert_eq!(
214
4
        ron::to_string(&bytes::Bytes::copy_from_slice(&[
215
4
            123, 0, 0, 0, 0, 214, 214, 214, 214, 214
216
4
        ]))
217
4
        .unwrap(),
218
        r#"b"{\x00\x00\x00\x00\xd6\xd6\xd6\xd6\xd6""#
219
    );
220
    // Need to fall back to escaping so no invalid UTF-8 is produced
221
4
    assert_eq!(
222
4
        ron::ser::to_string_pretty(
223
4
            &bytes::Bytes::copy_from_slice(&[123, 0, 0, 0, 0, 214, 214, 214, 214, 214]),
224
4
            ron::ser::PrettyConfig::default().escape_strings(false)
225
        )
226
4
        .unwrap(),
227
        r#"b"{\x00\x00\x00\x00\xd6\xd6\xd6\xd6\xd6""#
228
    );
229

            
230
4
    assert_eq!(
231
4
        ron::to_string(&bytes::Bytes::copy_from_slice(&[123, 0, 0, 0, 0])).unwrap(),
232
        r#"b"{\x00\x00\x00\x00""#
233
    );
234
4
    assert_eq!(
235
4
        ron::ser::to_string_pretty(
236
4
            &bytes::Bytes::copy_from_slice(&[123, 0, 0, 0, 0]),
237
4
            ron::ser::PrettyConfig::default().escape_strings(false)
238
        )
239
4
        .unwrap(),
240
        "b\"{\x00\x00\x00\x00\""
241
    );
242

            
243
    // `br#` should be parsed as the start of a byte string, not the identifier `br` and a `#`
244
4
    assert_eq!(
245
4
        ron::from_str(r##"br#"""#"##),
246
4
        Ok(ron::Value::Bytes(vec![34]))
247
    );
248
4
    assert_eq!(
249
4
        ron::from_str(r##"{"error": br#"""#}"##),
250
4
        Ok(ron::Value::Map(
251
4
            [(
252
4
                ron::Value::String(String::from("error")),
253
4
                ron::Value::Bytes(vec![34])
254
4
            )]
255
4
            .into_iter()
256
4
            .collect()
257
4
        ))
258
    );
259
4
    assert_eq!(
260
4
        ron::from_str(
261
4
            r##"#![enable(unwrap_newtypes)]
262
4
    #![enable(unwrap_variant_newtypes)]
263
4
    Some({"error": br#"""#})
264
4
    "##
265
        ),
266
4
        Ok(ron::Value::Option(Some(Box::new(ron::Value::Map(
267
4
            [(
268
4
                ron::Value::String(String::from("error")),
269
4
                ron::Value::Bytes(vec![34])
270
4
            )]
271
4
            .into_iter()
272
4
            .collect()
273
4
        )))))
274
    );
275

            
276
    // `br"` should be parsed as the start of a byte string, not the identifier `br` and a `"`
277
4
    assert_eq!(ron::from_str(r#"br"""#), Ok(ron::Value::Bytes(vec![])));
278
4
    assert_eq!(
279
4
        ron::from_str(r#"{"error": br""}"#),
280
4
        Ok(ron::Value::Map(
281
4
            [(
282
4
                ron::Value::String(String::from("error")),
283
4
                ron::Value::Bytes(vec![])
284
4
            )]
285
4
            .into_iter()
286
4
            .collect()
287
4
        ))
288
    );
289
4
    assert_eq!(
290
4
        ron::from_str(
291
4
            r#"#![enable(unwrap_newtypes)]
292
4
    #![enable(unwrap_variant_newtypes)]
293
4
    Some({"error": br""})
294
4
    "#
295
        ),
296
4
        Ok(ron::Value::Option(Some(Box::new(ron::Value::Map(
297
4
            [(
298
4
                ron::Value::String(String::from("error")),
299
4
                ron::Value::Bytes(vec![])
300
4
            )]
301
4
            .into_iter()
302
4
            .collect()
303
4
        )))))
304
    );
305

            
306
    // Test that the struct type check for newtype variant unwrapping does
307
    //  not enter inside a byte string to find a bad comment start
308
4
    assert_eq!(
309
4
        ron::from_str::<Option<ron::Value>>(
310
4
            r#"#![enable(unwrap_variant_newtypes)] Some(b"\xff/not a comment")"#
311
        )
312
4
        .unwrap(),
313
4
        Some(ron::Value::Bytes(b"\xff/not a comment".to_vec()))
314
    );
315

            
316
    // `b'` should be parsed as the start of a byte literal, not the identifier `b` and a `'`
317
4
    assert_eq!(
318
4
        ron::from_str(r"b'\xff'"),
319
        Ok(ron::Value::Number(ron::value::Number::U8(b'\xff')))
320
    );
321

            
322
    // `b`, `br`, `bq`, and `brq` should all be parsed as identifiers
323
16
    for id in ["b", "br", "bq", "brq"] {
324
16
        assert_eq!(ron::from_str(id), Ok(ron::Value::Unit));
325
    }
326
4
}
327

            
328
#[test]
329
4
fn serialize_backslash_byte_string() {
330
4
    check_roundtrip('\\', r"'\\'", r"'\\'");
331
4
    check_roundtrip(
332
4
        bytes::Bytes::copy_from_slice(b"\\"),
333
4
        r#"b"\\""#,
334
4
        "br#\"\\\"#",
335
    );
336
4
}
337

            
338
8
fn check_roundtrip<
339
8
    T: PartialEq + core::fmt::Debug + serde::Serialize + serde::de::DeserializeOwned,
340
8
>(
341
8
    val: T,
342
8
    cmp: &str,
343
8
    cmp_raw: &str,
344
8
) {
345
8
    let ron = ron::to_string(&val).unwrap();
346
8
    assert_eq!(ron, cmp);
347

            
348
8
    let ron_escaped =
349
8
        ron::ser::to_string_pretty(&val, ron::ser::PrettyConfig::default().escape_strings(true))
350
8
            .unwrap();
351
8
    assert_eq!(ron_escaped, cmp);
352

            
353
8
    let ron_raw = ron::ser::to_string_pretty(
354
8
        &val,
355
8
        ron::ser::PrettyConfig::default().escape_strings(false),
356
    )
357
8
    .unwrap();
358
8
    assert_eq!(ron_raw, cmp_raw);
359

            
360
8
    let de = ron::from_str::<T>(&ron).unwrap();
361
8
    assert_eq!(de, val);
362

            
363
8
    let de_raw = ron::from_str::<T>(&ron_raw).unwrap();
364
8
    assert_eq!(de_raw, val);
365
8
}
366

            
367
#[test]
368
4
fn test_weird_escapes() {
369
4
    assert_eq!(
370
4
        ron::from_str::<String>(r#""\u{1F980}""#),
371
4
        Ok(String::from("\u{1F980}"))
372
    );
373
4
    assert_eq!(
374
4
        ron::from_str::<bytes::Bytes>(r#"b"\xf0\x9f\xa6\x80""#),
375
4
        Ok(bytes::Bytes::copy_from_slice("\u{1F980}".as_bytes()))
376
    );
377
4
    assert_eq!(
378
4
        ron::from_str::<String>(r#""\xf0\x9f\xa6\x80""#),
379
4
        Ok(String::from("\u{1F980}"))
380
    );
381
4
    assert_eq!(
382
4
        ron::from_str::<String>(r#""\xf0""#),
383
        Err(SpannedError {
384
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
385
            span: Span {
386
                start: Position { line: 1, col: 2 },
387
                end: Position { line: 1, col: 6 }
388
            }
389
        })
390
    );
391
4
    assert_eq!(
392
4
        ron::from_str::<String>(r#""\xf0\x9f""#),
393
        Err(SpannedError {
394
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
395
            span: Span {
396
                start: Position { line: 1, col: 6 },
397
                end: Position { line: 1, col: 10 }
398
            }
399
        })
400
    );
401
4
    assert_eq!(
402
4
        ron::from_str::<String>(r#""\xf0\x9f\x40""#),
403
        Err(SpannedError {
404
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
405
            span: Span {
406
                start: Position { line: 1, col: 10 },
407
                end: Position { line: 1, col: 14 }
408
            }
409
        })
410
    );
411
4
    assert_eq!(
412
4
        ron::from_str::<String>(r#""\xf0\x9f\xa6""#),
413
        Err(SpannedError {
414
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
415
            span: Span {
416
                start: Position { line: 1, col: 10 },
417
                end: Position { line: 1, col: 14 }
418
            }
419
        })
420
    );
421
4
    assert_eq!(
422
4
        ron::from_str::<String>(r#""\xff\xff\xff\xff""#),
423
        Err(SpannedError {
424
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
425
            span: Span {
426
                start: Position { line: 1, col: 14 },
427
                end: Position { line: 1, col: 18 }
428
            }
429
        })
430
    );
431

            
432
4
    assert_eq!(ron::from_str::<char>(r"'\u{1F980}'"), Ok('\u{1F980}'));
433
4
    assert_eq!(
434
4
        ron::from_str::<char>(r"'\xf0\x9f\xa6\x80'"),
435
        Err(SpannedError {
436
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
437
            span: Span {
438
                start: Position { line: 1, col: 1 },
439
                end: Position { line: 1, col: 6 }
440
            }
441
        })
442
    );
443
4
}
444

            
445
#[test]
446
4
fn byte_literal() {
447
4
    assert_eq!(
448
4
        ron::from_str("b'\0'"),
449
        Ok(ron::Value::Number(ron::value::Number::U8(0)))
450
    );
451
4
    assert_eq!(
452
4
        ron::from_str("b'\\0'"),
453
        Ok(ron::Value::Number(ron::value::Number::U8(0)))
454
    );
455

            
456
1028
    for b in 0..=255_u8 {
457
1024
        let default = std::ascii::escape_default(b)
458
1024
            .map(char::from)
459
1024
            .collect::<String>();
460
1024
        let lower = format!(r"\x{:02x}", b);
461
1024
        let upper = format!(r"\x{:02X}", b);
462

            
463
1024
        assert_eq!(
464
1024
            ron::from_str(&format!("b'{}'", default)),
465
1024
            Ok(ron::Value::Number(ron::value::Number::U8(b)))
466
        );
467
1024
        assert_eq!(
468
1024
            ron::from_str(&format!("b'{}'", lower)),
469
1024
            Ok(ron::Value::Number(ron::value::Number::U8(b)))
470
        );
471
1024
        assert_eq!(
472
1024
            ron::from_str(&format!("b'{}'", upper)),
473
1024
            Ok(ron::Value::Number(ron::value::Number::U8(b)))
474
        );
475
    }
476

            
477
4
    assert_eq!(
478
4
        ron::from_str::<u8>(r#"b'\u{0}'"#),
479
        Err(SpannedError {
480
            code: Error::InvalidEscape("Unexpected Unicode escape in byte literal"),
481
            span: Span {
482
                start: Position { line: 1, col: 7 },
483
                end: Position { line: 1, col: 8 },
484
            }
485
        })
486
    );
487

            
488
4
    let err = ron::from_str::<u8>(r#"b'🦀'"#).unwrap_err();
489
4
    assert_eq!(
490
        err,
491
        SpannedError {
492
            code: Error::ExpectedByteLiteral,
493
            span: Span {
494
                start: Position { line: 1, col: 1 },
495
                end: Position { line: 1, col: 4 },
496
            }
497
        }
498
    );
499
4
    assert_eq!(format!("{}", err.code), "Expected byte literal");
500

            
501
4
    assert_eq!(
502
4
        ron::from_str::<u8>(r#"b'qq'"#).unwrap_err(),
503
        SpannedError {
504
            code: Error::ExpectedByteLiteral,
505
            span: Span {
506
                start: Position { line: 1, col: 1 },
507
                end: Position { line: 1, col: 4 },
508
            }
509
        }
510
    );
511

            
512
4
    assert_eq!(
513
4
        ron::from_str::<i8>(r#"b'9'"#),
514
4
        Err(SpannedError {
515
4
            code: Error::InvalidValueForType {
516
4
                expected: String::from("an 8-bit signed integer"),
517
4
                found: String::from(r#"b'9'"#)
518
4
            },
519
4
            span: Span {
520
4
                start: Position { line: 1, col: 4 },
521
4
                end: Position { line: 1, col: 5 },
522
4
            }
523
4
        })
524
    );
525
4
}
526

            
527
#[test]
528
4
fn invalid_identifier() {
529
    #[allow(dead_code)]
530
    #[derive(Debug, Deserialize)] // GRCOV_EXCL_LINE
531
    struct Test {
532
        a: i32,
533
    }
534

            
535
28
    for id in ["b\"", "b'", "br#", "br\"", "r\"", "r#\"", "r##"] {
536
28
        assert_eq!(
537
28
            ron::from_str::<Test>(&format!("({}: 42)", id)).unwrap_err(),
538
            SpannedError {
539
                code: Error::ExpectedIdentifier,
540
                span: Span {
541
                    start: Position { line: 1, col: 2 },
542
                    end: Position { line: 1, col: 2 },
543
                }
544
            }
545
        );
546
    }
547
4
}