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

            
7
128
#[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
4
    #![allow(deprecated)]
17
4

            
18
4
    // 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
4
    );
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
4
    );
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
4
    );
44

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

            
54
    // Invalid last base64 symbol
55
4
    assert_eq!(
56
4
        Err(SpannedError {
57
4
            code: Error::Base64Error(base64::DecodeError::InvalidLastSymbol(1, b'x')),
58
4
            position: Position { line: 1, col: 40 }
59
4
        }),
60
4
        ron::from_str::<BytesStruct>("BytesStruct( small:[1, 2], large:\"/x==\" )"),
61
4
    );
62

            
63
    // Missing padding
64
4
    assert_eq!(
65
4
        Err(SpannedError {
66
4
            code: Error::Base64Error(base64::DecodeError::InvalidPadding),
67
4
            position: Position { line: 1, col: 42 }
68
4
        }),
69
4
        ron::from_str::<BytesStruct>("BytesStruct( small:[1, 2], large:\"AQIDBA\" )"),
70
4
    );
71

            
72
    // Too much padding
73
4
    assert_eq!(
74
4
        Err(SpannedError {
75
4
            code: Error::Base64Error(base64::DecodeError::InvalidByte(6, b'=')),
76
4
            position: Position { line: 1, col: 45 }
77
4
        }),
78
4
        ron::from_str::<BytesStruct>("BytesStruct( small:[1, 2], large:\"AQIDBA===\" )"),
79
4
    );
