1pub mod datatypes;
11mod grammar;
12
13pub use crate::grammar::abc;
14
15#[cfg(test)]
16mod tests {
17 use pretty_assertions::assert_eq;
18
19 use super::*;
20 use crate::datatypes::builder::NoteBuilder;
21 use crate::datatypes::*;
22
23 fn make_tune_header(x: &str, t: &str, k: &str) -> TuneHeader {
24 TuneHeader::new(vec![
25 HeaderLine::Field(InfoField::new('X', x.to_string()), None),
26 HeaderLine::Field(InfoField::new('T', t.to_string()), None),
27 HeaderLine::Field(InfoField::new('K', k.to_string()), None),
28 ])
29 }
30
31 #[test]
32 fn empty_tune_book() {
33 let t = abc::tune_book("").unwrap();
34 assert_eq!(t, TuneBook::new(vec![], None, vec![]));
35 }
36
37 #[test]
38 fn tune_book() {
39 let t = abc::tune_book("X:1\nT:Some Title\nK:G\n").unwrap();
40 assert_eq!(
41 t,
42 TuneBook::new(
43 vec![],
44 None,
45 vec![Tune::new(make_tune_header("1", "Some Title", "G"), None)]
46 )
47 );
48 }
49
50 #[test]
51 fn tune_book_comments() {
52 let t = abc::tune_book("\n\n% A comment\n\n% Some empty lines\nX:1\nT:Some Title\nK:G\n")
53 .unwrap();
54 assert_eq!(
55 t,
56 TuneBook::new(
57 vec![
58 IgnoredLine::EmptyLine,
59 IgnoredLine::EmptyLine,
60 IgnoredLine::Comment(Comment::CommentLine(
61 "".to_string(),
62 " A comment".to_string()
63 )),
64 IgnoredLine::EmptyLine,
65 IgnoredLine::Comment(Comment::CommentLine(
66 "".to_string(),
67 " Some empty lines".to_string()
68 )),
69 ],
70 None,
71 vec![Tune::new(make_tune_header("1", "Some Title", "G"), None)]
72 )
73 );
74 }
75
76 #[test]
77 fn tune_book_comments_2() {
78 let t = abc::tune_book("%%%%%%%\n% C1\n% C2\n\n% C3\nX:1\nT:Some Title\nK:G\n").unwrap();
79 assert_eq!(
80 t,
81 TuneBook::new(
82 vec![
83 IgnoredLine::Comment(Comment::StylesheetDirective("%%%%%".to_string())),
84 IgnoredLine::Comment(Comment::CommentLine("".to_string(), " C1".to_string())),
85 IgnoredLine::Comment(Comment::CommentLine("".to_string(), " C2".to_string())),
86 IgnoredLine::EmptyLine,
87 IgnoredLine::Comment(Comment::CommentLine("".to_string(), " C3".to_string())),
88 ],
89 None,
90 vec![Tune::new(make_tune_header("1", "Some Title", "G"), None)]
91 )
92 );
93 }
94
95 #[test]
96 fn file_header() {
97 let t = abc::tune_book("O:Some origin info\n\nX:1\nT:Some Title\nK:G\n").unwrap();
98 assert_eq!(
99 t,
100 TuneBook::new(
101 vec![],
102 Some(FileHeader::new(vec![HeaderLine::Field(
103 InfoField::new('O', "Some origin info".to_string()),
104 None
105 )]),),
106 vec![Tune::new(make_tune_header("1", "Some Title", "G"), None)]
107 )
108 );
109 }
110
111 #[test]
112 fn file_header_comments() {
113 let t = abc::tune_book(
114 "\
115% Comment 1
116O:Some origin info
117% Comment 2
118
119X:1
120T:Some Title
121K:G
122",
123 )
124 .unwrap();
125 assert_eq!(
126 t,
127 TuneBook::new(
128 vec![IgnoredLine::Comment(Comment::CommentLine(
129 "".to_string(),
130 " Comment 1".to_string()
131 ))],
132 Some(FileHeader::new(vec![
133 HeaderLine::Field(InfoField::new('O', "Some origin info".to_string()), None),
134 HeaderLine::Comment(Comment::CommentLine(
135 "".to_string(),
136 " Comment 2".to_string()
137 )),
138 ])),
139 vec![Tune::new(make_tune_header("1", "Some Title", "G"), None)]
140 )
141 );
142 }
143
144 #[test]
145 fn file_header_comment_empty() {
146 assert_eq!(
147 abc::file_header("%\n\n").unwrap(),
148 FileHeader::new(vec![HeaderLine::Comment(Comment::CommentLine(
149 "".to_string(),
150 "".to_string()
151 ))])
152 );
153 }
154
155 #[test]
156 fn file_header_comment_mixed() {
157 assert_eq!(
158 abc::file_header("% Some text 123-45[\teu] \n\n").unwrap(),
159 FileHeader::new(vec![HeaderLine::Comment(Comment::CommentLine(
160 "".to_string(),
161 " Some text 123-45[\teu] ".to_string()
162 ))])
163 );
164 }
165
166 #[test]
167 fn file_header_comment_preceding_whitespace() {
168 assert_eq!(
169 abc::file_header(" % Some text\n\n").unwrap(),
170 FileHeader::new(vec![HeaderLine::Comment(Comment::CommentLine(
171 " ".to_string(),
172 " Some text".to_string()
173 ))])
174 );
175 }
176
177 #[test]
178 fn file_header_trailing_comments() {
179 let file_header = abc::file_header(
180 "\
181O:Origin % Comment
182B:Book%Another comment
183
184",
185 )
186 .unwrap();
187 assert_eq!(
188 file_header,
189 FileHeader::new(vec![
190 HeaderLine::Field(
191 InfoField::new('O', "Origin ".to_string()),
192 Some(Comment::Comment(" Comment".to_string()))
193 ),
194 HeaderLine::Field(
195 InfoField::new('B', "Book".to_string()),
196 Some(Comment::Comment("Another comment".to_string()))
197 ),
198 ])
199 );
200 }
201
202 #[test]
203 fn file_header_stylesheet_directive_empty() {
204 let text = "%%\n\n";
205 assert_eq!(
206 abc::file_header(text).unwrap(),
207 FileHeader::new(vec![HeaderLine::Comment(Comment::StylesheetDirective(
208 "".to_string()
209 ))])
210 );
211 }
212
213 #[test]
214 fn file_header_stylesheet_directive() {
215 let text = "%%pagewidth\t21cm\n\n";
216 assert_eq!(
217 abc::file_header(text).unwrap(),
218 FileHeader::new(vec![HeaderLine::Comment(Comment::StylesheetDirective(
219 "pagewidth\t21cm".to_string()
220 ))])
221 );
222 }
223
224 #[test]
225 fn invalid_tune() {
226 abc::tune("a").unwrap_err();
227 }
228
229 #[test]
230 fn empty_tune_no_body() {
231 let t = abc::tune("X:1\nT:Some Title\nK:G\n").unwrap();
232 assert_eq!(t, Tune::new(make_tune_header("1", "Some Title", "G"), None));
233 }
234
235 #[test]
236 fn empty_tune_empty_body() {
237 let t = abc::tune("X:1\nT:Some Title\nK:G\n\n").unwrap();
238 assert_eq!(
239 t,
240 Tune::new(
241 make_tune_header("1", "Some Title", "G"),
242 Some(TuneBody::new(vec![]))
243 )
244 );
245 }
246
247 #[test]
248 fn tune_header() {
249 let t = abc::tune_header("X:1\nT:Some Title\nK:G\n").unwrap();
250 assert_eq!(t, make_tune_header("1", "Some Title", "G"));
251 }
252
253 #[test]
254 fn tune_header_unicode() {
255 let t = abc::tune_header("X:1\nT:S©ome ©Title©\nK:G\n").unwrap();
256 assert_eq!(t, make_tune_header("1", "S©ome ©Title©", "G"));
257 }
258
259 #[test]
260 fn tune_header_extra_fields() {
261 let t = abc::tune_header("X:1\nT:Some Title\nO:England\nK:G\n").unwrap();
262 assert_eq!(
263 t,
264 TuneHeader::new(vec![
265 HeaderLine::Field(InfoField::new('X', "1".to_string()), None),
266 HeaderLine::Field(InfoField::new('T', "Some Title".to_string()), None),
267 HeaderLine::Field(InfoField::new('O', "England".to_string()), None),
268 HeaderLine::Field(InfoField::new('K', "G".to_string()), None),
269 ])
270 );
271 }
272
273 #[test]
274 fn tune_header_comments() {
275 let t = abc::tune_header(
276 "\
277% Comment 1
278X:1
279% Comment 2
280T:Some Title
281% Comment 3
282O:England
283% Comment 4
284K:G
285",
286 )
287 .unwrap();
288 assert_eq!(
289 t,
290 TuneHeader::new(vec![
291 HeaderLine::Comment(Comment::CommentLine(
292 "".to_string(),
293 " Comment 1".to_string()
294 )),
295 HeaderLine::Field(InfoField::new('X', "1".to_string()), None),
296 HeaderLine::Comment(Comment::CommentLine(
297 "".to_string(),
298 " Comment 2".to_string()
299 )),
300 HeaderLine::Field(InfoField::new('T', "Some Title".to_string()), None),
301 HeaderLine::Comment(Comment::CommentLine(
302 "".to_string(),
303 " Comment 3".to_string()
304 )),
305 HeaderLine::Field(InfoField::new('O', "England".to_string()), None),
306 HeaderLine::Comment(Comment::CommentLine(
307 "".to_string(),
308 " Comment 4".to_string()
309 )),
310 HeaderLine::Field(InfoField::new('K', "G".to_string()), None),
311 ])
312 );
313 }
314
315 #[test]
316 fn tune_header_trailing_comments() {
317 let t = abc::tune_header(
318 "\
319X:1%Comment 1
320T:Some Title%Comment 2
321O:England%Comment 3
322K:G%Comment 4
323",
324 )
325 .unwrap();
326 assert_eq!(
327 t,
328 TuneHeader::new(vec![
329 HeaderLine::Field(
330 InfoField::new('X', "1".to_string()),
331 Some(Comment::Comment("Comment 1".to_string()))
332 ),
333 HeaderLine::Field(
334 InfoField::new('T', "Some Title".to_string()),
335 Some(Comment::Comment("Comment 2".to_string()))
336 ),
337 HeaderLine::Field(
338 InfoField::new('O', "England".to_string()),
339 Some(Comment::Comment("Comment 3".to_string()))
340 ),
341 HeaderLine::Field(
342 InfoField::new('K', "G".to_string()),
343 Some(Comment::Comment("Comment 4".to_string()))
344 ),
345 ])
346 );
347 }
348
349 #[test]
350 fn tune_header_comment_preceding_whitespace() {
351 let t = abc::tune_header(
352 "\
353X:1
354T:Some Title
355O:England
356 % Some comment
357K:G
358",
359 )
360 .unwrap();
361 assert_eq!(
362 t,
363 TuneHeader::new(vec![
364 HeaderLine::Field(InfoField::new('X', "1".to_string()), None),
365 HeaderLine::Field(InfoField::new('T', "Some Title".to_string()), None),
366 HeaderLine::Field(InfoField::new('O', "England".to_string()), None),
367 HeaderLine::Comment(Comment::CommentLine(
368 " ".to_string(),
369 " Some comment".to_string()
370 )),
371 HeaderLine::Field(InfoField::new('K', "G".to_string()), None),
372 ])
373 );
374 }
375
376 #[test]
377 fn body_with_music() {
378 let b = abc::tune_body("A").unwrap();
379 assert_eq!(
380 b,
381 TuneBody::new(vec![TuneLine::Music(MusicLine::new(vec![
382 NoteBuilder::new(Note::A).build()
383 ]))])
384 )
385 }
386
387 #[test]
388 fn body_with_music_2() {
389 let b = abc::tune_body("A\n").unwrap();
390 assert_eq!(
391 b,
392 TuneBody::new(vec![TuneLine::Music(MusicLine::new(vec![
393 NoteBuilder::new(Note::A).build()
394 ]))])
395 )
396 }
397
398 #[test]
399 fn tune_line_comment_line_1() {
400 let m = abc::tune_line("% This is a comment\n").unwrap();
401 assert_eq!(
402 m,
403 TuneLine::Comment(Comment::CommentLine(
404 "".to_string(),
405 " This is a comment".to_string()
406 ))
407 )
408 }
409
410 #[test]
411 fn tune_line_comment_line_2() {
412 let m = abc::tune_line("% This is a comment").unwrap();
413 assert_eq!(
414 m,
415 TuneLine::Comment(Comment::CommentLine(
416 "".to_string(),
417 " This is a comment".to_string()
418 ))
419 )
420 }
421
422 #[test]
423 fn tune_line_comment_line_3() {
424 let m = abc::tune_line(" % This is a comment").unwrap();
425 assert_eq!(
426 m,
427 TuneLine::Comment(Comment::CommentLine(
428 " ".to_string(),
429 " This is a comment".to_string()
430 ))
431 )
432 }
433
434 #[test]
435 fn music_line_empty_1() {
436 abc::music_line("").unwrap_err();
437 }
438
439 #[test]
440 fn music_line_empty_2() {
441 abc::music_line("\n").unwrap_err();
442 }
443
444 #[test]
445 fn music_line_comment_err() {
446 abc::music_line("% This is a comment\n").unwrap_err();
447 }
448
449 #[test]
450 fn music_line_comment_line() {
451 let m = abc::music_line(" % This is a comment").unwrap();
454 assert_eq!(
455 m,
456 MusicLine::new(vec![
457 MusicSymbol::Space(" ".to_string()),
458 MusicSymbol::Comment(Comment::Comment(" This is a comment".to_string()))
459 ])
460 )
461 }
462
463 #[test]
464 fn music_line() {
465 let m = abc::music_line("A\n").unwrap();
466 assert_eq!(m, MusicLine::new(vec![NoteBuilder::new(Note::A).build()]))
467 }
468
469 #[test]
470 fn music_line_2() {
471 let m = abc::music_line("A").unwrap();
472 assert_eq!(m, MusicLine::new(vec![NoteBuilder::new(Note::A).build()]))
473 }
474
475 #[test]
476 fn music_line_multiple_notes() {
477 let m = abc::music_line("AB cd").unwrap();
478 assert_eq!(
479 m,
480 MusicLine::new(vec![
481 NoteBuilder::new(Note::A).build(),
482 NoteBuilder::new(Note::B).build(),
483 MusicSymbol::Space(" ".to_string()),
484 NoteBuilder::new(Note::C).octave(2).build(),
485 NoteBuilder::new(Note::D).octave(2).build(),
486 ])
487 )
488 }
489
490 #[test]
491 fn music_line_trailing_comment() {
492 let m = abc::music_line("AB cd% Inline comment\n").unwrap();
493 assert_eq!(
494 m,
495 MusicLine::new(vec![
496 NoteBuilder::new(Note::A).build(),
497 NoteBuilder::new(Note::B).build(),
498 MusicSymbol::Space(" ".to_string()),
499 NoteBuilder::new(Note::C).octave(2).build(),
500 NoteBuilder::new(Note::D).octave(2).build(),
501 MusicSymbol::Comment(Comment::Comment(" Inline comment".to_string())),
502 ])
503 )
504 }
505
506 #[test]
507 fn music_line_chord() {
508 let m =
509 abc::music_line("( \"^I\" !f! [CEG]- > [CEG] \"^IV\" [F=AC]3/2\"^V\"[GBD]/ H[CEG]2 )")
510 .unwrap();
511 assert_eq!(
512 m,
513 MusicLine::new(vec![
514 MusicSymbol::Slur(Slur::Begin),
515 MusicSymbol::Space(" ".to_string()),
516 MusicSymbol::Annotation(Annotation::new(Some(Placement::Above), "I".to_string())),
517 MusicSymbol::Space(" ".to_string()),
518 MusicSymbol::Decoration(Decoration::Unresolved("f".to_string())),
519 MusicSymbol::Space(" ".to_string()),
520 MusicSymbol::BrokenRhythm {
521 rhythm: ">".to_string(),
522 before: vec![
523 MusicSymbol::Chord {
524 notes: vec![
525 NoteBuilder::new(Note::C).build(),
526 NoteBuilder::new(Note::E).build(),
527 NoteBuilder::new(Note::G).build(),
528 ],
529 length: None,
530 tie: Some(Tie::Solid),
531 },
532 MusicSymbol::Space(" ".to_string())
533 ],
534 after: vec![
535 MusicSymbol::Space(" ".to_string()),
536 MusicSymbol::Chord {
537 notes: vec![
538 NoteBuilder::new(Note::C).build(),
539 NoteBuilder::new(Note::E).build(),
540 NoteBuilder::new(Note::G).build(),
541 ],
542 length: None,
543 tie: None,
544 }
545 ]
546 },
547 MusicSymbol::Space(" ".to_string()),
548 MusicSymbol::Annotation(Annotation::new(Some(Placement::Above), "IV".to_string())),
549 MusicSymbol::Space(" ".to_string()),
550 MusicSymbol::Chord {
551 notes: vec![
552 NoteBuilder::new(Note::F).build(),
553 NoteBuilder::new(Note::A)
554 .accidental(Accidental::Natural)
555 .build(),
556 NoteBuilder::new(Note::C).build(),
557 ],
558 length: Some(Length::new(3.0 / 2.0)),
559 tie: None,
560 },
561 MusicSymbol::Annotation(Annotation::new(Some(Placement::Above), "V".to_string())),
562 MusicSymbol::Chord {
563 notes: vec![
564 NoteBuilder::new(Note::G).build(),
565 NoteBuilder::new(Note::B).build(),
566 NoteBuilder::new(Note::D).build(),
567 ],
568 length: Some(Length::new(0.5)),
569 tie: None,
570 },
571 MusicSymbol::Space(" ".to_string()),
572 MusicSymbol::Decoration(Decoration::Fermata),
573 MusicSymbol::Chord {
574 notes: vec![
575 NoteBuilder::new(Note::C).build(),
576 NoteBuilder::new(Note::E).build(),
577 NoteBuilder::new(Note::G).build(),
578 ],
579 length: Some(Length::new(2.0)),
580 tie: None,
581 },
582 MusicSymbol::Space(" ".to_string()),
583 MusicSymbol::Slur(Slur::End),
584 ])
585 );
586 }
587
588 #[test]
589 fn music_line_beams_1() {
590 let m = abc::music_line("A2``B``C").unwrap();
591 assert_eq!(
592 m,
593 MusicLine::new(vec![
594 NoteBuilder::new(Note::A).length(2.0).build(),
595 MusicSymbol::Beam("``".to_string()),
596 NoteBuilder::new(Note::B).build(),
597 MusicSymbol::Beam("``".to_string()),
598 NoteBuilder::new(Note::C).build(),
599 ])
600 )
601 }
602
603 #[test]
604 fn music_line_beams_2() {
605 let m = abc::music_line("```A2``").unwrap();
606 assert_eq!(
607 m,
608 MusicLine::new(vec![
609 MusicSymbol::Beam("```".to_string()),
610 NoteBuilder::new(Note::A).length(2.0).build(),
611 MusicSymbol::Beam("``".to_string()),
612 ])
613 )
614 }
615
616 #[test]
617 fn symbol_line_err_1() {
618 abc::symbol_line("s: A\n").unwrap_err();
619 }
620 #[test]
621 fn symbol_line_err_2() {
622 abc::symbol_line("s: z\n").unwrap_err();
623 }
624 #[test]
625 fn symbol_line_err_3() {
626 abc::symbol_line("s: [AB]\n").unwrap_err();
627 }
628 #[test]
629 fn symbol_line_err_4() {
630 abc::symbol_line("s: {AB}\n").unwrap_err();
631 }
632 #[test]
633 fn symbol_line_err_5() {
634 abc::symbol_line("s: (3abc\n").unwrap_err();
635 }
636
637 #[test]
638 fn symbol_line_1() {
639 let m = abc::symbol_line("s: |\n").unwrap();
640 assert_eq!(
641 m,
642 SymbolLine::new(vec![
643 SymbolLineSymbol::Space(" ".to_string()),
644 SymbolLineSymbol::SymbolAlignment(SymbolAlignment::Bar),
645 ])
646 )
647 }
648
649 #[test]
650 fn symbol_line_2() {
651 let m = abc::symbol_line("s: \"C\" * \"Am\" * |\n").unwrap();
652 assert_eq!(
653 m,
654 SymbolLine::new(vec![
655 SymbolLineSymbol::Space(" ".to_string()),
656 SymbolLineSymbol::Annotation(Annotation::new(None, "C".to_string())),
657 SymbolLineSymbol::Space(" ".to_string()),
658 SymbolLineSymbol::SymbolAlignment(SymbolAlignment::Skip),
659 SymbolLineSymbol::Space(" ".to_string()),
660 SymbolLineSymbol::Annotation(Annotation::new(None, "Am".to_string())),
661 SymbolLineSymbol::Space(" ".to_string()),
662 SymbolLineSymbol::SymbolAlignment(SymbolAlignment::Skip),
663 SymbolLineSymbol::Space(" ".to_string()),
664 SymbolLineSymbol::SymbolAlignment(SymbolAlignment::Bar),
665 ])
666 )
667 }
668
669 #[test]
670 fn lyric_line_1() {
671 let m = abc::lyric_line("w: doh\n").unwrap();
672 assert_eq!(
673 m,
674 LyricLine::new(vec![
675 LyricSymbol::Space(" ".to_string()),
676 LyricSymbol::Syllable("doh".to_string()),
677 ])
678 )
679 }
680
681 #[test]
682 fn lyric_line_2() {
683 let m = abc::lyric_line("w: doh re mi fa").unwrap();
684 assert_eq!(
685 m,
686 LyricLine::new(vec![
687 LyricSymbol::Space(" ".to_string()),
688 LyricSymbol::Syllable("doh".to_string()),
689 LyricSymbol::Space(" ".to_string()),
690 LyricSymbol::Syllable("re".to_string()),
691 LyricSymbol::Space(" ".to_string()),
692 LyricSymbol::Syllable("mi".to_string()),
693 LyricSymbol::Space(" ".to_string()),
694 LyricSymbol::Syllable("fa".to_string()),
695 ])
696 )
697 }
698
699 #[test]
700 fn lyric_line_3() {
701 let m = abc::lyric_line("w: syll-a-ble").unwrap();
702 assert_eq!(
703 m,
704 LyricLine::new(vec![
705 LyricSymbol::Space(" ".to_string()),
706 LyricSymbol::Syllable("syll".to_string()),
707 LyricSymbol::SymbolAlignment(SymbolAlignment::Break),
708 LyricSymbol::Syllable("a".to_string()),
709 LyricSymbol::SymbolAlignment(SymbolAlignment::Break),
710 LyricSymbol::Syllable("ble".to_string()),
711 ])
712 )
713 }
714
715 #[test]
716 fn lyric_line_4() {
717 let m = abc::lyric_line("w: Sa-ys my au-l' aul' wan, Will~ye come dar-gle?").unwrap();
718 assert_eq!(
719 m,
720 LyricLine::new(vec![
721 LyricSymbol::Space(" ".to_string()),
722 LyricSymbol::Syllable("Sa".to_string()),
723 LyricSymbol::SymbolAlignment(SymbolAlignment::Break),
724 LyricSymbol::Syllable("ys".to_string()),
725 LyricSymbol::Space(" ".to_string()),
726 LyricSymbol::Syllable("my".to_string()),
727 LyricSymbol::Space(" ".to_string()),
728 LyricSymbol::Syllable("au".to_string()),
729 LyricSymbol::SymbolAlignment(SymbolAlignment::Break),
730 LyricSymbol::Syllable("l'".to_string()),
731 LyricSymbol::Space(" ".to_string()),
732 LyricSymbol::Syllable("aul'".to_string()),
733 LyricSymbol::Space(" ".to_string()),
734 LyricSymbol::Syllable("wan,".to_string()),
735 LyricSymbol::Space(" ".to_string()),
736 LyricSymbol::Syllable("Will".to_string()),
737 LyricSymbol::SymbolAlignment(SymbolAlignment::Space),
738 LyricSymbol::Syllable("ye".to_string()),
739 LyricSymbol::Space(" ".to_string()),
740 LyricSymbol::Syllable("come".to_string()),
741 LyricSymbol::Space(" ".to_string()),
742 LyricSymbol::Syllable("dar".to_string()),
743 LyricSymbol::SymbolAlignment(SymbolAlignment::Break),
744 LyricSymbol::Syllable("gle?".to_string()),
745 ])
746 )
747 }
748
749 #[test]
750 fn note() {
751 let s = abc::music_symbol("A").unwrap();
752 assert_eq!(s, NoteBuilder::new(Note::A).build())
753 }
754
755 macro_rules! assert_note_len {
756 ($input:tt, $expected:expr) => {
757 assert_eq!(
758 abc::music_symbol($input).unwrap(),
759 NoteBuilder::new(Note::A).length($expected).build()
760 )
761 };
762 }
763
764 #[test]
765 fn note_length_1() {
766 assert_note_len!("A3", 3f32);
767 }
768 #[test]
769 fn note_length_2() {
770 assert_note_len!("A9001", 9001f32)
771 }
772 #[test]
773 fn note_length_3() {
774 assert_note_len!("A/2", 0.5)
775 }
776 #[test]
777 fn note_length_4() {
778 assert_note_len!("A/", 0.5)
779 }
780 #[test]
781 fn note_length_5() {
782 assert_note_len!("A/4", 0.25)
783 }
784 #[test]
785 fn note_length_6() {
786 assert_note_len!("A//", 0.25)
787 }
788 #[test]
789 fn note_length_7() {
790 assert_note_len!("A3/2", 3.0 / 2.0)
791 }
792 #[test]
793 fn note_length_8() {
794 assert_note_len!("A6821/962", 6821.0 / 962.0)
795 }
796
797 #[test]
798 fn note_length_invalid_1() {
799 abc::music_symbol("A0").unwrap_err();
800 }
801 #[test]
802 fn note_length_invalid_2() {
803 abc::music_symbol("A-1").unwrap_err();
804 }
805
806 #[test]
807 fn note_invalid_1() {
808 abc::music_symbol("I").unwrap_err();
809 }
810 #[test]
811 fn note_invalid_2() {
812 abc::music_symbol("h").unwrap_err();
813 }
814 #[test]
815 fn note_invalid_3() {
816 abc::music_symbol("Y").unwrap_err();
817 }
818 #[test]
819 fn note_invalid_4() {
820 abc::music_symbol("j").unwrap_err();
821 }
822 #[test]
823 fn note_invalid_5() {
824 abc::music_symbol("m").unwrap_err();
825 }
826 #[test]
827 fn note_invalid_6() {
828 abc::music_symbol("U").unwrap_err();
829 }
830
831 macro_rules! assert_annotation {
832 ($input:tt, $placement:expr, $expected: tt) => {
833 assert_eq!(
834 abc::music_symbol($input).unwrap(),
835 MusicSymbol::Annotation(Annotation::new($placement, $expected.to_string()))
836 )
837 };
838 }
839
840 #[test]
841 fn annotation_1() {
842 assert_annotation!("\"^foo\"", Some(Placement::Above), "foo")
843 }
844 #[test]
845 fn annotation_2() {
846 assert_annotation!("\"_foo\"", Some(Placement::Below), "foo")
847 }
848 #[test]
849 fn annotation_3() {
850 assert_annotation!("\"<foo\"", Some(Placement::Left), "foo")
851 }
852 #[test]
853 fn annotation_4() {
854 assert_annotation!("\">foo\"", Some(Placement::Right), "foo")
855 }
856 #[test]
857 fn annotation_5() {
858 assert_annotation!("\"@foo\"", Some(Placement::Auto), "foo")
859 }
860 #[test]
861 fn annotation_6() {
862 assert_annotation!("\"foo\"", None, "foo")
863 }
864
865 macro_rules! assert_bar {
866 ($bar:tt) => {
867 assert_eq!(
868 abc::music_symbol($bar).unwrap(),
869 MusicSymbol::Bar($bar.to_string(), None)
870 )
871 };
872 }
873
874 #[test]
875 fn bar_1() {
876 assert_bar!("|")
877 }
878 #[test]
879 fn bar_2() {
880 assert_bar!("|]")
881 }
882 #[test]
883 fn bar_3() {
884 assert_bar!("||")
885 }
886 #[test]
887 fn bar_4() {
888 assert_bar!("[|")
889 }
890 #[test]
891 fn bar_5() {
892 assert_bar!("|:")
893 }
894 #[test]
895 fn bar_6() {
896 assert_bar!(":|")
897 }
898 #[test]
899 fn bar_7() {
900 assert_bar!("::")
901 }
902 #[test]
903 fn bar_8() {
904 assert_bar!("[|]")
905 }
906 #[test]
907 fn bar_9() {
908 assert_bar!(".|")
909 }
910 #[test]
911 fn bar_10() {
912 assert_bar!("[|:::")
913 }
914
915 #[test]
916 fn beam_1() {
917 assert_eq!(
918 abc::music_symbol("```").unwrap(),
919 MusicSymbol::Beam("```".to_string())
920 )
921 }
922
923 #[test]
924 fn slur_1() {
925 assert_eq!(
926 abc::music_symbol("(").unwrap(),
927 MusicSymbol::Slur(Slur::Begin)
928 )
929 }
930 #[test]
931 fn slur_2() {
932 assert_eq!(
933 abc::music_symbol(".(").unwrap(),
934 MusicSymbol::Slur(Slur::BeginDotted)
935 )
936 }
937 #[test]
938 fn slur_3() {
939 assert_eq!(
940 abc::music_symbol(")").unwrap(),
941 MusicSymbol::Slur(Slur::End)
942 )
943 }
944
945 macro_rules! assert_dec {
946 ($input:tt, $expected:expr) => {
947 assert_eq!(
948 abc::music_symbol($input).unwrap(),
949 MusicSymbol::Decoration($expected)
950 )
951 };
952 }
953
954 #[test]
955 fn decoration_1() {
956 assert_dec!(".", Decoration::Staccato)
957 }
958 #[test]
959 fn decoration_2() {
960 assert_dec!("~", Decoration::Roll)
961 }
962 #[test]
963 fn decoration_3() {
964 assert_dec!("H", Decoration::Fermata)
965 }
966 #[test]
967 fn decoration_4() {
968 assert_dec!("L", Decoration::Accent)
969 }
970 #[test]
971 fn decoration_5() {
972 assert_dec!("M", Decoration::LowerMordent)
973 }
974 #[test]
975 fn decoration_6() {
976 assert_dec!("O", Decoration::Coda)
977 }
978 #[test]
979 fn decoration_7() {
980 assert_dec!("P", Decoration::UpperMordent)
981 }
982 #[test]
983 fn decoration_8() {
984 assert_dec!("S", Decoration::Segno)
985 }
986 #[test]
987 fn decoration_9() {
988 assert_dec!("T", Decoration::Trill)
989 }
990 #[test]
991 fn decoration_10() {
992 assert_dec!("u", Decoration::UpBow)
993 }
994 #[test]
995 fn decoration_11() {
996 assert_dec!("v", Decoration::DownBow)
997 }
998 #[test]
999 fn decoration_12() {
1000 assert_dec!("!somedec!", Decoration::Unresolved("somedec".to_string()))
1001 }
1002
1003 #[test]
1004 fn decoration_invalid() {
1005 abc::music_symbol("!A").unwrap_err();
1006 }
1007
1008 macro_rules! assert_acc {
1009 ($input:tt, $expected:expr) => {
1010 assert_eq!(
1011 abc::music_symbol($input).unwrap(),
1012 NoteBuilder::new(Note::A).accidental($expected).build()
1013 )
1014 };
1015 }
1016
1017 #[test]
1018 fn accidental_1() {
1019 assert_acc!("^A", Accidental::Sharp)
1020 }
1021 #[test]
1022 fn accidental_2() {
1023 assert_acc!("_A", Accidental::Flat)
1024 }
1025 #[test]
1026 fn accidental_3() {
1027 assert_acc!("=A", Accidental::Natural)
1028 }
1029 #[test]
1030 fn accidental_4() {
1031 assert_acc!("^^A", Accidental::DoubleSharp)
1032 }
1033 #[test]
1034 fn accidental_5() {
1035 assert_acc!("__A", Accidental::DoubleFlat)
1036 }
1037
1038 #[test]
1039 fn accidental_invalid_1() {
1040 abc::music_symbol("^^^A").unwrap_err();
1041 }
1042 #[test]
1043 fn accidental_invalid_2() {
1044 abc::music_symbol("___A").unwrap_err();
1045 }
1046 #[test]
1047 fn accidental_invalid_3() {
1048 abc::music_symbol("_^_A").unwrap_err();
1049 }
1050 #[test]
1051 fn accidental_invalid_4() {
1052 abc::music_symbol("^_A").unwrap_err();
1053 }
1054
1055 macro_rules! assert_oct {
1056 ($input:tt, $expected:expr) => {
1057 assert_eq!(
1058 abc::music_symbol($input).unwrap(),
1059 NoteBuilder::new(Note::A).octave($expected).build()
1060 )
1061 };
1062 }
1063
1064 #[test]
1065 fn octave_1() {
1066 assert_oct!("A,", 0)
1067 }
1068 #[test]
1069 fn octave_2() {
1070 assert_oct!("A'", 2)
1071 }
1072 #[test]
1073 fn octave_3() {
1074 assert_oct!("A,,,", -2)
1075 }
1076 #[test]
1077 fn octave_4() {
1078 assert_oct!("A''''", 5)
1079 }
1080 #[test]
1081 fn octave_5() {
1082 assert_oct!("A,'", 1)
1083 }
1084 #[test]
1085 fn octave_6() {
1086 assert_oct!("A,'',,','", 1)
1087 }
1088
1089 #[test]
1090 fn tie() {
1091 assert_eq!(
1092 abc::music_line("A-A").unwrap(),
1093 MusicLine::new(vec![
1094 NoteBuilder::new(Note::A).tie(Tie::Solid).build(),
1095 NoteBuilder::new(Note::A).build(),
1096 ])
1097 );
1098 }
1099
1100 #[test]
1101 fn tie_across_bars() {
1102 assert_eq!(
1103 abc::music_line("abc-|cba").unwrap(),
1104 MusicLine::new(vec![
1105 NoteBuilder::new(Note::A).octave(2).build(),
1106 NoteBuilder::new(Note::B).octave(2).build(),
1107 NoteBuilder::new(Note::C).octave(2).tie(Tie::Solid).build(),
1108 MusicSymbol::Bar("|".to_string(), None),
1109 NoteBuilder::new(Note::C).octave(2).build(),
1110 NoteBuilder::new(Note::B).octave(2).build(),
1111 NoteBuilder::new(Note::A).octave(2).build(),
1112 ])
1113 );
1114 }
1115
1116 #[test]
1117 fn tie_with_length() {
1118 assert_eq!(
1119 abc::music_line("c4-c4").unwrap(),
1120 MusicLine::new(vec![
1121 NoteBuilder::new(Note::C)
1122 .octave(2)
1123 .length(4.0)
1124 .tie(Tie::Solid)
1125 .build(),
1126 NoteBuilder::new(Note::C).octave(2).length(4.0).build(),
1127 ])
1128 );
1129 }
1130
1131 #[test]
1132 fn tie_dotted() {
1133 assert_eq!(
1134 abc::music_line("C.-C").unwrap(),
1135 MusicLine::new(vec![
1136 NoteBuilder::new(Note::C).tie(Tie::Dotted).build(),
1137 NoteBuilder::new(Note::C).build(),
1138 ])
1139 );
1140 }
1141
1142 #[test]
1143 fn invalid_tie() {
1144 assert!(abc::music_line("c4 -c4").is_err());
1145 assert!(abc::music_line("abc|-cba").is_err());
1146 }
1147
1148 macro_rules! assert_rst {
1149 ($input:tt, $expected:expr) => {
1150 assert_eq!(
1151 abc::music_symbol($input).unwrap(),
1152 MusicSymbol::Rest($expected)
1153 )
1154 };
1155 }
1156
1157 #[test]
1158 fn rest_1() {
1159 assert_rst!("z", Rest::Note(None))
1160 }
1161 #[test]
1162 fn rest_2() {
1163 assert_rst!("x", Rest::NoteHidden(None))
1164 }
1165 #[test]
1166 fn rest_3() {
1167 assert_rst!("Z", Rest::Measure(None))
1168 }
1169 #[test]
1170 fn rest_4() {
1171 assert_rst!("X", Rest::MeasureHidden(None))
1172 }
1173 #[test]
1174 fn rest_5() {
1175 assert_rst!("z3", Rest::Note(Some(Length::new(3.0))))
1176 }
1177 #[test]
1178 fn rest_6() {
1179 assert_rst!("Z10", Rest::Measure(Some(Length::new(10.0))))
1180 }
1181 #[test]
1182 fn rest_7() {
1183 assert_rst!("x7", Rest::NoteHidden(Some(Length::new(7.0))))
1184 }
1185 #[test]
1186 fn rest_8() {
1187 assert_rst!("X900", Rest::MeasureHidden(Some(Length::new(900.0))))
1188 }
1189
1190 #[test]
1191 fn spacer() {
1192 assert_eq!(abc::music_symbol("y").unwrap(), MusicSymbol::Spacer)
1193 }
1194
1195 #[test]
1196 fn endings_error_1() {
1197 abc::ending("[abc").unwrap_err();
1198 }
1199 #[test]
1200 fn endings_error_2() {
1201 abc::ending("[1-").unwrap_err();
1202 }
1203 #[test]
1204 fn endings_error_3() {
1205 abc::ending("[1,").unwrap_err();
1206 }
1207 #[test]
1208 fn endings_error_4() {
1209 abc::ending("[1-3,").unwrap_err();
1210 }
1211
1212 #[test]
1213 fn endings_general() {
1214 let m = abc::music_line("f|[1 d:|[2 d2 B|]").unwrap();
1215 assert_eq!(
1216 m,
1217 MusicLine::new(vec![
1218 NoteBuilder::new(Note::F).octave(2).build(),
1219 MusicSymbol::Bar("|".to_string(), None),
1220 MusicSymbol::Ending("1".to_string()),
1221 MusicSymbol::Space(" ".to_string()),
1222 NoteBuilder::new(Note::D).octave(2).build(),
1223 MusicSymbol::Bar(":|".to_string(), None),
1224 MusicSymbol::Ending("2".to_string()),
1225 MusicSymbol::Space(" ".to_string()),
1226 NoteBuilder::new(Note::D).octave(2).length(2.0).build(),
1227 MusicSymbol::Space(" ".to_string()),
1228 NoteBuilder::new(Note::B).build(),
1229 MusicSymbol::Bar("|]".to_string(), None)
1230 ])
1231 );
1232 }
1233
1234 #[test]
1235 fn endings_1() {
1236 assert_eq!(
1237 abc::ending("[1").unwrap(),
1238 MusicSymbol::Ending("1".to_string())
1239 )
1240 }
1241 #[test]
1242 fn endings_2() {
1243 assert_eq!(
1244 abc::ending("[2").unwrap(),
1245 MusicSymbol::Ending("2".to_string())
1246 )
1247 }
1248 #[test]
1249 fn endings_3() {
1250 assert_eq!(
1251 abc::ending("[87654").unwrap(),
1252 MusicSymbol::Ending("87654".to_string())
1253 )
1254 }
1255 #[test]
1256 fn endings_4() {
1257 assert_eq!(
1258 abc::ending("[1,3").unwrap(),
1259 MusicSymbol::Ending("1,3".to_string())
1260 )
1261 }
1262 #[test]
1263 fn endings_5() {
1264 assert_eq!(
1265 abc::ending("[1-3").unwrap(),
1266 MusicSymbol::Ending("1-3".to_string())
1267 )
1268 }
1269 #[test]
1270 fn endings_6() {
1271 assert_eq!(
1272 abc::ending("[1,3,5-7").unwrap(),
1273 MusicSymbol::Ending("1,3,5-7".to_string())
1274 )
1275 }
1276 #[test]
1277 fn endings_7() {
1278 assert_eq!(
1279 abc::ending("[1,3,5-7,8-10").unwrap(),
1280 MusicSymbol::Ending("1,3,5-7,8-10".to_string())
1281 )
1282 }
1283
1284 #[test]
1285 fn ending_after_bar() {
1286 let m = abc::music_line("|[1").unwrap();
1287 assert_eq!(
1288 m,
1289 MusicLine::new(vec![
1290 MusicSymbol::Bar("|".to_string(), None),
1291 MusicSymbol::Ending("1".to_string())
1292 ])
1293 )
1294 }
1295
1296 #[test]
1297 fn ending_combined_with_bar() {
1298 let m = abc::music_line("|1").unwrap();
1299 assert_eq!(
1300 m,
1301 MusicLine::new(vec![MusicSymbol::Bar(
1302 "|".to_string(),
1303 Some("1".to_string())
1304 )])
1305 )
1306 }
1307
1308 #[test]
1309 fn chord_1() {
1310 let c = abc::music_symbol("[CEG]").unwrap();
1311 assert_eq!(
1312 c,
1313 MusicSymbol::Chord {
1314 notes: vec![
1315 NoteBuilder::new(Note::C).build(),
1316 NoteBuilder::new(Note::E).build(),
1317 NoteBuilder::new(Note::G).build(),
1318 ],
1319 length: None,
1320 tie: None,
1321 }
1322 );
1323 }
1324
1325 #[test]
1326 fn chord_2() {
1327 let c = abc::music_symbol("[C2E2G2]3").unwrap();
1328 assert_eq!(
1329 c,
1330 MusicSymbol::Chord {
1331 notes: vec![
1332 NoteBuilder::new(Note::C).length(2.0).build(),
1333 NoteBuilder::new(Note::E).length(2.0).build(),
1334 NoteBuilder::new(Note::G).length(2.0).build(),
1335 ],
1336 length: Some(Length::new(3.0)),
1337 tie: None,
1338 }
1339 );
1340 }
1341
1342 #[test]
1343 fn chord_3() {
1344 let c = abc::music_symbol("[!1!C!3!E!5!G]").unwrap();
1345 assert_eq!(
1346 c,
1347 MusicSymbol::Chord {
1348 notes: vec![
1349 MusicSymbol::Decoration(Decoration::Unresolved("1".to_string())),
1350 NoteBuilder::new(Note::C).build(),
1351 MusicSymbol::Decoration(Decoration::Unresolved("3".to_string())),
1352 NoteBuilder::new(Note::E).build(),
1353 MusicSymbol::Decoration(Decoration::Unresolved("5".to_string())),
1354 NoteBuilder::new(Note::G).build(),
1355 ],
1356 length: None,
1357 tie: None,
1358 }
1359 );
1360 }
1361
1362 #[test]
1363 fn grace_notes_empty() {
1364 abc::music_symbol("{}").unwrap_err();
1365 }
1366 #[test]
1367 fn grace_notes_err_1() {
1368 abc::music_symbol("{vA}").unwrap_err();
1369 }
1370 #[test]
1371 fn grace_notes_err_2() {
1372 abc::music_symbol("{HA}").unwrap_err();
1373 }
1374 #[test]
1375 fn grace_notes_err_3() {
1376 abc::music_symbol("{!fermata!A}").unwrap_err();
1377 }
1378
1379 #[test]
1380 fn grace_notes_1() {
1381 let g = abc::music_symbol("{GdGe}").unwrap();
1382 assert_eq!(
1383 g,
1384 MusicSymbol::GraceNotes {
1385 acciaccatura: None,
1386 notes: vec![
1387 NoteBuilder::new(Note::G).build(),
1388 NoteBuilder::new(Note::D).octave(2).build(),
1389 NoteBuilder::new(Note::G).build(),
1390 NoteBuilder::new(Note::E).octave(2).build()
1391 ]
1392 }
1393 )
1394 }
1395 #[test]
1396 fn grace_notes_2() {
1397 let g = abc::music_symbol("{/g}").unwrap();
1398 assert_eq!(
1399 g,
1400 MusicSymbol::GraceNotes {
1401 acciaccatura: Some(()),
1402 notes: vec![NoteBuilder::new(Note::G).octave(2).build()]
1403 }
1404 )
1405 }
1406 #[test]
1407 fn grace_notes_3() {
1408 let g = abc::music_symbol("{A<B}").unwrap();
1409 assert_eq!(
1410 g,
1411 MusicSymbol::GraceNotes {
1412 acciaccatura: None,
1413 notes: vec![MusicSymbol::BrokenRhythm {
1414 rhythm: "<".to_string(),
1415 before: vec![NoteBuilder::new(Note::A).build()],
1416 after: vec![NoteBuilder::new(Note::B).build()],
1417 }]
1418 }
1419 )
1420 }
1421 #[test]
1422 fn grace_notes_4() {
1423 let g = abc::music_symbol("{A B}").unwrap();
1424 assert_eq!(
1425 g,
1426 MusicSymbol::GraceNotes {
1427 acciaccatura: None,
1428 notes: vec![
1429 NoteBuilder::new(Note::A).build(),
1430 MusicSymbol::Space(" ".to_string()),
1431 NoteBuilder::new(Note::B).build(),
1432 ]
1433 }
1434 )
1435 }
1436
1437 macro_rules! assert_tup {
1438 ($input:tt, $p:expr, $q:expr, $r:expr) => {
1439 assert_eq!(
1440 abc::music_symbol($input).unwrap(),
1441 MusicSymbol::Tuplet {
1442 p: $p,
1443 q: $q,
1444 r: $r,
1445 }
1446 )
1447 };
1448 }
1449
1450 #[test]
1451 fn tuplet_1() {
1452 assert_tup!("(2", 2, None, None)
1453 }
1454 #[test]
1455 fn tuplet_2() {
1456 assert_tup!("(3", 3, None, None)
1457 }
1458 #[test]
1459 fn tuplet_3() {
1460 assert_tup!("(3::", 3, None, None)
1461 }
1462 #[test]
1463 fn tuplet_5() {
1464 assert_tup!("(3:2", 3, Some(2), None)
1465 }
1466 #[test]
1467 fn tuplet_6() {
1468 assert_tup!("(3:2:3", 3, Some(2), Some(3))
1469 }
1470 #[test]
1471 fn tuplet_7() {
1472 assert_tup!("(9", 9, None, None)
1473 }
1474 #[test]
1475 fn tuplet_8() {
1476 assert_eq!(
1477 abc::music_symbol("(3:2:2").unwrap(),
1478 MusicSymbol::Tuplet {
1479 p: 3,
1480 q: Some(2),
1481 r: Some(2),
1482 }
1483 )
1484 }
1485
1486 #[test]
1487 fn broken_rhythm_1() {
1488 assert_eq!(
1489 abc::music_symbol("A<B").unwrap(),
1490 MusicSymbol::BrokenRhythm {
1491 rhythm: "<".to_string(),
1492 before: vec![NoteBuilder::new(Note::A).build()],
1493 after: vec![NoteBuilder::new(Note::B).build()],
1494 }
1495 )
1496 }
1497
1498 #[test]
1499 fn broken_rhythm_2() {
1500 assert_eq!(
1501 abc::music_symbol("A>>>B").unwrap(),
1502 MusicSymbol::BrokenRhythm {
1503 rhythm: ">>>".to_string(),
1504 before: vec![NoteBuilder::new(Note::A).build()],
1505 after: vec![NoteBuilder::new(Note::B).build()],
1506 }
1507 )
1508 }
1509
1510 #[test]
1511 fn broken_rhythm_3() {
1512 assert_eq!(
1513 abc::music_symbol("z<B").unwrap(),
1514 MusicSymbol::BrokenRhythm {
1515 rhythm: "<".to_string(),
1516 before: vec![MusicSymbol::Rest(Rest::Note(None)),],
1517 after: vec![NoteBuilder::new(Note::B).build()],
1518 }
1519 )
1520 }
1521
1522 #[test]
1523 fn broken_rhythm_4() {
1524 assert_eq!(
1525 abc::music_symbol("A < B").unwrap(),
1526 MusicSymbol::BrokenRhythm {
1527 rhythm: "<".to_string(),
1528 before: vec![
1529 NoteBuilder::new(Note::A).build(),
1530 MusicSymbol::Space(" ".to_string())
1531 ],
1532 after: vec![
1533 MusicSymbol::Space(" ".to_string()),
1534 NoteBuilder::new(Note::B).build()
1535 ],
1536 }
1537 )
1538 }
1539
1540 #[test]
1541 fn broken_rhythm_5() {
1542 assert_eq!(
1543 abc::music_symbol("[AB] < B").unwrap(),
1544 MusicSymbol::BrokenRhythm {
1545 rhythm: "<".to_string(),
1546 before: vec![
1547 MusicSymbol::Chord {
1548 notes: vec![
1549 NoteBuilder::new(Note::A).build(),
1550 NoteBuilder::new(Note::B).build()
1551 ],
1552 length: None,
1553 tie: None,
1554 },
1555 MusicSymbol::Space(" ".to_string()),
1556 ],
1557 after: vec![
1558 MusicSymbol::Space(" ".to_string()),
1559 NoteBuilder::new(Note::B).build()
1560 ],
1561 }
1562 )
1563 }
1564
1565 #[ignore]
1566 #[test]
1567 fn broken_rhythm_6() {
1568 assert_eq!(
1569 abc::music_symbol("A{g}<A").unwrap(),
1570 MusicSymbol::BrokenRhythm {
1571 rhythm: "<".to_string(),
1572 before: vec![MusicSymbol::GraceNotes {
1573 acciaccatura: None,
1574 notes: vec![NoteBuilder::new(Note::G).octave(2).build()]
1575 }],
1576 after: vec![NoteBuilder::new(Note::B).build()],
1577 }
1578 )
1579 }
1580
1581 #[test]
1582 fn broken_rhythm_recursive() {
1583 assert_eq!(
1584 abc::music_symbol("A<B<C").unwrap(),
1585 MusicSymbol::BrokenRhythm {
1586 rhythm: "<".to_string(),
1587 before: vec![NoteBuilder::new(Note::A).build()],
1588 after: vec![MusicSymbol::BrokenRhythm {
1589 rhythm: "<".to_string(),
1590 before: vec![NoteBuilder::new(Note::B).build()],
1591 after: vec![NoteBuilder::new(Note::C).build()],
1592 }],
1593 }
1594 )
1595 }
1596
1597 #[test]
1598 fn inline_field() {
1599 assert_eq!(
1600 abc::music_symbol("[M:9/8]").unwrap(),
1601 MusicSymbol::InlineField(InfoField('M', "9/8".to_string()), true),
1602 )
1603 }
1604
1605 #[test]
1606 fn inline_field_line() {
1607 assert_eq!(
1608 abc::tune_line("M:9/8\n").unwrap(),
1609 TuneLine::Music(MusicLine::new(vec![MusicSymbol::InlineField(
1610 InfoField('M', "9/8".to_string()),
1611 false
1612 )])),
1613 )
1614 }
1615
1616 #[test]
1617 fn inline_field_err_1() {
1618 abc::music_symbol("[M:9/8\n").unwrap_err();
1619 }
1620 #[test]
1621 fn inline_field_err_2() {
1622 abc::music_symbol("[C:Trad.]").unwrap_err();
1623 }
1624
1625 macro_rules! assert_reserved {
1626 ($input:expr) => {
1627 assert_eq!(
1628 abc::music_symbol($input).unwrap(),
1629 MusicSymbol::Reserved($input.to_string())
1630 )
1631 };
1632 }
1633
1634 #[test]
1635 fn reserved_1() {
1636 assert_reserved!("#");
1637 }
1638 #[test]
1639 fn reserved_2() {
1640 assert_reserved!("*");
1641 }
1642 #[test]
1643 fn reserved_3() {
1644 assert_reserved!(";");
1645 }
1646 #[test]
1647 fn reserved_4() {
1648 assert_reserved!("?");
1649 }
1650 #[test]
1651 fn reserved_5() {
1652 assert_reserved!("@");
1653 }
1654}