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 rusty_byte_string() {
16
4
    assert_eq!(
17
4
        Ok(BytesStruct {
18
4
            small: vec![1, 2],
19
4
            large: vec![1, 2, 0, 4]
20
4
        }),
21
4
        ron::from_str("BytesStruct( small:[1, 2], large: b\"\\x01\\u{2}\\0\\x04\" )"),
22
    );
23

            
24
4
    assert_eq!(
25
4
        ron::from_str::<String>("\"Hello \\x01 \\u{2}!\"").unwrap(),
26
        "Hello \x01 \u{2}!",
27
    );
28
4
    assert_eq!(
29
4
        &*ron::from_str::<bytes::Bytes>("b\"Hello \\x01 \\u{2}!\"").unwrap(),
30
        b"Hello \x01 \x02!",
31
    );
32

            
33
4
    rusty_byte_string_roundtrip(b"hello", "b\"hello\"", "b\"hello\"");
34
4
    rusty_byte_string_roundtrip(b"\"", "b\"\\\"\"", "br#\"\"\"#");
35
4
    rusty_byte_string_roundtrip(b"\"#", "b\"\\\"#\"", "br##\"\"#\"##");
36
4
    rusty_byte_string_roundtrip(b"\n", "b\"\\n\"", "b\"\n\"");
37

            
38
4
    assert_eq!(
39
4
        ron::from_str::<bytes::Bytes>("b\"\\xf\"").unwrap_err(),
40
        SpannedError {
41
            code: Error::InvalidEscape("Non-hex digit found"),
42
            span: Span {
43
                start: Position { line: 1, col: 3 },
44
                end: Position { line: 1, col: 7 },
45
            }
46
        },
47
    );
48
4
    assert_eq!(
49
4
        ron::from_str::<bytes::Bytes>("b\"\\xf🦀\"").unwrap_err(),
50
        SpannedError {
51
            code: Error::InvalidEscape("Non-hex digit found"),
52
            span: Span {
53
                start: Position { line: 1, col: 3 },
54
                end: Position { line: 1, col: 7 },
55
            }
56
        },
57
    );
58
4
    let err = ron::from_str::<bytes::Bytes>("br#q\"").unwrap_err();
59
4
    assert_eq!(
60
        err,
61
        SpannedError {
62
            code: Error::ExpectedByteString,
63
            span: Span {
64
                start: Position { line: 1, col: 3 },
65
                end: Position { line: 1, col: 4 },
66
            }
67
        },
68
    );
69
4
    assert_eq!(format!("{}", err.code), "Expected byte string",);
70
4
    assert_eq!(
71
4
        ron::from_str::<bytes::Bytes>("br#\"q").unwrap_err(),
72
        SpannedError {
73
            code: Error::ExpectedStringEnd,
74
            span: Span {
75
                start: Position { line: 1, col: 4 },
76
                end: Position { line: 1, col: 5 },
77
            }
78
        },
79
    );
80
4
    assert_eq!(
81
4
        ron::from_str::<String>("r#q\"").unwrap_err(),
82
        SpannedError {
83
            code: Error::ExpectedString,
84
            span: Span {
85
                start: Position { line: 1, col: 2 },
86
                end: Position { line: 1, col: 3 },
87
            }
88
        },
89
    );
90
4
    assert_eq!(
91
4
        ron::from_str::<String>("r#\"q").unwrap_err(),
92
        SpannedError {
93
            code: Error::ExpectedStringEnd,
94
            span: Span {
95
                start: Position { line: 1, col: 3 },
96
                end: Position { line: 1, col: 4 },
97
            }
98
        },
99
    );
100
4
}
101

            
102
16
fn rusty_byte_string_roundtrip(bytes: &[u8], ron: &str, ron_raw: &str) {
103
16
    let ser_list = ron::to_string(bytes).unwrap();
104
16
    let de_list: Vec<u8> = ron::from_str(&ser_list).unwrap();
105
16
    assert_eq!(de_list, bytes);
106

            
107
16
    let ser = ron::to_string(&bytes::Bytes::copy_from_slice(bytes)).unwrap();
108
16
    assert_eq!(ser, ron);
109

            
110
16
    let ser_non_raw = ron::ser::to_string_pretty(
111
16
        &bytes::Bytes::copy_from_slice(bytes),
112
16
        ron::ser::PrettyConfig::default(),
113
    )
114
16
    .unwrap();
115
16
    assert_eq!(ser_non_raw, ron);
116

            
117
16
    let ser_raw = ron::ser::to_string_pretty(
118
16
        &bytes::Bytes::copy_from_slice(bytes),
119
16
        ron::ser::PrettyConfig::default().escape_strings(false),
120
    )
121
16
    .unwrap();
122
16
    assert_eq!(ser_raw, ron_raw);
123

            
124
16
    let de: bytes::Bytes = ron::from_str(&ser).unwrap();
125
16
    assert_eq!(de, bytes);
126

            
127
16
    let de_raw: bytes::Bytes = ron::from_str(&ser_raw).unwrap();
128
16
    assert_eq!(de_raw, bytes);
129
16
}
130

            
131
#[test]
132
4
fn fuzzer_failures() {
133
4
    assert_eq!(
134
4
        ron::to_string(&bytes::Bytes::copy_from_slice(&[
135
4
            123, 0, 0, 0, 0, 214, 214, 214, 214, 214
136
4
        ]))
137
4
        .unwrap(),
138
        r#"b"{\x00\x00\x00\x00\xd6\xd6\xd6\xd6\xd6""#
139
    );
140
    // Need to fall back to escaping so no invalid UTF-8 is produced
141
4
    assert_eq!(
142
4
        ron::ser::to_string_pretty(
143
4
            &bytes::Bytes::copy_from_slice(&[123, 0, 0, 0, 0, 214, 214, 214, 214, 214]),
144
4
            ron::ser::PrettyConfig::default().escape_strings(false)
145
        )
146
4
        .unwrap(),
147
        r#"b"{\x00\x00\x00\x00\xd6\xd6\xd6\xd6\xd6""#
148
    );
149

            
150
4
    assert_eq!(
151
4
        ron::to_string(&bytes::Bytes::copy_from_slice(&[123, 0, 0, 0, 0])).unwrap(),
152
        r#"b"{\x00\x00\x00\x00""#
153
    );
154
4
    assert_eq!(
155
4
        ron::ser::to_string_pretty(
156
4
            &bytes::Bytes::copy_from_slice(&[123, 0, 0, 0, 0]),
157
4
            ron::ser::PrettyConfig::default().escape_strings(false)
158
        )
159
4
        .unwrap(),
160
        "b\"{\x00\x00\x00\x00\""
161
    );
162

            
163
    // `br#` should be parsed as the start of a byte string, not the identifier `br` and a `#`
164
4
    assert_eq!(
165
4
        ron::from_str(r##"br#"""#"##),
166
4
        Ok(ron::Value::Bytes(vec![34]))
167
    );
168
4
    assert_eq!(
169
4
        ron::from_str(r##"{"error": br#"""#}"##),
170
4
        Ok(ron::Value::Map(
171
4
            [(
172
4
                ron::Value::String(String::from("error")),
173
4
                ron::Value::Bytes(vec![34])
174
4
            )]
175
4
            .into_iter()
176
4
            .collect()
177
4
        ))
178
    );
179
4
    assert_eq!(
180
4
        ron::from_str(
181
4
            r##"#![enable(unwrap_newtypes)]
182
4
    #![enable(unwrap_variant_newtypes)]
183
4
    Some({"error": br#"""#})
184
4
    "##
185
        ),
186
4
        Ok(ron::Value::Option(Some(Box::new(ron::Value::Map(
187
4
            [(
188
4
                ron::Value::String(String::from("error")),
189
4
                ron::Value::Bytes(vec![34])
190
4
            )]
191
4
            .into_iter()
192
4
            .collect()
193
4
        )))))
194
    );
195

            
196
    // `br"` should be parsed as the start of a byte string, not the identifier `br` and a `"`
197
4
    assert_eq!(ron::from_str(r#"br"""#), Ok(ron::Value::Bytes(vec![])));
198
4
    assert_eq!(
199
4
        ron::from_str(r#"{"error": br""}"#),
200
4
        Ok(ron::Value::Map(
201
4
            [(
202
4
                ron::Value::String(String::from("error")),
203
4
                ron::Value::Bytes(vec![])
204
4
            )]
205
4
            .into_iter()
206
4
            .collect()
207
4
        ))
208
    );
209
4
    assert_eq!(
210
4
        ron::from_str(
211
4
            r#"#![enable(unwrap_newtypes)]
212
4
    #![enable(unwrap_variant_newtypes)]
213
4
    Some({"error": br""})
214
4
    "#
215
        ),
216
4
        Ok(ron::Value::Option(Some(Box::new(ron::Value::Map(
217
4
            [(
218
4
                ron::Value::String(String::from("error")),
219
4
                ron::Value::Bytes(vec![])
220
4
            )]
221
4
            .into_iter()
222
4
            .collect()
223
4
        )))))
224
    );
225

            
226
    // Test that the struct type check for newtype variant unwrapping does
227
    //  not enter inside a byte string to find a bad comment start
228
4
    assert_eq!(
229
4
        ron::from_str::<Option<ron::Value>>(
230
4
            r#"#![enable(unwrap_variant_newtypes)] Some(b"\xff/not a comment")"#
231
        )
232
4
        .unwrap(),
233
4
        Some(ron::Value::Bytes(b"\xff/not a comment".to_vec()))
234
    );
235

            
236
    // `b'` should be parsed as the start of a byte literal, not the identifier `b` and a `'`
237
4
    assert_eq!(
238
4
        ron::from_str(r"b'\xff'"),
239
        Ok(ron::Value::Number(ron::value::Number::U8(b'\xff')))
240
    );
241

            
242
    // `b`, `br`, `bq`, and `brq` should all be parsed as identifiers
243
16
    for id in ["b", "br", "bq", "brq"] {
244
16
        assert_eq!(ron::from_str(id), Ok(ron::Value::Unit));
245
    }
246
4
}
247

            
248
#[test]
249
4
fn serialize_backslash_byte_string() {
250
4
    check_roundtrip('\\', r"'\\'", r"'\\'");
251
4
    check_roundtrip(
252
4
        bytes::Bytes::copy_from_slice(b"\\"),
253
4
        r#"b"\\""#,
254
4
        "br#\"\\\"#",
255
    );
256
4
}
257

            
258
8
fn check_roundtrip<
259
8
    T: PartialEq + core::fmt::Debug + serde::Serialize + serde::de::DeserializeOwned,
260
8
>(
261
8
    val: T,
262
8
    cmp: &str,
263
8
    cmp_raw: &str,
264
8
) {
265
8
    let ron = ron::to_string(&val).unwrap();
266
8
    assert_eq!(ron, cmp);
267

            
268
8
    let ron_escaped =
269
8
        ron::ser::to_string_pretty(&val, ron::ser::PrettyConfig::default().escape_strings(true))
270
8
            .unwrap();
271
8
    assert_eq!(ron_escaped, cmp);
272

            
273
8
    let ron_raw = ron::ser::to_string_pretty(
274
8
        &val,
275
8
        ron::ser::PrettyConfig::default().escape_strings(false),
276
    )
277
8
    .unwrap();
278
8
    assert_eq!(ron_raw, cmp_raw);
279

            
280
8
    let de = ron::from_str::<T>(&ron).unwrap();
281
8
    assert_eq!(de, val);
282

            
283
8
    let de_raw = ron::from_str::<T>(&ron_raw).unwrap();
284
8
    assert_eq!(de_raw, val);
285
8
}
286

            
287
#[test]
288
4
fn test_weird_escapes() {
289
4
    assert_eq!(
290
4
        ron::from_str::<String>(r#""\u{1F980}""#),
291
4
        Ok(String::from("\u{1F980}"))
292
    );
293
4
    assert_eq!(
294
4
        ron::from_str::<bytes::Bytes>(r#"b"\xf0\x9f\xa6\x80""#),
295
4
        Ok(bytes::Bytes::copy_from_slice("\u{1F980}".as_bytes()))
296
    );
297
4
    assert_eq!(
298
4
        ron::from_str::<String>(r#""\xf0\x9f\xa6\x80""#),
299
4
        Ok(String::from("\u{1F980}"))
300
    );
301
4
    assert_eq!(
302
4
        ron::from_str::<String>(r#""\xf0""#),
303
        Err(SpannedError {
304
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
305
            span: Span {
306
                start: Position { line: 1, col: 2 },
307
                end: Position { line: 1, col: 6 }
308
            }
309
        })
310
    );
311
4
    assert_eq!(
312
4
        ron::from_str::<String>(r#""\xf0\x9f""#),
313
        Err(SpannedError {
314
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
315
            span: Span {
316
                start: Position { line: 1, col: 6 },
317
                end: Position { line: 1, col: 10 }
318
            }
319
        })
320
    );
321
4
    assert_eq!(
322
4
        ron::from_str::<String>(r#""\xf0\x9f\x40""#),
323
        Err(SpannedError {
324
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
325
            span: Span {
326
                start: Position { line: 1, col: 10 },
327
                end: Position { line: 1, col: 14 }
328
            }
329
        })
330
    );
331
4
    assert_eq!(
332
4
        ron::from_str::<String>(r#""\xf0\x9f\xa6""#),
333
        Err(SpannedError {
334
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
335
            span: Span {
336
                start: Position { line: 1, col: 10 },
337
                end: Position { line: 1, col: 14 }
338
            }
339
        })
340
    );
341
4
    assert_eq!(
342
4
        ron::from_str::<String>(r#""\xff\xff\xff\xff""#),
343
        Err(SpannedError {
344
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
345
            span: Span {
346
                start: Position { line: 1, col: 14 },
347
                end: Position { line: 1, col: 18 }
348
            }
349
        })
350
    );
351

            
352
4
    assert_eq!(ron::from_str::<char>(r"'\u{1F980}'"), Ok('\u{1F980}'));
353
4
    assert_eq!(
354
4
        ron::from_str::<char>(r"'\xf0\x9f\xa6\x80'"),
355
        Err(SpannedError {
356
            code: Error::InvalidEscape("Not a valid byte-escaped Unicode character"),
357
            span: Span {
358
                start: Position { line: 1, col: 1 },
359
                end: Position { line: 1, col: 6 }
360
            }
361
        })
362
    );
363
4
}
364

            
365
#[test]
366
4
fn byte_literal() {
367
4
    assert_eq!(
368
4
        ron::from_str("b'\0'"),
369
        Ok(ron::Value::Number(ron::value::Number::U8(0)))
370
    );
371
4
    assert_eq!(
372
4
        ron::from_str("b'\\0'"),
373
        Ok(ron::Value::Number(ron::value::Number::U8(0)))
374
    );
375

            
376
1028
    for b in 0..=255_u8 {
377
1024
        let default = std::ascii::escape_default(b)
378
1024
            .map(char::from)
379
1024
            .collect::<String>();
380
1024
        let lower = format!(r"\x{:02x}", b);
381
1024
        let upper = format!(r"\x{:02X}", b);
382

            
383
1024
        assert_eq!(
384
1024
            ron::from_str(&format!("b'{}'", default)),
385
1024
            Ok(ron::Value::Number(ron::value::Number::U8(b)))
386
        );
387
1024
        assert_eq!(
388
1024
            ron::from_str(&format!("b'{}'", lower)),
389
1024
            Ok(ron::Value::Number(ron::value::Number::U8(b)))
390
        );
391
1024
        assert_eq!(
392
1024
            ron::from_str(&format!("b'{}'", upper)),
393
1024
            Ok(ron::Value::Number(ron::value::Number::U8(b)))
394
        );
395
    }
396

            
397
4
    assert_eq!(
398
4
        ron::from_str::<u8>(r#"b'\u{0}'"#),
399
        Err(SpannedError {
400
            code: Error::InvalidEscape("Unexpected Unicode escape in byte literal"),
401
            span: Span {
402
                start: Position { line: 1, col: 7 },
403
                end: Position { line: 1, col: 8 },
404
            }
405
        })
406
    );
407

            
408
4
    let err = ron::from_str::<u8>(r#"b'🦀'"#).unwrap_err();
409
4
    assert_eq!(
410
        err,
411
        SpannedError {
412
            code: Error::ExpectedByteLiteral,
413
            span: Span {
414
                start: Position { line: 1, col: 1 },
415
                end: Position { line: 1, col: 4 },
416
            }
417
        }
418
    );
419
4
    assert_eq!(format!("{}", err.code), "Expected byte literal");
420

            
421
4
    assert_eq!(
422
4
        ron::from_str::<u8>(r#"b'qq'"#).unwrap_err(),
423
        SpannedError {
424
            code: Error::ExpectedByteLiteral,
425
            span: Span {
426
                start: Position { line: 1, col: 1 },
427
                end: Position { line: 1, col: 4 },
428
            }
429
        }
430
    );
431

            
432
4
    assert_eq!(
433
4
        ron::from_str::<i8>(r#"b'9'"#),
434
4
        Err(SpannedError {
435
4
            code: Error::InvalidValueForType {
436
4
                expected: String::from("an 8-bit signed integer"),
437
4
                found: String::from(r#"b'9'"#)
438
4
            },
439
4
            span: Span {
440
4
                start: Position { line: 1, col: 4 },
441
4
                end: Position { line: 1, col: 5 },
442
4
            }
443
4
        })
444
    );
445
4
}
446

            
447
#[test]
448
4
fn invalid_identifier() {
449
    #[allow(dead_code)]
450
    #[derive(Debug, Deserialize)] // GRCOV_EXCL_LINE
451
    struct Test {
452
        a: i32,
453
    }
454

            
455
28
    for id in ["b\"", "b'", "br#", "br\"", "r\"", "r#\"", "r##"] {
456
28
        assert_eq!(
457
28
            ron::from_str::<Test>(&format!("({}: 42)", id)).unwrap_err(),
458
            SpannedError {
459
                code: Error::ExpectedIdentifier,
460
                span: Span {
461
                    start: Position { line: 1, col: 2 },
462
                    end: Position { line: 1, col: 2 },
463
                }
464
            }
465
        );
466
    }
467
4
}