80
4
}
81

            
82
#[test]
83
4
fn rusty_byte_string() {
84
4
    assert_eq!(
85
4
        Ok(BytesStruct {
86
4
            small: vec![1, 2],
87
4
            large: vec![1, 2, 0, 4]
88
4
        }),
89
4
        ron::from_str("BytesStruct( small:[1, 2], large: b\"\\x01\\u{2}\\0\\x04\" )"),
90
4
    );
91

            
92
4
    assert_eq!(
93
4
        ron::from_str::<String>("\"Hello \\x01 \\u{2}!\"").unwrap(),
94
4
        "Hello \x01 \u{2}!",
95
4
    );
96
4
    assert_eq!(
97
4
        &*ron::from_str::<bytes::Bytes>("b\"Hello \\x01 \\u{2}!\"").unwrap(),
98
4
        b"Hello \x01 \x02!",
99
4
    );
100

            
101
4
    rusty_byte_string_roundtrip(b"hello", "b\"hello\"", "b\"hello\"");
102
4
    rusty_byte_string_roundtrip(b"\"", "b\"\\\"\"", "br#\"\"\"#");
103
4
    rusty_byte_string_roundtrip(b"\"#", "b\"\\\"#\"", "br##\"\"#\"##");
104
4
    rusty_byte_string_roundtrip(b"\n", "b\"\\n\"", "b\"\n\"");
105
4

            
106
4
    assert_eq!(
107
4
        ron::from_str::<bytes::Bytes>("b\"\\xf\"").unwrap_err(),
108
4
        SpannedError {
109
4
            code: Error::InvalidEscape("Non-hex digit found"),
110
4
            position: Position { line: 1, col: 7 },
111
4
        },
112
4
    );
113
4
    assert_eq!(
114
4
        ron::from_str::<bytes::Bytes>("b\"\\xf🦀\"").unwrap_err(),
115
4
        SpannedError {
116
4
            code: Error::InvalidEscape("Non-hex digit found"),
117
4
            position: Position { line: 1, col: 7 },
118
4
        },
119
4
    );
120
4
    let err = ron::from_str::<bytes::Bytes>("br#q\"").unwrap_err();
121
4
    assert_eq!(
122
4
        err,
123
4
        SpannedError {
124
4
            code: Error::ExpectedByteString,
125
4
            position: Position { line: 1, col: 4 },
126
4
        },
127
4
    );
128
4
    assert_eq!(format!("{}", err.code), "Expected byte string",);
129
4
    assert_eq!(
130
4
        ron::from_str::<bytes::Bytes>("br#\"q").unwrap_err(),
131
4
        SpannedError {
132
4
            code: Error::ExpectedStringEnd,
133
4
            position: Position { line: 1, col: 5 },
134
4
        },
135
4
    );
136
4
    assert_eq!(
137
4
        ron::from_str::<String>("r#q\"").unwrap_err(),
138
4
        SpannedError {
139
4
            code: Error::ExpectedString,
140
4
            position: Position { line: 1, col: 3 },
141
4
        },
142
4
    );
143
4
    assert_eq!(
144
4
        ron::from_str::<String>("r#\"q").unwrap_err(),
145
4
        SpannedError {
146
4
            code: Error::ExpectedStringEnd,
147
4
            position: Position { line: 1, col: 4 },
148
4
        },
149
4
    );
150
4
}
151

            
152
16
fn rusty_byte_string_roundtrip(bytes: &[u8], ron: &str, ron_raw: &str) {
153
16
    let ser_list = ron::to_string(bytes).unwrap();
154
16
    let de_list: Vec<u8> = ron::from_str(&ser_list).unwrap();
155
16
    assert_eq!(de_list, bytes);
156

            
157
16
    let ser = ron::to_string(&bytes::Bytes::copy_from_slice(bytes)).unwrap();
158
16
    assert_eq!(ser, ron);
159

            
160
16
    let ser_non_raw = ron::ser::to_string_pretty(
161
16
        &bytes::Bytes::copy_from_slice(bytes),
162
16
        ron::ser::PrettyConfig::default(),
163
16
    )
164
16
    .unwrap();
165
16
    assert_eq!(ser_non_raw, ron);
166

            
167
16
    let ser_raw = ron::ser::to_string_pretty(
168
16
        &bytes::Bytes::copy_from_slice(bytes),
169
16
        ron::ser::PrettyConfig::default().escape_strings(false),
170
16
    )
171
16
    .unwrap();
172
16
    assert_eq!(ser_raw, ron_raw);
173

            
174
16
    let de: bytes::Bytes = ron::from_str(&ser).unwrap();
175
16
    assert_eq!(de, bytes);
176

            
177
16
    let de_raw: bytes::Bytes = ron::from_str(&ser_raw).unwrap();
178
16
    assert_eq!(de_raw, bytes);
179
16
}
180

            
181
#[test]
182
4
fn fuzzer_failures() {
183
4
    assert_eq!(
184
4
        ron::to_string(&bytes::Bytes::copy_from_slice(&[
185
4
            123, 0, 0, 0, 0, 214, 214, 214, 214, 214
186
4
        ]))
187
4
        .unwrap(),
188
4
        r#"b"{\x00\x00\x00\x00\xd6\xd6\xd6\xd6\xd6""#
189
4
    );
190
    // Need to fall back to escaping so no invalid UTF-8 is produced
191
4
    assert_eq!(
192
4
        ron::ser::to_string_pretty(
193
4
            &bytes::Bytes::copy_from_slice(&[123, 0, 0, 0, 0, 214, 214, 214, 214, 214]),
194
4
            ron::ser::PrettyConfig::default().escape_strings(false)
195
4
        )
196
4
        .unwrap(),
197
4
        r#"b"{\x00\x00\x00\x00\xd6\xd6\xd6\xd6\xd6""#
198
4
    );
199

            
200
4
    assert_eq!(
201
4
        ron::to_string(&bytes::Bytes::copy_from_slice(&[123, 0, 0, 0, 0])).unwrap(),
202
4
        r#"b"{\x00\x00\x00\x00""#
203
4
    );
204
4
    assert_eq!(
205
4
        ron::ser::to_string_pretty(
206
4
            &bytes::Bytes::copy_from_slice(&[123, 0, 0, 0, 0]),
207
4
            ron::ser::PrettyConfig::default().escape_strings(false)
208
4
        )
209
4
        .unwrap(),
210
4
        "b\"{\x00\x00\x00\x00\""
211
4
    );
212

            
213
    // `br#` should be parsed as the start of a byte string, not the identifier `br` and a `#`
214
4
    assert_eq!(
215
4
        ron::from_str(r##"br#"""#"##),
216
4
        Ok(ron::Value::Bytes(vec![34]))
217
4
    );
218
4
    assert_eq!(
219
4
        ron::from_str(r##"{"error": br#"""#}"##),
220
4
        Ok(ron::Value::Map(
221
4
            [(
222
4
                ron::Value::String(String::from("error")),
223
4
                ron::Value::Bytes(vec![34])
224
4
            )]
225
4
            .into_iter()
226
4
            .collect()
227
4
        ))
228
4
    );
229
4
    assert_eq!(
230
4
        ron::from_str(
231
4
            r##"#![enable(unwrap_newtypes)]
232
4
    #![enable(unwrap_variant_newtypes)]
233
4
    Some({"error": br#"""#})
234
4
    "##
235
4
        ),
236
4
        Ok(ron::Value::Option(Some(Box::new(ron::Value::Map(
237
4
            [(
238
4
                ron::Value::String(String::from("error")),
239
4
                ron::Value::Bytes(vec![34])
240
4
            )]
241
4
            .into_iter()
242
4
            .collect()
243
4
        )))))
244
4
    );
245

            
246
    // `br"` should be parsed as the start of a byte string, not the identifier `br` and a `"`
247
4
    assert_eq!(ron::from_str(r#"br"""#), Ok(ron::Value::Bytes(vec![])));
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![])
254
4
            )]
255
4
            .into_iter()
256
4
            .collect()
257
4
        ))
258
4
    );
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
4
        ),
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![])
270
4
            )]
