mirror of
https://github.com/imjasonh/testscript-rs
synced 2026-07-12 10:58:27 +00:00
improve error messages with context (#13)
Signed-off-by: Jason Hall <jason@chainguard.dev>
This commit is contained in:
parent
38bef8a370
commit
3a8e953f70
5 changed files with 156 additions and 3 deletions
51
src/error.rs
51
src/error.rs
|
|
@ -46,6 +46,16 @@ pub enum Error {
|
|||
/// Generic error with message
|
||||
#[error("{0}")]
|
||||
Generic(String),
|
||||
|
||||
/// Script execution error with context
|
||||
#[error("Error in {script_file} at line {line_num}:\n{context}")]
|
||||
ScriptError {
|
||||
script_file: String,
|
||||
line_num: usize,
|
||||
context: String,
|
||||
#[source]
|
||||
source: Box<Error>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Error {
|
||||
|
|
@ -64,4 +74,45 @@ impl Error {
|
|||
message: message.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a script error with context
|
||||
pub fn script_error(
|
||||
script_file: impl Into<String>,
|
||||
line_num: usize,
|
||||
script_content: &str,
|
||||
source: Error,
|
||||
) -> Self {
|
||||
let context = generate_error_context(script_content, line_num);
|
||||
Error::ScriptError {
|
||||
script_file: script_file.into(),
|
||||
line_num,
|
||||
context,
|
||||
source: Box::new(source),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate error context showing surrounding lines
|
||||
fn generate_error_context(script_content: &str, error_line: usize) -> String {
|
||||
let lines: Vec<&str> = script_content.lines().collect();
|
||||
let mut context = String::new();
|
||||
|
||||
let start = error_line.saturating_sub(3).max(1);
|
||||
let end = (error_line + 2).min(lines.len());
|
||||
|
||||
for line_num in start..=end {
|
||||
if line_num == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let line_content = lines.get(line_num - 1).unwrap_or(&"");
|
||||
|
||||
if line_num == error_line {
|
||||
context.push_str(&format!("> {} | {}\n", line_num, line_content));
|
||||
} else {
|
||||
context.push_str(&format!(" {} | {}\n", line_num, line_content));
|
||||
}
|
||||
}
|
||||
|
||||
context.trim_end().to_string()
|
||||
}
|
||||
|
|
|
|||
26
src/run.rs
26
src/run.rs
|
|
@ -659,7 +659,21 @@ pub fn run_test(script_path: &Path) -> Result<()> {
|
|||
pub fn run_script(script_path: &Path, params: &RunParams) -> Result<()> {
|
||||
// Read and parse the script
|
||||
let content = fs::read_to_string(script_path)?;
|
||||
let script = crate::parser::parse(&content)?;
|
||||
let script = crate::parser::parse(&content).map_err(|e| {
|
||||
// Enhance parse errors with script context
|
||||
match e {
|
||||
Error::Parse { line, message } => Error::script_error(
|
||||
script_path.to_string_lossy().to_string(),
|
||||
line,
|
||||
&content,
|
||||
Error::Parse { line, message },
|
||||
),
|
||||
other => other,
|
||||
}
|
||||
})?;
|
||||
|
||||
// Create script context for better error reporting
|
||||
let script_file = script_path.to_string_lossy().to_string();
|
||||
|
||||
// Create test environment
|
||||
let mut env = TestEnvironment::new()?;
|
||||
|
|
@ -678,7 +692,15 @@ pub fn run_script(script_path: &Path, params: &RunParams) -> Result<()> {
|
|||
|
||||
// Execute commands
|
||||
for command in &script.commands {
|
||||
execute_command(&mut env, command, params)?;
|
||||
if let Err(e) = execute_command(&mut env, command, params) {
|
||||
// Wrap error with script context
|
||||
return Err(Error::script_error(
|
||||
&script_file,
|
||||
command.line_num,
|
||||
&content,
|
||||
e,
|
||||
));
|
||||
}
|
||||
|
||||
// Check for early termination
|
||||
if env.should_skip {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue