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
45pub fn run(script: &str) {
47 let file = ScriptFile::new("<inline>");
48 let parsed =
49 parser::parse_script(file, script).unwrap_or_else(|e| panic!("clitest parse error: {e}"));
50 let output = ScriptOutput::no_color();
51 execute(&parsed, output).unwrap_or_else(|e| panic!("clitest failed: {e}"));
52}
53
54pub fn run_captured(script: &str) -> String {
56 match try_run_captured(script) {
57 Ok(output) => output,
58 Err(e) => panic!("clitest failed: {}\n\nOutput:\n{}", e.error, e.output),
59 }
60}
61
62pub fn try_run_captured(script: &str) -> Result<String, RunError> {
65 let file = ScriptFile::new("<inline>");
66 let parsed = match parser::parse_script(file, script) {
67 Ok(s) => s,
68 Err(e) => {
69 return Err(RunError {
70 error: e.to_string(),
71 output: String::new(),
72 });
73 }
74 };
75 let output = ScriptOutput::quiet(true);
76 match execute(&parsed, output.clone()) {
77 Ok(()) => Ok(output.take_buffer()),
78 Err(e) => Err(RunError {
79 error: e.to_string(),
80 output: output.take_buffer(),
81 }),
82 }
83}
84
85pub fn run_file(path: impl AsRef<Path>) {
87 let file = ScriptFile::new(path);
88 let parsed = parser::parse_script_file(None, file)
89 .unwrap_or_else(|e| panic!("clitest parse error: {:?}", e));
90 let output = ScriptOutput::no_color();
91 execute(&parsed, output).unwrap_or_else(|e| panic!("clitest failed: {e}"));
92}
93
94pub fn run_file_captured(path: impl AsRef<Path>) -> String {
96 match try_run_file_captured(path) {
97 Ok(output) => output,
98 Err(e) => panic!("clitest failed: {}\n\nOutput:\n{}", e.error, e.output),
99 }
100}
101
102pub fn try_run_file_captured(path: impl AsRef<Path>) -> Result<String, RunError> {
105 let file = ScriptFile::new(path);
106 let parsed = match parser::parse_script_file(None, file) {
107 Ok(s) => s,
108 Err(e) => {
109 let msg = e
110 .iter()
111 .map(|e| e.to_string())
112 .collect::<Vec<_>>()
113 .join("\n");
114 return Err(RunError {
115 error: msg,
116 output: String::new(),
117 });
118 }
119 };
120 let output = ScriptOutput::quiet(true);
121 match execute(&parsed, output.clone()) {
122 Ok(()) => Ok(output.take_buffer()),
123 Err(e) => Err(RunError {
124 error: e.to_string(),
125 output: output.take_buffer(),
126 }),
127 }
128}
129
130#[macro_export]
143macro_rules! clitest {
144 ($name:ident, $script:expr) => {
145 #[test]
146 fn $name() {
147 $crate::run(&format!("#!/usr/bin/env clitest --v0\n{}", $script));
148 }
149 };
150}