271
4
            .into_iter()
272
4
            .collect()
273
4
        )))))
274
4
    );
275

            
276
    // Test that the struct type check for newtype variant unwrapping does
277
    //  not enter inside a byte string to find a bad comment start
278
4
    assert_eq!(
279
4
        ron::from_str::<Option<ron::Value>>(
280
4
            r#"#![enable(unwrap_variant_newtypes)] Some(b"\xff/not a comment")"#
281
4
        )
282
4
        .unwrap(),
283
4
        Some(ron::Value::Bytes(b"\xff/not a comment".to_vec()))
284
4
    );
285

            
286
    // `b'` should be parsed as the start of a byte literal, not the identifier `b` and a `'`
287
4
    assert_eq!(
288
4
        ron::from_str(r"b'\xff'"),
289
4
        Ok(ron::Value::Number(ron::value::Number::U8(b'\xff')))
290
4
    );
291

            
292
    // `b`, `br`, `bq`, and `brq` should all be parsed as identifiers
293
16
    for id in ["b", "br", "bq", "brq"] {
294
16
        assert_eq!(ron::from_str(id), Ok(ron::Value::Unit));
295
    }
296
4
}
297

            
298
#[test]
299
4
fn serialize_backslash_byte_string() {
300
4
    check_roundtrip('\\', r"'\\'", r"'\\'");
301
4
    check_roundtrip(
302
4
        bytes::Bytes::copy_from_slice(b"\\"),
303
4
        r#"b"\\""#,
304
4
        "br#\"\\\"#",
305
4
    );
306
4
}
307

            
308
8
fn check_roundtrip<
309
8
    T: PartialEq + std::fmt::Debug + serde::Serialize + serde::de::DeserializeOwned,
