]>
Commit | Line | Data |
---|---|---|
0a29b90c FG |
1 | use snapbox::assert_eq; |
2 | use toml_edit::{Document, Key, Value}; | |
3 | ||
4 | macro_rules! parse { | |
5 | ($s:expr, $ty:ty) => {{ | |
6 | let v = $s.parse::<$ty>(); | |
7 | assert!(v.is_ok(), "Failed with {}", v.unwrap_err()); | |
8 | v.unwrap() | |
9 | }}; | |
10 | } | |
11 | ||
12 | macro_rules! parse_value { | |
13 | ($s:expr) => { | |
14 | parse!($s, Value) | |
15 | }; | |
16 | } | |
17 | ||
18 | macro_rules! test_key { | |
19 | ($s:expr, $expected:expr) => {{ | |
20 | let key = parse!($s, Key); | |
21 | assert_eq!($expected, key.get(), ""); | |
22 | }}; | |
23 | } | |
24 | ||
25 | #[test] | |
26 | fn test_key_from_str() { | |
27 | test_key!("a", "a"); | |
28 | test_key!(r#"'hello key'"#, "hello key"); | |
29 | test_key!( | |
30 | r#""Jos\u00E9\U000A0000\n\t\r\f\b\"""#, | |
31 | "Jos\u{00E9}\u{A0000}\n\t\r\u{c}\u{8}\"" | |
32 | ); | |
33 | test_key!("\"\"", ""); | |
34 | test_key!("\"'hello key'bla\"", "'hello key'bla"); | |
35 | test_key!( | |
36 | "'C:\\Users\\appveyor\\AppData\\Local\\Temp\\1\\cargo-edit-test.YizxPxxElXn9'", | |
37 | "C:\\Users\\appveyor\\AppData\\Local\\Temp\\1\\cargo-edit-test.YizxPxxElXn9" | |
38 | ); | |
39 | } | |
40 | ||
41 | #[test] | |
42 | fn test_value_from_str() { | |
43 | assert!(parse_value!("1979-05-27T00:32:00.999999-07:00").is_datetime()); | |
44 | assert!(parse_value!("1979-05-27T00:32:00.999999Z").is_datetime()); | |
45 | assert!(parse_value!("1979-05-27T00:32:00.999999").is_datetime()); | |
46 | assert!(parse_value!("1979-05-27T00:32:00").is_datetime()); | |
47 | assert!(parse_value!("1979-05-27").is_datetime()); | |
48 | assert!(parse_value!("00:32:00").is_datetime()); | |
49 | assert!(parse_value!("-239").is_integer()); | |
50 | assert!(parse_value!("1e200").is_float()); | |
51 | assert!(parse_value!("9_224_617.445_991_228_313").is_float()); | |
52 | assert!(parse_value!(r#""basic string\nJos\u00E9\n""#).is_str()); | |
53 | assert!(parse_value!( | |
54 | r#"""" | |
55 | multiline basic string | |
56 | """"# | |
57 | ) | |
58 | .is_str()); | |
59 | assert!(parse_value!(r#"'literal string\ \'"#).is_str()); | |
60 | assert!(parse_value!( | |
61 | r#"'''multiline | |
62 | literal \ \ | |
63 | string'''"# | |
64 | ) | |
65 | .is_str()); | |
66 | assert!(parse_value!(r#"{ hello = "world", a = 1}"#).is_inline_table()); | |
67 | assert!( | |
68 | parse_value!(r#"[ { x = 1, a = "2" }, {a = "a",b = "b", c = "c"} ]"#).is_array() | |
69 | ); | |
70 | let wp = "C:\\Users\\appveyor\\AppData\\Local\\Temp\\1\\cargo-edit-test.YizxPxxElXn9"; | |
71 | let lwp = "'C:\\Users\\appveyor\\AppData\\Local\\Temp\\1\\cargo-edit-test.YizxPxxElXn9'"; | |
72 | assert_eq!(Value::from(wp).as_str(), parse_value!(lwp).as_str()); | |
73 | assert!(parse_value!(r#""\\\"\b\f\n\r\t\u00E9\U000A0000""#).is_str()); | |
74 | } | |
75 | ||
76 | #[test] | |
77 | fn test_key_unification() { | |
78 | let toml = r#" | |
79 | [a] | |
80 | [a.'b'.c] | |
81 | [a."b".c.e] | |
82 | [a.b.c.d] | |
83 | "#; | |
84 | let expected = r#" | |
85 | [a] | |
86 | [a.'b'.c] | |
87 | [a.'b'.c.e] | |
88 | [a.'b'.c.d] | |
89 | "#; | |
90 | let doc = toml.parse::<Document>(); | |
91 | assert!(doc.is_ok()); | |
92 | let doc = doc.unwrap(); | |
93 | ||
94 | assert_eq(expected, doc.to_string()); | |
95 | } | |
96 | ||
97 | macro_rules! bad { | |
98 | ($toml:expr, $msg:expr) => { | |
99 | match $toml.parse::<Document>() { | |
100 | Ok(s) => panic!("parsed to: {:#?}", s), | |
101 | Err(e) => snapbox::assert_eq($msg, e.to_string()), | |
102 | } | |
103 | }; | |
104 | } | |
105 | ||
106 | #[test] | |
107 | fn crlf() { | |
108 | "\ | |
109 | [project]\r\n\ | |
110 | \r\n\ | |
111 | name = \"splay\"\r\n\ | |
112 | version = \"0.1.0\"\r\n\ | |
113 | authors = [\"alex@crichton.co\"]\r\n\ | |
114 | \r\n\ | |
115 | [[lib]]\r\n\ | |
116 | \r\n\ | |
117 | path = \"lib.rs\"\r\n\ | |
118 | name = \"splay\"\r\n\ | |
119 | description = \"\"\"\ | |
120 | A Rust implementation of a TAR file reader and writer. This library does not\r\n\ | |
121 | currently handle compression, but it is abstract over all I/O readers and\r\n\ | |
122 | writers. Additionally, great lengths are taken to ensure that the entire\r\n\ | |
123 | contents are never required to be entirely resident in memory all at once.\r\n\ | |
124 | \"\"\"\ | |
125 | " | |
126 | .parse::<Document>() | |
127 | .unwrap(); | |
128 | } | |
129 | ||
130 | #[test] | |
131 | fn fun_with_strings() { | |
132 | let table = r#" | |
133 | bar = "\U00000000" | |
134 | key1 = "One\nTwo" | |
135 | key2 = """One\nTwo""" | |
136 | key3 = """ | |
137 | One | |
138 | Two""" | |
139 | ||
140 | key4 = "The quick brown fox jumps over the lazy dog." | |
141 | key5 = """ | |
142 | The quick brown \ | |
143 | ||
144 | ||
145 | fox jumps over \ | |
146 | the lazy dog.""" | |
147 | key6 = """\ | |
148 | The quick brown \ | |
149 | fox jumps over \ | |
150 | the lazy dog.\ | |
151 | """ | |
152 | # What you see is what you get. | |
153 | winpath = 'C:\Users\nodejs\templates' | |
154 | winpath2 = '\\ServerX\admin$\system32\' | |
155 | quoted = 'Tom "Dubs" Preston-Werner' | |
156 | regex = '<\i\c*\s*>' | |
157 | ||
158 | regex2 = '''I [dw]on't need \d{2} apples''' | |
159 | lines = ''' | |
160 | The first newline is | |
161 | trimmed in raw strings. | |
162 | All other whitespace | |
163 | is preserved. | |
164 | ''' | |
165 | "# | |
166 | .parse::<Document>() | |
167 | .unwrap(); | |
168 | assert_eq!(table["bar"].as_str(), Some("\0")); | |
169 | assert_eq!(table["key1"].as_str(), Some("One\nTwo")); | |
170 | assert_eq!(table["key2"].as_str(), Some("One\nTwo")); | |
171 | assert_eq!(table["key3"].as_str(), Some("One\nTwo")); | |
172 | ||
173 | let msg = "The quick brown fox jumps over the lazy dog."; | |
174 | assert_eq!(table["key4"].as_str(), Some(msg)); | |
175 | assert_eq!(table["key5"].as_str(), Some(msg)); | |
176 | assert_eq!(table["key6"].as_str(), Some(msg)); | |
177 | ||
178 | assert_eq!( | |
179 | table["winpath"].as_str(), | |
180 | Some(r"C:\Users\nodejs\templates") | |
181 | ); | |
182 | assert_eq!( | |
183 | table["winpath2"].as_str(), | |
184 | Some(r"\\ServerX\admin$\system32\") | |
185 | ); | |
186 | assert_eq!( | |
187 | table["quoted"].as_str(), | |
188 | Some(r#"Tom "Dubs" Preston-Werner"#) | |
189 | ); | |
190 | assert_eq!(table["regex"].as_str(), Some(r"<\i\c*\s*>")); | |
191 | assert_eq!( | |
192 | table["regex2"].as_str(), | |
193 | Some(r"I [dw]on't need \d{2} apples") | |
194 | ); | |
195 | assert_eq!( | |
196 | table["lines"].as_str(), | |
197 | Some( | |
198 | "The first newline is\n\ | |
199 | trimmed in raw strings.\n\ | |
200 | All other whitespace\n\ | |
201 | is preserved.\n" | |
202 | ) | |
203 | ); | |
204 | } | |
205 | ||
206 | #[test] | |
207 | fn tables_in_arrays() { | |
208 | let table = r#" | |
209 | [[foo]] | |
210 | #… | |
211 | [foo.bar] | |
212 | #… | |
213 | ||
214 | [[foo]] # ... | |
215 | #… | |
216 | [foo.bar] | |
217 | #... | |
218 | "# | |
219 | .parse::<Document>() | |
220 | .unwrap(); | |
221 | table["foo"][0]["bar"].as_table().unwrap(); | |
222 | table["foo"][1]["bar"].as_table().unwrap(); | |
223 | } | |
224 | ||
225 | #[test] | |
226 | fn empty_table() { | |
227 | let table = r#" | |
228 | [foo]"# | |
229 | .parse::<Document>() | |
230 | .unwrap(); | |
231 | table["foo"].as_table().unwrap(); | |
232 | } | |
233 | ||
49aad941 FG |
234 | #[test] |
235 | fn mixed_table_issue_527() { | |
236 | let input = r#" | |
237 | [package] | |
238 | metadata.msrv = "1.65.0" | |
239 | ||
240 | [package.metadata.release.pre-release-replacements] | |
241 | "#; | |
242 | let document = input.parse::<Document>().unwrap(); | |
243 | let actual = document.to_string(); | |
244 | assert_eq(input, actual); | |
245 | } | |
246 | ||
0a29b90c FG |
247 | #[test] |
248 | fn fruit() { | |
249 | let table = r#" | |
250 | [[fruit]] | |
251 | name = "apple" | |
252 | ||
253 | [fruit.physical] | |
254 | color = "red" | |
255 | shape = "round" | |
256 | ||
257 | [[fruit.variety]] | |
258 | name = "red delicious" | |
259 | ||
260 | [[fruit.variety]] | |
261 | name = "granny smith" | |
262 | ||
263 | [[fruit]] | |
264 | name = "banana" | |
265 | ||
266 | [[fruit.variety]] | |
267 | name = "plantain" | |
268 | "# | |
269 | .parse::<Document>() | |
270 | .unwrap(); | |
271 | assert_eq!(table["fruit"][0]["name"].as_str(), Some("apple")); | |
272 | assert_eq!(table["fruit"][0]["physical"]["color"].as_str(), Some("red")); | |
273 | assert_eq!( | |
274 | table["fruit"][0]["physical"]["shape"].as_str(), | |
275 | Some("round") | |
276 | ); | |
277 | assert_eq!( | |
278 | table["fruit"][0]["variety"][0]["name"].as_str(), | |
279 | Some("red delicious") | |
280 | ); | |
281 | assert_eq!( | |
282 | table["fruit"][0]["variety"][1]["name"].as_str(), | |
283 | Some("granny smith") | |
284 | ); | |
285 | assert_eq!(table["fruit"][1]["name"].as_str(), Some("banana")); | |
286 | assert_eq!( | |
287 | table["fruit"][1]["variety"][0]["name"].as_str(), | |
288 | Some("plantain") | |
289 | ); | |
290 | } | |
291 | ||
292 | #[test] | |
293 | fn stray_cr() { | |
294 | bad!( | |
295 | "\r", | |
296 | "\ | |
297 | TOML parse error at line 1, column 1 | |
298 | | | |
299 | 1 | \r | |
300 | | ^ | |
301 | ||
302 | " | |
303 | ); | |
304 | bad!( | |
305 | "a = [ \r ]", | |
306 | "\ | |
307 | TOML parse error at line 1, column 7 | |
308 | | | |
309 | 1 | a = [ \r | |
310 | ] | |
311 | | ^ | |
312 | invalid array | |
313 | expected `]` | |
314 | " | |
315 | ); | |
316 | bad!( | |
317 | "a = \"\"\"\r\"\"\"", | |
318 | "\ | |
319 | TOML parse error at line 1, column 8 | |
320 | | | |
321 | 1 | a = \"\"\"\r | |
322 | \"\"\" | |
323 | | ^ | |
324 | invalid multiline basic string | |
325 | " | |
326 | ); | |
327 | bad!( | |
328 | "a = \"\"\"\\ \r \"\"\"", | |
329 | "\ | |
330 | TOML parse error at line 1, column 10 | |
331 | | | |
332 | 1 | a = \"\"\"\\ \r | |
333 | \"\"\" | |
334 | | ^ | |
335 | invalid escape sequence | |
336 | expected `b`, `f`, `n`, `r`, `t`, `u`, `U`, `\\`, `\"` | |
337 | " | |
338 | ); | |
339 | bad!( | |
340 | "a = '''\r'''", | |
341 | "\ | |
342 | TOML parse error at line 1, column 8 | |
343 | | | |
344 | 1 | a = '''\r | |
345 | ''' | |
346 | | ^ | |
347 | invalid multiline literal string | |
348 | " | |
349 | ); | |
350 | bad!( | |
351 | "a = '\r'", | |
352 | "\ | |
353 | TOML parse error at line 1, column 6 | |
354 | | | |
355 | 1 | a = '\r | |
356 | ' | |
357 | | ^ | |
358 | invalid literal string | |
359 | " | |
360 | ); | |
361 | bad!( | |
362 | "a = \"\r\"", | |
363 | "\ | |
364 | TOML parse error at line 1, column 6 | |
365 | | | |
366 | 1 | a = \"\r | |
367 | \" | |
368 | | ^ | |
369 | invalid basic string | |
370 | " | |
371 | ); | |
372 | } | |
373 | ||
374 | #[test] | |
375 | fn blank_literal_string() { | |
376 | let table = "foo = ''".parse::<Document>().unwrap(); | |
377 | assert_eq!(table["foo"].as_str(), Some("")); | |
378 | } | |
379 | ||
380 | #[test] | |
381 | fn many_blank() { | |
382 | let table = "foo = \"\"\"\n\n\n\"\"\"".parse::<Document>().unwrap(); | |
383 | assert_eq!(table["foo"].as_str(), Some("\n\n")); | |
384 | } | |
385 | ||
386 | #[test] | |
387 | fn literal_eats_crlf() { | |
388 | let table = " | |
389 | foo = \"\"\"\\\r\n\"\"\" | |
390 | bar = \"\"\"\\\r\n \r\n \r\n a\"\"\" | |
391 | " | |
392 | .parse::<Document>() | |
393 | .unwrap(); | |
394 | assert_eq!(table["foo"].as_str(), Some("")); | |
395 | assert_eq!(table["bar"].as_str(), Some("a")); | |
396 | } | |
397 | ||
398 | #[test] | |
399 | fn string_no_newline() { | |
400 | bad!( | |
401 | "a = \"\n\"", | |
402 | "\ | |
403 | TOML parse error at line 1, column 6 | |
404 | | | |
405 | 1 | a = \" | |
406 | | ^ | |
407 | invalid basic string | |
408 | " | |
409 | ); | |
410 | bad!( | |
411 | "a = '\n'", | |
412 | "\ | |
413 | TOML parse error at line 1, column 6 | |
414 | | | |
415 | 1 | a = ' | |
416 | | ^ | |
417 | invalid literal string | |
418 | " | |
419 | ); | |
420 | } | |
421 | ||
422 | #[test] | |
423 | fn bad_leading_zeros() { | |
424 | bad!( | |
425 | "a = 00", | |
426 | "\ | |
427 | TOML parse error at line 1, column 6 | |
428 | | | |
429 | 1 | a = 00 | |
430 | | ^ | |
431 | expected newline, `#` | |
432 | " | |
433 | ); | |
434 | bad!( | |
435 | "a = -00", | |
436 | "\ | |
437 | TOML parse error at line 1, column 7 | |
438 | | | |
439 | 1 | a = -00 | |
440 | | ^ | |
441 | expected newline, `#` | |
442 | " | |
443 | ); | |
444 | bad!( | |
445 | "a = +00", | |
446 | "\ | |
447 | TOML parse error at line 1, column 7 | |
448 | | | |
449 | 1 | a = +00 | |
450 | | ^ | |
451 | expected newline, `#` | |
452 | " | |
453 | ); | |
454 | bad!( | |
455 | "a = 00.0", | |
456 | "\ | |
457 | TOML parse error at line 1, column 6 | |
458 | | | |
459 | 1 | a = 00.0 | |
460 | | ^ | |
461 | expected newline, `#` | |
462 | " | |
463 | ); | |
464 | bad!( | |
465 | "a = -00.0", | |
466 | "\ | |
467 | TOML parse error at line 1, column 7 | |
468 | | | |
469 | 1 | a = -00.0 | |
470 | | ^ | |
471 | expected newline, `#` | |
472 | " | |
473 | ); | |
474 | bad!( | |
475 | "a = +00.0", | |
476 | "\ | |
477 | TOML parse error at line 1, column 7 | |
478 | | | |
479 | 1 | a = +00.0 | |
480 | | ^ | |
481 | expected newline, `#` | |
482 | " | |
483 | ); | |
484 | bad!( | |
485 | "a = 9223372036854775808", | |
486 | "\ | |
487 | TOML parse error at line 1, column 5 | |
488 | | | |
489 | 1 | a = 9223372036854775808 | |
490 | | ^ | |
491 | number too large to fit in target type | |
492 | " | |
493 | ); | |
494 | bad!( | |
495 | "a = -9223372036854775809", | |
496 | "\ | |
497 | TOML parse error at line 1, column 5 | |
498 | | | |
499 | 1 | a = -9223372036854775809 | |
500 | | ^ | |
501 | number too small to fit in target type | |
502 | " | |
503 | ); | |
504 | } | |
505 | ||
506 | #[test] | |
507 | fn bad_floats() { | |
508 | bad!( | |
509 | "a = 0.", | |
510 | "\ | |
511 | TOML parse error at line 1, column 7 | |
512 | | | |
513 | 1 | a = 0. | |
514 | | ^ | |
515 | invalid floating-point number | |
516 | expected digit | |
517 | " | |
518 | ); | |
519 | bad!( | |
520 | "a = 0.e", | |
521 | "\ | |
522 | TOML parse error at line 1, column 7 | |
523 | | | |
524 | 1 | a = 0.e | |
525 | | ^ | |
526 | invalid floating-point number | |
527 | expected digit | |
528 | " | |
529 | ); | |
530 | bad!( | |
531 | "a = 0.E", | |
532 | "\ | |
533 | TOML parse error at line 1, column 7 | |
534 | | | |
535 | 1 | a = 0.E | |
536 | | ^ | |
537 | invalid floating-point number | |
538 | expected digit | |
539 | " | |
540 | ); | |
541 | bad!( | |
542 | "a = 0.0E", | |
543 | "\ | |
544 | TOML parse error at line 1, column 9 | |
545 | | | |
546 | 1 | a = 0.0E | |
547 | | ^ | |
548 | invalid floating-point number | |
549 | " | |
550 | ); | |
551 | bad!( | |
552 | "a = 0.0e", | |
553 | "\ | |
554 | TOML parse error at line 1, column 9 | |
555 | | | |
556 | 1 | a = 0.0e | |
557 | | ^ | |
558 | invalid floating-point number | |
559 | " | |
560 | ); | |
561 | bad!( | |
562 | "a = 0.0e-", | |
563 | "\ | |
564 | TOML parse error at line 1, column 10 | |
565 | | | |
566 | 1 | a = 0.0e- | |
567 | | ^ | |
568 | invalid floating-point number | |
569 | " | |
570 | ); | |
571 | bad!( | |
572 | "a = 0.0e+", | |
573 | "\ | |
574 | TOML parse error at line 1, column 10 | |
575 | | | |
576 | 1 | a = 0.0e+ | |
577 | | ^ | |
578 | invalid floating-point number | |
579 | " | |
580 | ); | |
581 | } | |
582 | ||
583 | #[test] | |
584 | fn floats() { | |
585 | macro_rules! t { | |
586 | ($actual:expr, $expected:expr) => {{ | |
587 | let f = format!("foo = {}", $actual); | |
588 | println!("{}", f); | |
589 | let a = f.parse::<Document>().unwrap(); | |
590 | assert_eq!(a["foo"].as_float().unwrap(), $expected); | |
591 | }}; | |
592 | } | |
593 | ||
594 | t!("1.0", 1.0); | |
595 | t!("1.0e0", 1.0); | |
596 | t!("1.0e+0", 1.0); | |
597 | t!("1.0e-0", 1.0); | |
598 | t!("1E-0", 1.0); | |
599 | t!("1.001e-0", 1.001); | |
600 | t!("2e10", 2e10); | |
601 | t!("2e+10", 2e10); | |
602 | t!("2e-10", 2e-10); | |
603 | t!("2_0.0", 20.0); | |
604 | t!("2_0.0_0e1_0", 20.0e10); | |
605 | t!("2_0.1_0e1_0", 20.1e10); | |
606 | } | |
607 | ||
608 | #[test] | |
609 | fn bare_key_names() { | |
610 | let a = " | |
611 | foo = 3 | |
612 | foo_3 = 3 | |
613 | foo_-2--3--r23f--4-f2-4 = 3 | |
614 | _ = 3 | |
615 | - = 3 | |
616 | 8 = 8 | |
617 | \"a\" = 3 | |
618 | \"!\" = 3 | |
619 | \"a^b\" = 3 | |
620 | \"\\\"\" = 3 | |
621 | \"character encoding\" = \"value\" | |
622 | 'ʎǝʞ' = \"value\" | |
623 | " | |
624 | .parse::<Document>() | |
625 | .unwrap(); | |
626 | let _ = &a["foo"]; | |
627 | let _ = &a["-"]; | |
628 | let _ = &a["_"]; | |
629 | let _ = &a["8"]; | |
630 | let _ = &a["foo_3"]; | |
631 | let _ = &a["foo_-2--3--r23f--4-f2-4"]; | |
632 | let _ = &a["a"]; | |
633 | let _ = &a["!"]; | |
634 | let _ = &a["\""]; | |
635 | let _ = &a["character encoding"]; | |
636 | let _ = &a["ʎǝʞ"]; | |
637 | } | |
638 | ||
639 | #[test] | |
640 | fn bad_keys() { | |
641 | bad!( | |
642 | "key\n=3", | |
643 | "\ | |
644 | TOML parse error at line 1, column 4 | |
645 | | | |
646 | 1 | key | |
647 | | ^ | |
648 | expected `.`, `=` | |
649 | " | |
650 | ); | |
651 | bad!( | |
652 | "key=\n3", | |
653 | "\ | |
654 | TOML parse error at line 1, column 5 | |
655 | | | |
656 | 1 | key= | |
657 | | ^ | |
658 | invalid string | |
659 | expected `\"`, `'` | |
660 | " | |
661 | ); | |
662 | bad!( | |
663 | "key|=3", | |
664 | "\ | |
665 | TOML parse error at line 1, column 4 | |
666 | | | |
667 | 1 | key|=3 | |
668 | | ^ | |
669 | expected `.`, `=` | |
670 | " | |
671 | ); | |
672 | bad!( | |
673 | "=3", | |
674 | "\ | |
675 | TOML parse error at line 1, column 1 | |
676 | | | |
677 | 1 | =3 | |
678 | | ^ | |
679 | invalid key | |
680 | " | |
681 | ); | |
682 | bad!( | |
683 | "\"\"|=3", | |
684 | "\ | |
685 | TOML parse error at line 1, column 3 | |
686 | | | |
687 | 1 | \"\"|=3 | |
688 | | ^ | |
689 | expected `.`, `=` | |
690 | " | |
691 | ); | |
692 | bad!( | |
693 | "\"\n\"|=3", | |
694 | "\ | |
695 | TOML parse error at line 1, column 2 | |
696 | | | |
697 | 1 | \" | |
698 | | ^ | |
699 | invalid basic string | |
700 | " | |
701 | ); | |
702 | bad!( | |
703 | "\"\r\"|=3", | |
704 | "\ | |
705 | TOML parse error at line 1, column 2 | |
706 | | | |
707 | 1 | \"\r\"|=3 | |
708 | | ^ | |
709 | invalid basic string | |
710 | " | |
711 | ); | |
712 | bad!( | |
713 | "''''''=3", | |
714 | "\ | |
715 | TOML parse error at line 1, column 3 | |
716 | | | |
717 | 1 | ''''''=3 | |
718 | | ^ | |
719 | expected `.`, `=` | |
720 | " | |
721 | ); | |
722 | bad!( | |
723 | "\"\"\"\"\"\"=3", | |
724 | "\ | |
725 | TOML parse error at line 1, column 3 | |
726 | | | |
727 | 1 | \"\"\"\"\"\"=3 | |
728 | | ^ | |
729 | expected `.`, `=` | |
730 | " | |
731 | ); | |
732 | bad!( | |
733 | "'''key'''=3", | |
734 | "\ | |
735 | TOML parse error at line 1, column 3 | |
736 | | | |
737 | 1 | '''key'''=3 | |
738 | | ^ | |
739 | expected `.`, `=` | |
740 | " | |
741 | ); | |
742 | bad!( | |
743 | "\"\"\"key\"\"\"=3", | |
744 | "\ | |
745 | TOML parse error at line 1, column 3 | |
746 | | | |
747 | 1 | \"\"\"key\"\"\"=3 | |
748 | | ^ | |
749 | expected `.`, `=` | |
750 | " | |
751 | ); | |
752 | } | |
753 | ||
754 | #[test] | |
755 | fn bad_table_names() { | |
756 | bad!( | |
757 | "[]", | |
758 | "\ | |
759 | TOML parse error at line 1, column 2 | |
760 | | | |
761 | 1 | [] | |
762 | | ^ | |
763 | invalid key | |
764 | " | |
765 | ); | |
766 | bad!( | |
767 | "[.]", | |
768 | "\ | |
769 | TOML parse error at line 1, column 2 | |
770 | | | |
771 | 1 | [.] | |
772 | | ^ | |
773 | invalid key | |
774 | " | |
775 | ); | |
776 | bad!( | |
777 | "[a.]", | |
778 | "\ | |
779 | TOML parse error at line 1, column 3 | |
780 | | | |
781 | 1 | [a.] | |
782 | | ^ | |
783 | invalid table header | |
784 | expected `.`, `]` | |
785 | " | |
786 | ); | |
787 | bad!( | |
788 | "[!]", | |
789 | "\ | |
790 | TOML parse error at line 1, column 2 | |
791 | | | |
792 | 1 | [!] | |
793 | | ^ | |
794 | invalid key | |
795 | " | |
796 | ); | |
797 | bad!( | |
798 | "[\"\n\"]", | |
799 | "\ | |
800 | TOML parse error at line 1, column 3 | |
801 | | | |
802 | 1 | [\" | |
803 | | ^ | |
804 | invalid basic string | |
805 | " | |
806 | ); | |
807 | bad!( | |
808 | "[a.b]\n[a.\"b\"]", | |
809 | "\ | |
810 | TOML parse error at line 2, column 1 | |
811 | | | |
812 | 2 | [a.\"b\"] | |
813 | | ^ | |
814 | invalid table header | |
815 | duplicate key `b` in table `a` | |
816 | " | |
817 | ); | |
818 | bad!( | |
819 | "[']", | |
820 | "\ | |
821 | TOML parse error at line 1, column 4 | |
822 | | | |
823 | 1 | ['] | |
824 | | ^ | |
825 | invalid literal string | |
826 | " | |
827 | ); | |
828 | bad!( | |
829 | "[''']", | |
830 | "\ | |
831 | TOML parse error at line 1, column 4 | |
832 | | | |
833 | 1 | ['''] | |
834 | | ^ | |
835 | invalid table header | |
836 | expected `.`, `]` | |
837 | " | |
838 | ); | |
839 | bad!( | |
840 | "['''''']", | |
841 | "\ | |
842 | TOML parse error at line 1, column 4 | |
843 | | | |
844 | 1 | [''''''] | |
845 | | ^ | |
846 | invalid table header | |
847 | expected `.`, `]` | |
848 | " | |
849 | ); | |
850 | bad!( | |
851 | "['''foo''']", | |
852 | "\ | |
853 | TOML parse error at line 1, column 4 | |
854 | | | |
855 | 1 | ['''foo'''] | |
856 | | ^ | |
857 | invalid table header | |
858 | expected `.`, `]` | |
859 | " | |
860 | ); | |
861 | bad!( | |
862 | "[\"\"\"bar\"\"\"]", | |
863 | "\ | |
864 | TOML parse error at line 1, column 4 | |
865 | | | |
866 | 1 | [\"\"\"bar\"\"\"] | |
867 | | ^ | |
868 | invalid table header | |
869 | expected `.`, `]` | |
870 | " | |
871 | ); | |
872 | bad!( | |
873 | "['\n']", | |
874 | "\ | |
875 | TOML parse error at line 1, column 3 | |
876 | | | |
877 | 1 | [' | |
878 | | ^ | |
879 | invalid literal string | |
880 | " | |
881 | ); | |
882 | bad!( | |
883 | "['\r\n']", | |
884 | "\ | |
885 | TOML parse error at line 1, column 3 | |
886 | | | |
887 | 1 | [' | |
888 | | ^ | |
889 | invalid literal string | |
890 | " | |
891 | ); | |
892 | } | |
893 | ||
894 | #[test] | |
895 | fn table_names() { | |
896 | let a = " | |
897 | [a.\"b\"] | |
898 | [\"f f\"] | |
899 | [\"f.f\"] | |
900 | [\"\\\"\"] | |
901 | ['a.a'] | |
902 | ['\"\"'] | |
903 | " | |
904 | .parse::<Document>() | |
905 | .unwrap(); | |
906 | println!("{:?}", a); | |
907 | let _ = &a["a"]["b"]; | |
908 | let _ = &a["f f"]; | |
909 | let _ = &a["f.f"]; | |
910 | let _ = &a["\""]; | |
911 | let _ = &a["\"\""]; | |
912 | } | |
913 | ||
914 | #[test] | |
915 | fn invalid_bare_numeral() { | |
916 | bad!( | |
917 | "4", | |
918 | "\ | |
919 | TOML parse error at line 1, column 2 | |
920 | | | |
921 | 1 | 4 | |
922 | | ^ | |
923 | expected `.`, `=` | |
924 | " | |
925 | ); | |
926 | } | |
927 | ||
928 | #[test] | |
929 | fn inline_tables() { | |
930 | "a = {}".parse::<Document>().unwrap(); | |
931 | "a = {b=1}".parse::<Document>().unwrap(); | |
932 | "a = { b = 1 }".parse::<Document>().unwrap(); | |
933 | "a = {a=1,b=2}".parse::<Document>().unwrap(); | |
934 | "a = {a=1,b=2,c={}}".parse::<Document>().unwrap(); | |
935 | ||
936 | bad!( | |
937 | "a = {a=1,}", | |
938 | "\ | |
939 | TOML parse error at line 1, column 9 | |
940 | | | |
941 | 1 | a = {a=1,} | |
942 | | ^ | |
943 | invalid inline table | |
944 | expected `}` | |
945 | " | |
946 | ); | |
947 | bad!( | |
948 | "a = {,}", | |
949 | "\ | |
950 | TOML parse error at line 1, column 6 | |
951 | | | |
952 | 1 | a = {,} | |
953 | | ^ | |
954 | invalid inline table | |
955 | expected `}` | |
956 | " | |
957 | ); | |
958 | bad!( | |
959 | "a = {a=1,a=1}", | |
960 | "\ | |
961 | TOML parse error at line 1, column 6 | |
962 | | | |
963 | 1 | a = {a=1,a=1} | |
964 | | ^ | |
965 | duplicate key `a` | |
966 | " | |
967 | ); | |
968 | bad!( | |
969 | "a = {\n}", | |
970 | "\ | |
971 | TOML parse error at line 1, column 6 | |
972 | | | |
973 | 1 | a = { | |
974 | | ^ | |
975 | invalid inline table | |
976 | expected `}` | |
977 | " | |
978 | ); | |
979 | bad!( | |
980 | "a = {", | |
981 | "\ | |
982 | TOML parse error at line 1, column 6 | |
983 | | | |
984 | 1 | a = { | |
985 | | ^ | |
986 | invalid inline table | |
987 | expected `}` | |
988 | " | |
989 | ); | |
990 | ||
991 | "a = {a=[\n]}".parse::<Document>().unwrap(); | |
992 | "a = {\"a\"=[\n]}".parse::<Document>().unwrap(); | |
993 | "a = [\n{},\n{},\n]".parse::<Document>().unwrap(); | |
994 | } | |
995 | ||
996 | #[test] | |
997 | fn number_underscores() { | |
998 | macro_rules! t { | |
999 | ($actual:expr, $expected:expr) => {{ | |
1000 | let f = format!("foo = {}", $actual); | |
1001 | let table = f.parse::<Document>().unwrap(); | |
1002 | assert_eq!(table["foo"].as_integer().unwrap(), $expected); | |
1003 | }}; | |
1004 | } | |
1005 | ||
1006 | t!("1_0", 10); | |
1007 | t!("1_0_0", 100); | |
1008 | t!("1_000", 1000); | |
1009 | t!("+1_000", 1000); | |
1010 | t!("-1_000", -1000); | |
1011 | } | |
1012 | ||
1013 | #[test] | |
1014 | fn bad_underscores() { | |
1015 | bad!( | |
1016 | "foo = 0_", | |
1017 | "\ | |
1018 | TOML parse error at line 1, column 8 | |
1019 | | | |
1020 | 1 | foo = 0_ | |
1021 | | ^ | |
1022 | expected newline, `#` | |
1023 | " | |
1024 | ); | |
1025 | bad!( | |
1026 | "foo = 0__0", | |
1027 | "\ | |
1028 | TOML parse error at line 1, column 8 | |
1029 | | | |
1030 | 1 | foo = 0__0 | |
1031 | | ^ | |
1032 | expected newline, `#` | |
1033 | " | |
1034 | ); | |
1035 | bad!( | |
1036 | "foo = __0", | |
1037 | "\ | |
1038 | TOML parse error at line 1, column 7 | |
1039 | | | |
1040 | 1 | foo = __0 | |
1041 | | ^ | |
1042 | invalid integer | |
1043 | expected leading digit | |
1044 | " | |
1045 | ); | |
1046 | bad!( | |
1047 | "foo = 1_0_", | |
1048 | "\ | |
1049 | TOML parse error at line 1, column 11 | |
1050 | | | |
1051 | 1 | foo = 1_0_ | |
1052 | | ^ | |
1053 | invalid integer | |
1054 | expected digit | |
1055 | " | |
1056 | ); | |
1057 | } | |
1058 | ||
1059 | #[test] | |
1060 | fn bad_unicode_codepoint() { | |
1061 | bad!( | |
1062 | "foo = \"\\uD800\"", | |
1063 | "\ | |
1064 | TOML parse error at line 1, column 10 | |
1065 | | | |
1066 | 1 | foo = \"\\uD800\" | |
1067 | | ^ | |
1068 | invalid unicode 4-digit hex code | |
1069 | value is out of range | |
1070 | " | |
1071 | ); | |
1072 | } | |
1073 | ||
1074 | #[test] | |
1075 | fn bad_strings() { | |
1076 | bad!( | |
1077 | "foo = \"\\uxx\"", | |
1078 | "\ | |
1079 | TOML parse error at line 1, column 10 | |
1080 | | | |
1081 | 1 | foo = \"\\uxx\" | |
1082 | | ^ | |
1083 | invalid unicode 4-digit hex code | |
1084 | " | |
1085 | ); | |
1086 | bad!( | |
1087 | "foo = \"\\u\"", | |
1088 | "\ | |
1089 | TOML parse error at line 1, column 10 | |
1090 | | | |
1091 | 1 | foo = \"\\u\" | |
1092 | | ^ | |
1093 | invalid unicode 4-digit hex code | |
1094 | " | |
1095 | ); | |
1096 | bad!( | |
1097 | "foo = \"\\", | |
1098 | "\ | |
1099 | TOML parse error at line 1, column 8 | |
1100 | | | |
1101 | 1 | foo = \"\\ | |
1102 | | ^ | |
1103 | invalid basic string | |
1104 | " | |
1105 | ); | |
1106 | bad!( | |
1107 | "foo = '", | |
1108 | "\ | |
1109 | TOML parse error at line 1, column 8 | |
1110 | | | |
1111 | 1 | foo = ' | |
1112 | | ^ | |
1113 | invalid literal string | |
1114 | " | |
1115 | ); | |
1116 | } | |
1117 | ||
1118 | #[test] | |
1119 | fn empty_string() { | |
1120 | assert_eq!( | |
1121 | "foo = \"\"".parse::<Document>().unwrap()["foo"] | |
1122 | .as_str() | |
1123 | .unwrap(), | |
1124 | "" | |
1125 | ); | |
1126 | } | |
1127 | ||
1128 | #[test] | |
1129 | fn booleans() { | |
1130 | let table = "foo = true".parse::<Document>().unwrap(); | |
1131 | assert_eq!(table["foo"].as_bool(), Some(true)); | |
1132 | ||
1133 | let table = "foo = false".parse::<Document>().unwrap(); | |
1134 | assert_eq!(table["foo"].as_bool(), Some(false)); | |
1135 | ||
1136 | bad!( | |
1137 | "foo = true2", | |
1138 | "\ | |
1139 | TOML parse error at line 1, column 11 | |
1140 | | | |
1141 | 1 | foo = true2 | |
1142 | | ^ | |
1143 | expected newline, `#` | |
1144 | " | |
1145 | ); | |
1146 | bad!( | |
1147 | "foo = false2", | |
1148 | "\ | |
1149 | TOML parse error at line 1, column 12 | |
1150 | | | |
1151 | 1 | foo = false2 | |
1152 | | ^ | |
1153 | expected newline, `#` | |
1154 | " | |
1155 | ); | |
1156 | bad!( | |
1157 | "foo = t1", | |
1158 | "\ | |
1159 | TOML parse error at line 1, column 7 | |
1160 | | | |
1161 | 1 | foo = t1 | |
1162 | | ^ | |
1163 | invalid string | |
1164 | expected `\"`, `'` | |
1165 | " | |
1166 | ); | |
1167 | bad!( | |
1168 | "foo = f2", | |
1169 | "\ | |
1170 | TOML parse error at line 1, column 7 | |
1171 | | | |
1172 | 1 | foo = f2 | |
1173 | | ^ | |
1174 | invalid string | |
1175 | expected `\"`, `'` | |
1176 | " | |
1177 | ); | |
1178 | } | |
1179 | ||
1180 | #[test] | |
1181 | fn bad_nesting() { | |
1182 | bad!( | |
1183 | " | |
1184 | a = [2] | |
1185 | [[a]] | |
1186 | b = 5 | |
1187 | ", | |
1188 | "\ | |
1189 | TOML parse error at line 3, column 9 | |
1190 | | | |
1191 | 3 | [[a]] | |
1192 | | ^ | |
1193 | invalid table header | |
1194 | duplicate key `a` in document root | |
1195 | " | |
1196 | ); | |
1197 | bad!( | |
1198 | " | |
1199 | a = 1 | |
1200 | [a.b] | |
1201 | ", | |
1202 | "\ | |
1203 | TOML parse error at line 3, column 9 | |
1204 | | | |
1205 | 3 | [a.b] | |
1206 | | ^ | |
1207 | invalid table header | |
1208 | dotted key `a` attempted to extend non-table type (integer) | |
1209 | " | |
1210 | ); | |
1211 | bad!( | |
1212 | " | |
1213 | a = [] | |
1214 | [a.b] | |
1215 | ", | |
1216 | "\ | |
1217 | TOML parse error at line 3, column 9 | |
1218 | | | |
1219 | 3 | [a.b] | |
1220 | | ^ | |
1221 | invalid table header | |
1222 | dotted key `a` attempted to extend non-table type (array) | |
1223 | " | |
1224 | ); | |
1225 | bad!( | |
1226 | " | |
1227 | a = [] | |
1228 | [[a.b]] | |
1229 | ", | |
1230 | "\ | |
1231 | TOML parse error at line 3, column 9 | |
1232 | | | |
1233 | 3 | [[a.b]] | |
1234 | | ^ | |
1235 | invalid table header | |
1236 | dotted key `a` attempted to extend non-table type (array) | |
1237 | " | |
1238 | ); | |
1239 | bad!( | |
1240 | " | |
1241 | [a] | |
1242 | b = { c = 2, d = {} } | |
1243 | [a.b] | |
1244 | c = 2 | |
1245 | ", | |
1246 | "\ | |
1247 | TOML parse error at line 4, column 9 | |
1248 | | | |
1249 | 4 | [a.b] | |
1250 | | ^ | |
1251 | invalid table header | |
1252 | duplicate key `b` in table `a` | |
1253 | " | |
1254 | ); | |
1255 | } | |
1256 | ||
1257 | #[test] | |
1258 | fn bad_table_redefine() { | |
1259 | bad!( | |
1260 | " | |
1261 | [a] | |
1262 | foo=\"bar\" | |
1263 | [a.b] | |
1264 | foo=\"bar\" | |
1265 | [a] | |
1266 | ", | |
1267 | "\ | |
1268 | TOML parse error at line 6, column 9 | |
1269 | | | |
1270 | 6 | [a] | |
1271 | | ^ | |
1272 | invalid table header | |
1273 | duplicate key `a` in document root | |
1274 | " | |
1275 | ); | |
1276 | bad!( | |
1277 | " | |
1278 | [a] | |
1279 | foo=\"bar\" | |
1280 | b = { foo = \"bar\" } | |
1281 | [a] | |
1282 | ", | |
1283 | "\ | |
1284 | TOML parse error at line 5, column 9 | |
1285 | | | |
1286 | 5 | [a] | |
1287 | | ^ | |
1288 | invalid table header | |
1289 | duplicate key `a` in document root | |
1290 | " | |
1291 | ); | |
1292 | bad!( | |
1293 | " | |
1294 | [a] | |
1295 | b = {} | |
1296 | [a.b] | |
1297 | ", | |
1298 | "\ | |
1299 | TOML parse error at line 4, column 9 | |
1300 | | | |
1301 | 4 | [a.b] | |
1302 | | ^ | |
1303 | invalid table header | |
1304 | duplicate key `b` in table `a` | |
1305 | " | |
1306 | ); | |
1307 | ||
1308 | bad!( | |
1309 | " | |
1310 | [a] | |
1311 | b = {} | |
1312 | [a] | |
1313 | ", | |
1314 | "\ | |
1315 | TOML parse error at line 4, column 9 | |
1316 | | | |
1317 | 4 | [a] | |
1318 | | ^ | |
1319 | invalid table header | |
1320 | duplicate key `a` in document root | |
1321 | " | |
1322 | ); | |
1323 | } | |
1324 | ||
1325 | #[test] | |
1326 | fn datetimes() { | |
1327 | macro_rules! t { | |
1328 | ($actual:expr) => {{ | |
1329 | let f = format!("foo = {}", $actual); | |
1330 | let toml = f.parse::<Document>().expect(&format!("failed: {}", f)); | |
1331 | assert_eq!(toml["foo"].as_datetime().unwrap().to_string(), $actual); | |
1332 | }}; | |
1333 | } | |
1334 | ||
1335 | t!("2016-09-09T09:09:09Z"); | |
1336 | t!("2016-09-09T09:09:09.1Z"); | |
1337 | t!("2016-09-09T09:09:09.2+10:00"); | |
1338 | t!("2016-09-09T09:09:09.123456789-02:00"); | |
1339 | bad!( | |
1340 | "foo = 2016-09-09T09:09:09.Z", | |
1341 | "\ | |
1342 | TOML parse error at line 1, column 26 | |
1343 | | | |
1344 | 1 | foo = 2016-09-09T09:09:09.Z | |
1345 | | ^ | |
1346 | expected newline, `#` | |
1347 | " | |
1348 | ); | |
1349 | bad!( | |
1350 | "foo = 2016-9-09T09:09:09Z", | |
1351 | "\ | |
1352 | TOML parse error at line 1, column 12 | |
1353 | | | |
1354 | 1 | foo = 2016-9-09T09:09:09Z | |
1355 | | ^ | |
1356 | invalid date-time | |
1357 | " | |
1358 | ); | |
1359 | bad!( | |
1360 | "foo = 2016-09-09T09:09:09+2:00", | |
1361 | "\ | |
1362 | TOML parse error at line 1, column 27 | |
1363 | | | |
1364 | 1 | foo = 2016-09-09T09:09:09+2:00 | |
1365 | | ^ | |
1366 | invalid time offset | |
1367 | " | |
1368 | ); | |
1369 | bad!( | |
1370 | "foo = 2016-09-09T09:09:09-2:00", | |
1371 | "\ | |
1372 | TOML parse error at line 1, column 27 | |
1373 | | | |
1374 | 1 | foo = 2016-09-09T09:09:09-2:00 | |
1375 | | ^ | |
1376 | invalid time offset | |
1377 | " | |
1378 | ); | |
1379 | bad!( | |
1380 | "foo = 2016-09-09T09:09:09Z-2:00", | |
1381 | "\ | |
1382 | TOML parse error at line 1, column 27 | |
1383 | | | |
1384 | 1 | foo = 2016-09-09T09:09:09Z-2:00 | |
1385 | | ^ | |
1386 | expected newline, `#` | |
1387 | " | |
1388 | ); | |
1389 | } | |
1390 | ||
1391 | #[test] | |
1392 | fn require_newline_after_value() { | |
1393 | bad!( | |
1394 | "0=0r=false", | |
1395 | "\ | |
1396 | TOML parse error at line 1, column 4 | |
1397 | | | |
1398 | 1 | 0=0r=false | |
1399 | | ^ | |
1400 | expected newline, `#` | |
1401 | " | |
1402 | ); | |
1403 | bad!( | |
1404 | r#" | |
1405 | 0=""o=""m=""r=""00="0"q="""0"""e="""0""" | |
1406 | "#, | |
1407 | r#"TOML parse error at line 2, column 5 | |
1408 | | | |
1409 | 2 | 0=""o=""m=""r=""00="0"q="""0"""e="""0""" | |
1410 | | ^ | |
1411 | expected newline, `#` | |
1412 | "# | |
1413 | ); | |
1414 | bad!( | |
1415 | r#" | |
1416 | [[0000l0]] | |
1417 | 0="0"[[0000l0]] | |
1418 | 0="0"[[0000l0]] | |
1419 | 0="0"l="0" | |
1420 | "#, | |
1421 | r#"TOML parse error at line 3, column 6 | |
1422 | | | |
1423 | 3 | 0="0"[[0000l0]] | |
1424 | | ^ | |
1425 | expected newline, `#` | |
1426 | "# | |
1427 | ); | |
1428 | bad!( | |
1429 | r#" | |
1430 | 0=[0]00=[0,0,0]t=["0","0","0"]s=[1000-00-00T00:00:00Z,2000-00-00T00:00:00Z] | |
1431 | "#, | |
1432 | r#"TOML parse error at line 2, column 6 | |
1433 | | | |
1434 | 2 | 0=[0]00=[0,0,0]t=["0","0","0"]s=[1000-00-00T00:00:00Z,2000-00-00T00:00:00Z] | |
1435 | | ^ | |
1436 | expected newline, `#` | |
1437 | "# | |
1438 | ); | |
1439 | bad!( | |
1440 | r#" | |
1441 | 0=0r0=0r=false | |
1442 | "#, | |
1443 | r#"TOML parse error at line 2, column 4 | |
1444 | | | |
1445 | 2 | 0=0r0=0r=false | |
1446 | | ^ | |
1447 | expected newline, `#` | |
1448 | "# | |
1449 | ); | |
1450 | bad!( | |
1451 | r#" | |
1452 | 0=0r0=0r=falsefal=false | |
1453 | "#, | |
1454 | r#"TOML parse error at line 2, column 4 | |
1455 | | | |
1456 | 2 | 0=0r0=0r=falsefal=false | |
1457 | | ^ | |
1458 | expected newline, `#` | |
1459 | "# | |
1460 | ); | |
1461 | } | |
49aad941 FG |
1462 | |
1463 | #[test] | |
1464 | fn dont_use_dotted_key_prefix_on_table_fuzz_57049() { | |
1465 | // This could generate | |
1466 | // ```toml | |
1467 | // [ | |
1468 | // p.o] | |
1469 | // ``` | |
1470 | let input = r#" | |
1471 | p.a=4 | |
1472 | [p.o] | |
1473 | "#; | |
1474 | let document = input.parse::<Document>().unwrap(); | |
1475 | let actual = document.to_string(); | |
1476 | assert_eq(input, actual); | |
1477 | } |