1pub mod ast;
8pub mod error;
9pub mod parser;
10
11pub use ast::{Op, Pattern, Refrain};
12pub use error::{RefrainError, Result};
13pub use parser::parse;
14
15#[cfg(test)]
16mod tests {
17 use super::*;
18
19 #[test]
20 fn refrain_constructor_smoke() {
21 let r = Refrain::new("melody-a");
22 assert_eq!(r.name, "melody-a");
23 assert!(r.territorialize.is_none());
24 assert!(r.deterritorialize.is_none());
25 assert!(r.reterritorialize.is_none());
26 }
27
28 #[test]
29 fn ast_serde_roundtrip() {
30 let mut r = Refrain::new("t");
31 r.territorialize = Some(Pattern::Op(Op::Note {
32 pitch: "C4".into(),
33 dur: "q".into(),
34 }));
35 let s = serde_json::to_string(&r).unwrap();
36 let r2: Refrain = serde_json::from_str(&s).unwrap();
37 assert_eq!(r, r2);
38 }
39
40 #[test]
41 fn op_loop_holds_body() {
42 let body = Box::new(Pattern::Op(Op::Note {
43 pitch: "G4".into(),
44 dur: "e".into(),
45 }));
46 let op = Op::Loop { count: 4, body };
47 let s = serde_json::to_string(&op).unwrap();
48 assert!(s.contains("Loop"));
49 assert!(s.contains("\"count\":4"));
50 }
51
52 #[test]
53 fn parser_parses_empty_refrain() {
54 let r = parser::parse("(refrain x)").unwrap();
55 assert_eq!(r.name, "x");
56 assert!(r.territorialize.is_none());
57 }
58}