310
8
>(
311
8
    val: T,
312
8
    cmp: &str,
313
8
    cmp_raw: &str,
314
8
) {
315
8
    let ron = ron::to_string(&val).unwrap();
316
8
    assert_eq!(ron, cmp);
317

            
318
8
    let ron_escaped =
319
8
        ron::ser::to_string_pretty(&val, ron::ser::PrettyConfig::default().escape_strings(true))
320
8
            .unwrap();
321
8
    assert_eq!(ron_escaped, cmp);
322

            
323
8
    let ron_raw = ron::ser::to_string_pretty(
324
8
        &val,
325
8
        ron::ser::PrettyConfig::default().escape_strings(false),
326
8
    )
327
8
    .unwrap();
328
8
    assert_eq!(ron_raw, cmp_raw);
329

            
330
8
    let de = ron::from_str::<T>(&ron).unwrap();
331
8
    assert_eq!(de, val);
332

            
333
8
    let de_raw = ron::from_str::<T>(&ron_raw).unwrap();
334
8
    assert_eq!(de_raw, val);
335
8
}
336

            
337
#[test]
338
4
fn test_weird_escapes() {
339
4
    assert_eq!(
340
4
        ron::from_str::<String>(r#""\u{1F980}""#),
341
4
        Ok(String::from("\u{1F980}"))
342
4
    );
343
4
    assert_eq!(
344
4
        ron::from_str::<bytes::Bytes>(r#"b"\xf0\x9f\xa6\x80""#),
345
4
        Ok(bytes::Bytes::copy_from_slice("\u{1F980}".as_bytes()))
346
4
    );
347
4
    assert_eq!(
348
4
        ron::from_str::<String>(r#""\xf0\x9f\xa6\x80""#),
349
4
        Ok(String::from("\u{1F980}"))
350
4
    );
351
4
    assert_eq!(
352
4
        ron::from_str::<String>(r#""\xf0""#),
353
4
        Err(SpannedError {
354
4
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
355
4
            position: Position { line: 1, col: 6 }
356
4
        })
357
4
    );
358
4
    assert_eq!(
359
4
        ron::from_str::<String>(r#""\xf0\x9f""#),
360
4
        Err(SpannedError {
361
4
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
362
4
            position: Position { line: 1, col: 10 }
363
4
        })
364
4
    );
365
4
    assert_eq!(
366
4
        ron::from_str::<String>(r#""\xf0\x9f\x40""#),
367
4
        Err(SpannedError {
368
4
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
369
4
            position: Position { line: 1, col: 14 }
370
4
        })
371
4
    );
372
4
    assert_eq!(
373
4
        ron::from_str::<String>(r#""\xf0\x9f\xa6""#),
374
4
        Err(SpannedError {
375
4
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
376
4
            position: Position { line: 1, col: 14 }
377
4
        })
378
4
    );
379
4
    assert_eq!(
380
4
        ron::from_str::<String>(r#""\xff\xff\xff\xff""#),
381
4
        Err(SpannedError {
382
4
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
383
4
            position: Position { line: 1, col: 18 }
384
4
        })
385
4
    );
386

            
387
4
    assert_eq!(ron::from_str::<char>(r"'\u{1F980}'"), Ok('\u{1F980}'));
388
4
    assert_eq!(
389
4
        ron::from_str::<char>(r"'\xf0\x9f\xa6\x80'"),
390
4
        Err(SpannedError {
391
4
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
392
4
            position: Position { line: 1, col: 6 }
393
4
        })
394
4
    );
395
4
}
396

            
397
#[test]
398
4
fn byte_literal() {
399
4
    assert_eq!(
400
4
        ron::from_str("b'\0'"),
401
4
        Ok(ron::Value::Number(ron::value::Number::U8(0)))
402
4
    );
403
4
    assert_eq!(
404
4
        ron::from_str("b'\\0'"),
405
4
        Ok(ron::Value::Number(ron::value::Number::U8(0)))
406
4
    );
407

            
408
1028
    for b in 0..=255_u8 {
409
1024
        let default = std::ascii::escape_default(b)
410
1024
            .map(char::from)
411
1024
            .collect::<String>();
412
1024
        let lower = format!(r"\x{:02x}", b);
413
1024
        let upper = format!(r"\x{:02X}", b);
414
1024

            
415
1024
        assert_eq!(
416
1024
            ron::from_str(&format!("b'{}'", default)),
417
1024
            Ok(ron::Value::Number(ron::value::Number::U8(b)))
418
1024
        );
419
1024
        assert_eq!(
420
1024
            ron::from_str(&format!("b'{}'", lower)),
421
1024
            Ok(ron::Value::Number(ron::value::Number::U8(b)))
422
1024
        );
423
1024
        assert_eq!(
424
1024
            ron::from_str(&format!("b'{}'", upper)),
425
1024
            Ok(ron::Value::Number(ron::value::Number::U8(b)))
426
1024
        );
427
    }
428

            
429
4
    assert_eq!(
430
4
        ron::from_str::<u8>(r#"b'\u{0}'"#),
431
4
        Err(SpannedError {
432
4
            code: Error::InvalidEscape("Unexpected Unicode escape in byte literal"),
433
4
            position: Position { line: 1, col: 8 },
434
4
        })
435
4
    );
436

            
437
4
    let err = ron::from_str::<u8>(r#"b'🦀'"#).unwrap_err();
438
4
    assert_eq!(
439
4
        err,
440
4
        SpannedError {
441
4
            code: Error::ExpectedByteLiteral,
442
4
            position: Position { line: 1, col: 4 },
443
4
        }
444
4
    );
445
4
    assert_eq!(format!("{}", err.code), "Expected byte literal");
446

            
447
4
    assert_eq!(
448
4
        ron::from_str::<u8>(r#"b'qq'"#).unwrap_err(),
449
4
        SpannedError {
450
4
            code: Error::ExpectedByteLiteral,
451
4
            position: Position { line: 1, col: 4 },
452
4
        }
453
4
    );
454

            
455
4
    assert_eq!(
456
4
        ron::from_str::<i8>(r#"b'9'"#),
457
4
        Err(SpannedError {
458
4
            code: Error::InvalidValueForType {
459
4
                expected: String::from("an 8-bit signed integer"),
460
4
                found: String::from(r#"b'9'"#)
461
4
            },
462
4
            position: Position { line: 1, col: 5 },
463
4
        })
464
4
    );
465
4
}
466

            
467
#[test]
468
4
fn invalid_identifier() {
469
    #[allow(dead_code)]
470
    #[derive(Debug, Deserialize)] // GRCOV_EXCL_LINE
471
    struct Test {
472
        a: i32,
473
    }
474

            
475
28
    for id in ["b\"", "b'", "br#", "br\"", "r\"", "r#\"", "r##"] {
476
28
        assert_eq!(
477
28
            ron::from_str::<Test>(&format!("({}: 42)", id)).unwrap_err(),
478
28
            SpannedError {
479
28
                code: Error::ExpectedIdentifier,
480
28
                position: Position { line: 1, col: 2 },
481
28
            }
482
28
        );
483
    }
484
4
}