1pub mod datatypes;
11mod grammar;
12
13pub use grammar::abc;
14
15#[cfg(test)]
16mod tests {
17 use super::*;
18 use datatypes::*;
19
20 fn make_tune_header(x: &str, t: &str, k: &str) -> TuneHeader {
21 TuneHeader::new(vec![
22 InfoField::new('X', x.to_string()),
23 InfoField::new('T', t.to_string()),
24 InfoField::new('K', k.to_string()),
25 ])
26 }
27
28 #[test]
29 fn empty_tunebook() {
30 let t = abc::tune_book("").unwrap();
31 assert_eq!(t, TuneBook::new(None, vec![]));
32 }
33
34 #[test]
35 fn tune_book() {
36 let t = abc::tune_book("X:1\nT:Some Title\nK:G\n").unwrap();
37 assert_eq!(
38 t,
39 TuneBook::new(
40 None,
41 vec![Tune::new(make_tune_header("1", "Some Title", "G"), None)]
42 )
43 );
44 }
45
46 #[test]
47 fn invalid_tune() {
48 abc::tune("a").unwrap_err();
49 }
50
51 #[test]
52 fn empty_tune_no_body() {
53 let t = abc::tune("X:1\nT:Some Title\nK:G\n").unwrap();
54 assert_eq!(t, Tune::new(make_tune_header("1", "Some Title", "G"), None));
55 }
56
57 #[test]
58 fn empty_tune_empty_body() {
59 let t = abc::tune("X:1\nT:Some Title\nK:G\n\n").unwrap();
60 assert_eq!(
61 t,
62 Tune::new(
63 make_tune_header("1", "Some Title", "G"),
64 Some(TuneBody::new(vec![]))
65 )
66 );
67 }
68
69 #[test]
70 fn tune_header() {
71 let t = abc::tune_header("X:1\nT:Some Title\nK:G\n").unwrap();
72 assert_eq!(t, make_tune_header("1", "Some Title", "G"));
73 }
74
75 #[test]
76 fn tune_header_unicode() {
77 let t = abc::tune_header("X:1\nT:S©ome ©Title©\nK:G\n").unwrap();
78 assert_eq!(t, make_tune_header("1", "S©ome ©Title©", "G"));
79 }
80
81 #[test]
82 fn tune_header_extra_fields() {
83 let t = abc::tune_header("X:1\nT:Some Title\nO:England\nK:G\n").unwrap();
84 assert_eq!(
85 t,
86 TuneHeader::new(vec![
87 InfoField::new('X', "1".to_string()),
88 InfoField::new('T', "Some Title".to_string()),
89 InfoField::new('O', "England".to_string()),
90 InfoField::new('K', "G".to_string())
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 Some(FileHeader::new(vec![InfoField::new(
102 'O',
103 "Some origin info".to_string()
104 )])),
105 vec![Tune::new(make_tune_header("1", "Some Title", "G"), None)]
106 )
107 );
108 }
109
110 #[test]
111 fn music_line_empty_1() {
112 abc::music_line("").unwrap_err();
113 }
114 #[test]
115 fn music_line_empty_2() {
116 abc::music_line("\n").unwrap_err();
117 }
118
119 #[test]
120 fn body_with_music() {
121 let b = abc::tune_body("A").unwrap();
122 assert_eq!(
123 b,
124 TuneBody::new(vec![MusicLine::new(vec![MusicSymbol::note(Note::A)])])
125 )
126 }
127
128 #[test]
129 fn body_with_music_2() {
130 let b = abc::tune_body("A\n").unwrap();
131 assert_eq!(
132 b,
133 TuneBody::new(vec![MusicLine::new(vec![MusicSymbol::note(Note::A)])])
134 )
135 }
136
137 #[test]
138 fn music_line() {
139 let m = abc::music_line("A\n").unwrap();
140 assert_eq!(m, MusicLine::new(vec![MusicSymbol::note(Note::A)]))
141 }
142
143 #[test]
144 fn music_line_2() {
145 let m = abc::music_line("A").unwrap();
146 assert_eq!(m, MusicLine::new(vec![MusicSymbol::note(Note::A)]))
147 }
148
149 #[test]
150 fn music_line_multiple_notes() {
151 let m = abc::music_line("AB cd").unwrap();
152 assert_eq!(
153 m,
154 MusicLine::new(vec![
155 MusicSymbol::note(Note::A),
156 MusicSymbol::note(Note::B),
157 MusicSymbol::VisualBreak,
158 MusicSymbol::new_note(vec![], None, Note::C, 2, 1.0, None),
159 MusicSymbol::new_note(vec![], None, Note::D, 2, 1.0, None)
160 ])
161 )
162 }
163
164 #[test]
165 fn music_line_chord() {
166 let m = abc::music_line("!f! [F=AC]3/2[GBD] H[CEG]2").unwrap();
167 assert_eq!(
168 m,
169 MusicLine::new(vec![
170 MusicSymbol::Chord {
171 decorations: vec![Decoration::Unresolved("f".to_string())],
172 notes: vec![
173 MusicSymbol::note(Note::F),
174 MusicSymbol::new_note(
175 vec![],
176 Some(Accidental::Natural),
177 Note::A,
178 1,
179 1.0,
180 None
181 ),
182 MusicSymbol::note(Note::C)
183 ],
184 length: 3.0 / 2.0
185 },
186 MusicSymbol::Chord {
187 decorations: vec![],
188 notes: vec![
189 MusicSymbol::note(Note::G),
190 MusicSymbol::note(Note::B),
191 MusicSymbol::note(Note::D)
192 ],
193 length: 1f32
194 },
195 MusicSymbol::VisualBreak,
196 MusicSymbol::Chord {
197 decorations: vec![Decoration::Fermata],
198 notes: vec![
199 MusicSymbol::note(Note::C),
200 MusicSymbol::note(Note::E),
201 MusicSymbol::note(Note::G)
202 ],
203 length: 2.0
204 }
205 ])
206 );
207 }
208
209 #[test]
210 fn music_line_backticks() {
211 let m = abc::music_line("A2``B``C").unwrap();
212 assert_eq!(
213 m,
214 MusicLine::new(vec![
215 MusicSymbol::note_from_length(Note::A, 2.0),
216 MusicSymbol::note(Note::B),
217 MusicSymbol::note(Note::C)
218 ])
219 )
220 }
221
222 #[test]
223 fn note() {
224 let s = abc::music_symbol("A").unwrap();
225 assert_eq!(s, MusicSymbol::note(Note::A))
226 }
227
228 macro_rules! assert_note_len {
229 ($input:tt, $expected:expr) => {
230 assert_eq!(
231 abc::music_symbol($input).unwrap(),
232 MusicSymbol::note_from_length(Note::A, $expected)
233 );
234 };
235 }
236
237 #[test]
238 fn note_length_1() {
239 assert_note_len!("A3", 3f32);
240 }
241 #[test]
242 fn note_length_2() {
243 assert_note_len!("A9001", 9001f32)
244 }
245 #[test]
246 fn note_length_3() {
247 assert_note_len!("A/2", 0.5)
248 }
249 #[test]
250 fn note_length_4() {
251 assert_note_len!("A/", 0.5)
252 }
253 #[test]
254 fn note_length_5() {
255 assert_note_len!("A/4", 0.25)
256 }
257 #[test]
258 fn note_length_6() {
259 assert_note_len!("A//", 0.25)
260 }
261 #[test]
262 fn note_length_7() {
263 assert_note_len!("A3/2", 3.0 / 2.0)
264 }
265 #[test]
266 fn note_length_8() {
267 assert_note_len!("A6821/962", 6821.0 / 962.0)
268 }
269
270 #[test]
271 fn note_length_invalid_1() {
272 abc::music_symbol("A0").unwrap_err();
273 }
274 #[test]
275 fn note_length_invalid_2() {
276 abc::music_symbol("A-1").unwrap_err();
277 }
278
279 #[test]
280 fn note_invalid_1() {
281 abc::music_symbol("H").unwrap_err();
282 }
283 #[test]
284 fn note_invalid_2() {
285 abc::music_symbol("h").unwrap_err();
286 }
287 #[test]
288 fn note_invalid_3() {
289 abc::music_symbol("Y").unwrap_err();
290 }
291 #[test]
292 fn note_invalid_4() {
293 abc::music_symbol("y").unwrap_err();
294 }
295 #[test]
296 fn note_invalid_5() {
297 abc::music_symbol("m").unwrap_err();
298 }
299 #[test]
300 fn note_invalid_6() {
301 abc::music_symbol("T").unwrap_err();
302 }
303
304 macro_rules! assert_bar {
305 ($bar:tt) => {
306 assert_eq!(
307 abc::music_symbol($bar).unwrap(),
308 MusicSymbol::Bar($bar.to_string())
309 )
310 };
311 }
312
313 #[test]
314 fn bar_1() {
315 assert_bar!("|")
316 }
317 #[test]
318 fn bar_2() {
319 assert_bar!("|]")
320 }
321 #[test]
322 fn bar_3() {
323 assert_bar!("||")
324 }
325 #[test]
326 fn bar_4() {
327 assert_bar!("[|")
328 }
329 #[test]
330 fn bar_5() {
331 assert_bar!("|:")
332 }
333 #[test]
334 fn bar_6() {
335 assert_bar!(":|")
336 }
337 #[test]
338 fn bar_7() {
339 assert_bar!("::")
340 }
341 #[test]
342 fn bar_8() {
343 assert_bar!("[|]")
344 }
345
346 macro_rules! assert_dec {
347 ($input:tt, $expected:expr) => {
348 assert_eq!(
349 abc::music_symbol($input).unwrap(),
350 MusicSymbol::new_note($expected, None, Note::A, 1, 1.0, None)
351 );
352 };
353 }
354
355 #[test]
356 fn decoration_1() {
357 assert_dec!(".A", vec![Decoration::Staccato])
358 }
359 #[test]
360 fn decoration_2() {
361 assert_dec!("~A", vec![Decoration::Roll])
362 }
363 #[test]
364 fn decoration_3() {
365 assert_dec!("HA", vec![Decoration::Fermata])
366 }
367 #[test]
368 fn decoration_4() {
369 assert_dec!("LA", vec![Decoration::Accent])
370 }
371 #[test]
372 fn decoration_5() {
373 assert_dec!("MA", vec![Decoration::LowerMordent])
374 }
375 #[test]
376 fn decoration_6() {
377 assert_dec!("OA", vec![Decoration::Coda])
378 }
379 #[test]
380 fn decoration_7() {
381 assert_dec!("PA", vec![Decoration::UpperMordent])
382 }
383 #[test]
384 fn decoration_8() {
385 assert_dec!("SA", vec![Decoration::Segno])
386 }
387 #[test]
388 fn decoration_9() {
389 assert_dec!("TA", vec![Decoration::Trill])
390 }
391 #[test]
392 fn decoration_10() {
393 assert_dec!("uA", vec![Decoration::UpBow])
394 }
395 #[test]
396 fn decoration_11() {
397 assert_dec!("vA", vec![Decoration::DownBow])
398 }
399 #[test]
400 fn decoration_12() {
401 assert_dec!(
402 "!somedec!A",
403 vec![Decoration::Unresolved("somedec".to_string())]
404 )
405 }
406
407 #[test]
408 fn multiple_decorations() {
409 assert_dec!("v.A", vec![Decoration::DownBow, Decoration::Staccato]);
410 }
411
412 #[test]
413 fn decoration_invalid() {
414 abc::music_symbol("!A").unwrap_err();
415 }
416
417 macro_rules! assert_acc {
418 ($input:tt, $expected:expr) => {
419 assert_eq!(
420 abc::music_symbol($input).unwrap(),
421 MusicSymbol::new_note(vec![], Some($expected), Note::A, 1, 1.0, None)
422 )
423 };
424 }
425
426 #[test]
427 fn accidental_1() {
428 assert_acc!("^A", Accidental::Sharp)
429 }
430 #[test]
431 fn accidental_2() {
432 assert_acc!("_A", Accidental::Flat)
433 }
434 #[test]
435 fn accidental_3() {
436 assert_acc!("=A", Accidental::Natural)
437 }
438 #[test]
439 fn accidental_4() {
440 assert_acc!("^^A", Accidental::DoubleSharp)
441 }
442 #[test]
443 fn accidental_5() {
444 assert_acc!("__A", Accidental::DoubleFlat)
445 }
446
447 #[test]
448 fn accidental_invalid_1() {
449 abc::music_symbol("^^^A").unwrap_err();
450 }
451 #[test]
452 fn accidental_invalid_2() {
453 abc::music_symbol("___A").unwrap_err();
454 }
455 #[test]
456 fn accidental_invalid_3() {
457 abc::music_symbol("_^_A").unwrap_err();
458 }
459 #[test]
460 fn accidental_invalid_4() {
461 abc::music_symbol("^_A").unwrap_err();
462 }
463
464 macro_rules! assert_oct {
465 ($input:tt, $expected:expr) => {
466 assert_eq!(
467 abc::music_symbol($input).unwrap(),
468 MusicSymbol::new_note(vec![], None, Note::A, $expected, 1.0, None)
469 );
470 };
471 }
472
473 #[test]
474 fn octave_1() {
475 assert_oct!("A,", 0)
476 }
477 #[test]
478 fn octave_2() {
479 assert_oct!("A'", 2)
480 }
481 #[test]
482 fn octave_3() {
483 assert_oct!("A,,,", -2)
484 }
485 #[test]
486 fn octave_4() {
487 assert_oct!("A''''", 5)
488 }
489 #[test]
490 fn octave_5() {
491 assert_oct!("A,'", 1)
492 }
493 #[test]
494 fn octave_6() {
495 assert_oct!("A,'',,','", 1)
496 }
497
498 #[test]
499 fn tie() {
500 assert_eq!(
501 abc::music_line("A-A").unwrap(),
502 MusicLine::new(vec![
503 MusicSymbol::new_note(vec![], None, Note::A, 1, 1.0, Some(Tie::Solid)),
504 MusicSymbol::new_note(vec![], None, Note::A, 1, 1.0, None)
505 ])
506 );
507 }
508
509 #[test]
510 fn tie_across_bars() {
511 assert_eq!(
512 abc::music_line("abc-|cba").unwrap(),
513 MusicLine::new(vec![
514 MusicSymbol::new_note(vec![], None, Note::A, 2, 1.0, None),
515 MusicSymbol::new_note(vec![], None, Note::B, 2, 1.0, None),
516 MusicSymbol::new_note(vec![], None, Note::C, 2, 1.0, Some(Tie::Solid)),
517 MusicSymbol::Bar("|".to_string()),
518 MusicSymbol::new_note(vec![], None, Note::C, 2, 1.0, None),
519 MusicSymbol::new_note(vec![], None, Note::B, 2, 1.0, None),
520 MusicSymbol::new_note(vec![], None, Note::A, 2, 1.0, None),
521 ])
522 );
523 }
524
525 #[test]
526 fn tie_with_length() {
527 assert_eq!(
528 abc::music_line("c4-c4").unwrap(),
529 MusicLine::new(vec![
530 MusicSymbol::new_note(vec![], None, Note::C, 2, 4.0, Some(Tie::Solid)),
531 MusicSymbol::new_note(vec![], None, Note::C, 2, 4.0, None)
532 ])
533 );
534 }
535
536 #[test]
537 fn tie_dotted() {
538 assert_eq!(
539 abc::music_line("C.-C").unwrap(),
540 MusicLine::new(vec![
541 MusicSymbol::new_note(vec![], None, Note::C, 1, 1.0, Some(Tie::Dotted)),
542 MusicSymbol::new_note(vec![], None, Note::C, 1, 1.0, None)
543 ])
544 );
545 }
546
547 #[test]
548 fn invalid_tie() {
549 assert!(abc::music_line("c4 -c4").is_err());
550 assert!(abc::music_line("abc|-cba").is_err());
551 }
552
553 macro_rules! assert_rst {
554 ($input:tt, $expected:expr) => {
555 assert_eq!(
556 abc::music_symbol($input).unwrap(),
557 MusicSymbol::Rest($expected)
558 )
559 };
560 }
561
562 #[test]
563 fn rest_1() {
564 assert_rst!("z", Rest::Note(1))
565 }
566 #[test]
567 fn rest_2() {
568 assert_rst!("x", Rest::NoteHidden(1))
569 }
570 #[test]
571 fn rest_3() {
572 assert_rst!("Z", Rest::Measure(1))
573 }
574 #[test]
575 fn rest_4() {
576 assert_rst!("X", Rest::MeasureHidden(1))
577 }
578 #[test]
579 fn rest_5() {
580 assert_rst!("z3", Rest::Note(3))
581 }
582 #[test]
583 fn rest_6() {
584 assert_rst!("Z10", Rest::Measure(10))
585 }
586 #[test]
587 fn rest_7() {
588 assert_rst!("x7", Rest::NoteHidden(7))
589 }
590 #[test]
591 fn rest_8() {
592 assert_rst!("X900", Rest::MeasureHidden(900))
593 }
594
595 #[ignore]
596 #[test]
597 fn endings_general() {
598 let m = abc::music_line("f|[1 d:|[2 d2 B|]").unwrap();
599 assert_eq!(
600 m,
601 MusicLine::new(vec![
602 MusicSymbol::new_note(vec![], None, Note::F, 2, 1.0, None),
603 MusicSymbol::Bar("|".to_string()),
604 MusicSymbol::Ending(1),
605 MusicSymbol::new_note(vec![], None, Note::D, 2, 1.0, None),
606 MusicSymbol::Bar(":|".to_string()),
607 MusicSymbol::Ending(2),
608 MusicSymbol::new_note(vec![], None, Note::D, 2, 2.0, None),
609 MusicSymbol::VisualBreak,
610 MusicSymbol::note(Note::B),
611 MusicSymbol::Bar("|]".to_string())
612 ])
613 );
614 }
615
616 #[test]
617 fn endings_1() {
618 assert_eq!(abc::ending("[1").unwrap(), MusicSymbol::Ending(1))
619 }
620 #[test]
621 fn endings_2() {
622 assert_eq!(abc::ending("[2").unwrap(), MusicSymbol::Ending(2))
623 }
624 #[test]
625 fn endings_3() {
626 assert_eq!(abc::ending("[87654").unwrap(), MusicSymbol::Ending(87654))
627 }
628
629 #[ignore]
630 #[test]
631 fn ending_after_bar() {
632 let m = abc::music_line("|[1").unwrap();
633 assert_eq!(
634 m,
635 MusicLine::new(vec![
636 MusicSymbol::Bar("|".to_string()),
637 MusicSymbol::Ending(1)
638 ])
639 )
640 }
641
642 #[test]
643 fn chord_1() {
644 let c = abc::music_symbol("[CEG]").unwrap();
645 assert_eq!(
646 c,
647 MusicSymbol::Chord {
648 decorations: vec![],
649 notes: vec![
650 MusicSymbol::note(Note::C),
651 MusicSymbol::note(Note::E),
652 MusicSymbol::note(Note::G)
653 ],
654 length: 1.0
655 }
656 );
657 }
658
659 #[test]
660 fn chord_2() {
661 let c = abc::music_symbol("[C2E2G2]3").unwrap();
662 assert_eq!(
663 c,
664 MusicSymbol::Chord {
665 decorations: vec![],
666 notes: vec![
667 MusicSymbol::note_from_length(Note::C, 2.0),
668 MusicSymbol::note_from_length(Note::E, 2.0),
669 MusicSymbol::note_from_length(Note::G, 2.0)
670 ],
671 length: 3.0
672 }
673 );
674 }
675
676 #[test]
677 fn grace_notes_1() {
678 let g = abc::music_symbol("{GdGe}").unwrap();
679 assert_eq!(
680 g,
681 MusicSymbol::GraceNotes {
682 acciaccatura: None,
683 notes: vec![
684 MusicSymbol::note(Note::G),
685 MusicSymbol::new_note(vec![], None, Note::D, 2, 1.0, None),
686 MusicSymbol::note(Note::G),
687 MusicSymbol::new_note(vec![], None, Note::E, 2, 1.0, None)
688 ]
689 }
690 )
691 }
692
693 #[test]
694 fn grace_notes_2() {
695 let g = abc::music_symbol("{/g}").unwrap();
696 assert_eq!(
697 g,
698 MusicSymbol::GraceNotes {
699 acciaccatura: Some(()),
700 notes: vec![MusicSymbol::new_note(vec![], None, Note::G, 2, 1.0, None)]
701 }
702 )
703 }
704
705 macro_rules! assert_tup {
706 ($input:tt, $p:expr, $q:expr, $r:expr, $($expected:expr), *) => {
707 assert_eq!(
708 abc::music_symbol($input).unwrap(),
709 MusicSymbol::Tuplet {
710 p: $p,
711 q: $q,
712 r: $r,
713 notes: vec![
714 $(
715 MusicSymbol::note($expected),
716 )*
717 ]
718 }
719 )
720 };
721 }
722
723 #[test]
724 fn tuplet_1() {
725 assert_tup!("(2AB", 2, 3, 2, Note::A, Note::B)
726 }
727 #[test]
728 fn tuplet_2() {
729 assert_tup!("(2 AB", 2, 3, 2, Note::A, Note::B)
730 }
731 #[test]
732 fn tuplet_3() {
733 assert_tup!("(3ABC", 3, 2, 3, Note::A, Note::B, Note::C)
734 }
735 #[test]
736 fn tuplet_4() {
737 assert_tup!("(3::ABC", 3, 2, 3, Note::A, Note::B, Note::C)
738 }
739 #[test]
740 fn tuplet_5() {
741 assert_tup!("(3:2ABC", 3, 2, 3, Note::A, Note::B, Note::C)
742 }
743 #[test]
744 fn tuplet_6() {
745 assert_tup!("(3:2:3ABC", 3, 2, 3, Note::A, Note::B, Note::C)
746 }
747 #[test]
748 fn tuplet_7() {
749 assert_tup!(
750 "(9ABCDEFGAB",
751 9,
752 0,
753 9,
754 Note::A,
755 Note::B,
756 Note::C,
757 Note::D,
758 Note::E,
759 Note::F,
760 Note::G,
761 Note::A,
762 Note::B
763 )
764 }
765}