1pub mod ast;
11pub mod summary;
12pub mod tier;
13pub mod tool_invocation;
14pub mod wrappers;
15mod convert;
16mod error;
17mod parse;
18
19pub use error::ParseError;
20pub use parse::{parse, parse_to_ast};
21
22#[cfg(test)]
23mod tests {
24 use super::*;
25 use summary::summarise_bash_shape;
26
27 fn roundtrip_program(src: &str) {
28 let program = parse_to_ast(src).expect("parse failed");
29 let json = serde_json::to_string(&program).expect("serialize failed");
30 let restored: ast::Program = serde_json::from_str(&json).expect("deserialize failed");
31 assert_eq!(program, restored, "round-trip mismatch for: {src}");
32 }
33
34 fn roundtrip_shape(src: &str) {
35 let program = parse_to_ast(src).expect("parse failed");
36 let shape = summarise_bash_shape(&program);
37 let json = serde_json::to_string(&shape).expect("serialize shape failed");
38 let restored: summary::BashShape = serde_json::from_str(&json).expect("deserialize shape failed");
39 assert_eq!(shape, restored, "shape round-trip mismatch for: {src}");
40 }
41
42 #[test]
43 fn roundtrip_simple_command() {
44 roundtrip_program("git push --force origin main");
45 }
46
47 #[test]
48 fn roundtrip_pipeline() {
49 roundtrip_program("head -n 20 server.log | tail -3");
50 }
51
52 #[test]
53 fn roundtrip_wrapper_command() {
54 roundtrip_program("timeout 30 git push --force origin main");
55 }
56
57 #[test]
58 fn roundtrip_list_ops() {
59 roundtrip_program("cd /tmp && cargo build --release || echo failed");
60 }
61
62 #[test]
63 fn roundtrip_heredoc() {
64 roundtrip_program("cat <<EOF\nhello world\nEOF");
65 }
66
67 #[test]
68 fn shape_roundtrip_simple() {
69 roundtrip_shape("git push origin main");
70 }
71
72 #[test]
73 fn shape_roundtrip_pipeline() {
74 roundtrip_shape("head -n 20 log | tail -3");
75 }
76
77 #[test]
78 fn shape_roundtrip_wrapper() {
79 roundtrip_shape("timeout 30 git push --force origin main");
80 }
81
82 #[test]
83 fn shape_list_ops_are_strings() {
84 let program = parse_to_ast("make && make install || echo failed").expect("parse");
85 let shape = summarise_bash_shape(&program);
86 assert!(shape.list_ops.iter().any(|op| op == "&&"), "missing &&: {:?}", shape.list_ops);
87 assert!(shape.list_ops.iter().any(|op| op == "||"), "missing ||: {:?}", shape.list_ops);
88 roundtrip_shape("make && make install || echo failed");
89 }
90}