mirror of
https://github.com/bahdotsh/wrkflw.git
synced 2026-05-18 05:05:35 +02:00
test: add tests for review fixes and clean up dead code
The previous commit fixed a bunch of bugs but left a few loose ends. The next_job() function still had a redundant bounds check that previous_job() already had cleaned up — the .filter() call makes the inner `if workflow_idx >= self.workflows.len()` dead code. Let's not leave half-finished refactors lying around. While at it, add tests for the three behavioral changes that *really* should have had tests from the start: emulation runtime returning Ok on non-zero exit codes, log processor not panicking on multi-byte UTF-8 near bracket boundaries, and step validator correctly rejecting steps with only a name field. Also fix formatting (cargo fmt) and a clippy warning about items defined after the test module.
This commit is contained in:
@@ -827,3 +827,25 @@ pub fn get_tracked_processes() -> Vec<u32> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_nonzero_exit_code_returns_ok() {
|
||||
let runtime = EmulationRuntime::new();
|
||||
let result = runtime
|
||||
.run_container(
|
||||
"alpine:latest",
|
||||
&["exit", "42"],
|
||||
&[],
|
||||
Path::new("."),
|
||||
&[(Path::new("."), Path::new("/github/workspace"))],
|
||||
)
|
||||
.await;
|
||||
|
||||
let output = result.expect("non-zero exit should return Ok, not Err");
|
||||
assert_eq!(output.exit_code, 42);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +308,6 @@ impl App {
|
||||
.filter(|&idx| idx < self.workflows.len());
|
||||
|
||||
if let Some(workflow_idx) = current_workflow_idx {
|
||||
|
||||
if let Some(execution) = &self.workflows[workflow_idx].execution_details {
|
||||
if execution.jobs.is_empty() {
|
||||
return;
|
||||
@@ -340,10 +339,6 @@ impl App {
|
||||
.filter(|&idx| idx < self.workflows.len());
|
||||
|
||||
if let Some(workflow_idx) = current_workflow_idx {
|
||||
if workflow_idx >= self.workflows.len() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(execution) = &self.workflows[workflow_idx].execution_details {
|
||||
if execution.jobs.is_empty() {
|
||||
return;
|
||||
|
||||
@@ -307,3 +307,24 @@ impl Default for LogProcessor {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_multibyte_log_line_does_not_panic() {
|
||||
// Emoji and multi-byte characters near bracket boundaries
|
||||
let entry = LogProcessor::process_log_entry("[🚀] deployed service", "");
|
||||
assert_eq!(entry.log_type, "INFO");
|
||||
|
||||
let entry2 = LogProcessor::process_log_entry("[ñ] latin char", "");
|
||||
assert!(!entry2.timestamp.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_normal_timestamp_extraction() {
|
||||
let entry = LogProcessor::process_log_entry("[12:34:56] some log", "");
|
||||
assert_eq!(entry.timestamp, "12:34:56");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,3 +55,53 @@ pub fn validate_steps(steps: &[Value], job_name: &str, result: &mut ValidationRe
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use wrkflw_models::ValidationResult;
|
||||
|
||||
#[test]
|
||||
fn test_step_with_only_name_is_invalid() {
|
||||
let yaml = r#"
|
||||
- name: "just a name"
|
||||
"#;
|
||||
let steps: Vec<Value> = serde_yaml::from_str(yaml).unwrap();
|
||||
let mut result = ValidationResult::new();
|
||||
validate_steps(&steps, "test-job", &mut result);
|
||||
|
||||
assert!(!result.is_valid);
|
||||
assert!(result
|
||||
.issues
|
||||
.iter()
|
||||
.any(|i| i.contains("Missing required 'uses' or 'run' field")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_step_with_run_is_valid() {
|
||||
let yaml = r#"
|
||||
- name: "build"
|
||||
run: "cargo build"
|
||||
"#;
|
||||
let steps: Vec<Value> = serde_yaml::from_str(yaml).unwrap();
|
||||
let mut result = ValidationResult::new();
|
||||
validate_steps(&steps, "test-job", &mut result);
|
||||
|
||||
assert!(result.is_valid);
|
||||
assert!(result.issues.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_step_with_uses_is_valid() {
|
||||
let yaml = r#"
|
||||
- name: "checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
"#;
|
||||
let steps: Vec<Value> = serde_yaml::from_str(yaml).unwrap();
|
||||
let mut result = ValidationResult::new();
|
||||
validate_steps(&steps, "test-job", &mut result);
|
||||
|
||||
assert!(result.is_valid);
|
||||
assert!(result.issues.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,19 +341,23 @@ async fn main() {
|
||||
let entries = match std::fs::read_dir(&validate_path) {
|
||||
Ok(rd) => rd,
|
||||
Err(e) => {
|
||||
eprintln!("Failed to read directory {}: {}", validate_path.display(), e);
|
||||
eprintln!(
|
||||
"Failed to read directory {}: {}",
|
||||
validate_path.display(),
|
||||
e
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
.filter_map(|entry| entry.ok())
|
||||
.filter(|entry| {
|
||||
entry.path().is_file()
|
||||
&& entry
|
||||
.path()
|
||||
.extension()
|
||||
.is_some_and(|ext| ext == "yml" || ext == "yaml")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
.filter_map(|entry| entry.ok())
|
||||
.filter(|entry| {
|
||||
entry.path().is_file()
|
||||
&& entry
|
||||
.path()
|
||||
.extension()
|
||||
.is_some_and(|ext| ext == "yml" || ext == "yaml")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
println!(
|
||||
"Validating {} workflow file(s) in {}...",
|
||||
@@ -660,15 +664,15 @@ fn list_workflows_and_pipelines(verbose: bool) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
.filter_map(|entry| entry.ok())
|
||||
.filter(|entry| {
|
||||
entry.path().is_file()
|
||||
&& entry
|
||||
.path()
|
||||
.extension()
|
||||
.is_some_and(|ext| ext == "yml" || ext == "yaml")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
.filter_map(|entry| entry.ok())
|
||||
.filter(|entry| {
|
||||
entry.path().is_file()
|
||||
&& entry
|
||||
.path()
|
||||
.extension()
|
||||
.is_some_and(|ext| ext == "yml" || ext == "yaml")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if entries.is_empty() {
|
||||
println!(" No workflow files found in .github/workflows");
|
||||
|
||||
Reference in New Issue
Block a user