1pub mod command;
4pub mod output;
5pub mod parser;
6pub mod script;
7pub mod term;
8pub mod util;
9
10use std::path::Path;
11
12use script::{ScriptFile, ScriptOutput, ScriptRunArgs, ScriptRunError};
13
14pub struct RunError {
16 pub error: String,
17 pub output: String,
18}
19
20impl std::fmt::Display for RunError {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 write!(f, "{}", self.error)
23 }
24}
25
26impl std::fmt::Debug for RunError {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 write!(f, "{}", self.error)
29 }
30}
31
32fn make_args() -> ScriptRunArgs {
33 ScriptRunArgs {
34 quiet: true,
35 no_color: true,
36 simplified_output: true,
37 ..Default::default()
38 }
39}
40
41fn execute(parsed: &script::Script, output: ScriptOutput) -> Result<(), ScriptRunError> {
42 parsed.run_with_args(make_args(), output)
43}
44
45fn get_inline_file() -> ScriptFile {
46 ScriptFile::new(std::env::current_dir().unwrap().join("<inline>"))
47}
48
49pub fn run(script: &str) {
51 let file = get_inline_file();
52 let parsed =
53 parser::parse_script(file, script).unwrap_or_else(|e| panic!("clitest parse error: {e}"));
54 let output = ScriptOutput::no_color();
55 execute(&parsed, output).unwrap_or_else(|e| panic!("clitest failed: {e}"));
56}
57
58pub fn run_with_path(path: impl AsRef<Path>, script: &str) {
60 let file = ScriptFile::new(path);
61 let parsed =
62 parser::parse_script(file, script).unwrap_or_else(|e| panic!("clitest parse error: {e}"));
63 let output = ScriptOutput::no_color();
64 execute(&parsed, output).unwrap_or_else(|e| panic!("clitest failed: {e}"));
65}
66
67pub fn run_captured(script: &str) -> String {
69 match try_run_captured(script) {
70 Ok(output) => output,
71 Err(e) => panic!("clitest failed: {}\n\nOutput:\n{}", e.error, e.output),
72 }
73}
74
75pub fn try_run_captured(script: &str) -> Result<String, RunError> {
78 let file = get_inline_file();
79 let parsed = match parser::parse_script(file, script) {
80 Ok(s) => s,
81 Err(e) => {
82 return Err(RunError {
83 error: e.to_string(),
84 output: String::new(),
85 });
86 }
87 };
88 let output = ScriptOutput::quiet(true);
89 match execute(&parsed, output.clone()) {
90 Ok(()) => Ok(output.take_buffer()),
91 Err(e) => Err(RunError {
92 error: e.to_string(),
93 output: output.take_buffer(),
94 }),
95 }
96}
97
98pub fn run_file(path: impl AsRef<Path>) {
100 let file = ScriptFile::new(path);
101 let parsed = parser::parse_script_file(None, file)
102 .unwrap_or_else(|e| panic!("clitest parse error: {:?}", e));
103 let output = ScriptOutput::no_color();
104 execute(&parsed, output).unwrap_or_else(|e| panic!("clitest failed: {e}"));
105}
106
107pub fn run_file_captured(path: impl AsRef<Path>) -> String {
109 match try_run_file_captured(path) {
110 Ok(output) => output,
111 Err(e) => panic!("clitest failed: {}\n\nOutput:\n{}", e.error, e.output),
112 }
113}
114
115pub fn try_run_file_captured(path: impl AsRef<Path>) -> Result<String, RunError> {
118 let file = ScriptFile::new(path);
119 let parsed = match parser::parse_script_file(None, file) {
120 Ok(s) => s,
121 Err(e) => {
122 let msg = e
123 .iter()
124 .map(|e| e.to_string())
125 .collect::<Vec<_>>()
126 .join("\n");
127 return Err(RunError {
128 error: msg,
129 output: String::new(),
130 });
131 }
132 };
133 let output = ScriptOutput::quiet(true);
134 match execute(&parsed, output.clone()) {
135 Ok(()) => Ok(output.take_buffer()),
136 Err(e) => Err(RunError {
137 error: e.to_string(),
138 output: output.take_buffer(),
139 }),
140 }
141}
142
143#[macro_export]
156macro_rules! clitest {
157 ($name:ident, $script:expr) => {
158 #[test]
159 fn $name() {
160 $crate::run_with_path(std::env::current_dir().unwrap(), &format!("#!/usr/bin/env clitest --v0\n{}", $script));
161 }
162 };
163}