use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FixupMode {
Preview,
Apply,
}
impl FixupMode {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Preview => "preview",
Self::Apply => "apply",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DiffHunk {
pub start: usize,
pub remove_count: usize,
pub add_count: usize,
pub remove_lines: Vec<String>,
pub add_lines: Vec<String>,
pub old_range: (usize, usize),
pub new_range: (usize, usize),
pub content: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnifiedDiff {
pub path: String,
pub target_file: String,
pub diff_content: String,
pub hunks: Vec<DiffHunk>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ChangeSummary {
pub hunk_count: usize,
pub lines_added: usize,
pub lines_removed: usize,
pub validation_passed: bool,
pub validation_messages: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AppliedFile {
pub path: String,
pub blake3_first8: String,
pub applied: bool,
pub warnings: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FixupPreview {
pub target_files: Vec<String>,
pub change_summary: HashMap<String, ChangeSummary>,
pub warnings: Vec<String>,
pub all_valid: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FixupResult {
pub applied_files: Vec<AppliedFile>,
pub failed_files: Vec<String>,
pub warnings: Vec<String>,
pub three_way_used: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fixup_mode() {
let preview = FixupMode::Preview;
let apply = FixupMode::Apply;
assert_eq!(preview, FixupMode::Preview);
assert_eq!(apply, FixupMode::Apply);
assert_ne!(preview, apply);
}
#[test]
fn test_diff_hunk() {
let hunk = DiffHunk {
start: 10,
remove_count: 2,
add_count: 3,
remove_lines: vec!["old line 1".to_string(), "old line 2".to_string()],
add_lines: vec![
"new line 1".to_string(),
"new line 2".to_string(),
"new line 3".to_string(),
],
old_range: (10, 2),
new_range: (10, 3),
content:
"@@ -10,2 +10,3 @@\n-old line 1\n-old line 2\n+new line 1\n+new line 2\n+new line 3"
.to_string(),
};
assert_eq!(hunk.start, 10);
assert_eq!(hunk.remove_count, 2);
assert_eq!(hunk.add_count, 3);
assert_eq!(hunk.remove_lines.len(), 2);
assert_eq!(hunk.add_lines.len(), 3);
assert_eq!(hunk.old_range, (10, 2));
assert_eq!(hunk.new_range, (10, 3));
}
#[test]
fn test_unified_diff() {
let hunk = DiffHunk {
start: 1,
remove_count: 1,
add_count: 1,
remove_lines: vec!["old".to_string()],
add_lines: vec!["new".to_string()],
old_range: (1, 1),
new_range: (1, 1),
content: "@@ -1,1 +1,1 @@\n-old\n+new".to_string(),
};
let diff = UnifiedDiff {
path: "a/src/main.rs".to_string(),
target_file: "src/main.rs".to_string(),
diff_content: "--- a/src/main.rs\n+++ b/src/main.rs\n@@ -1,1 +1,1 @@\n-old\n+new"
.to_string(),
hunks: vec![hunk],
};
assert_eq!(diff.path, "a/src/main.rs");
assert_eq!(diff.target_file, "src/main.rs");
assert_eq!(diff.hunks.len(), 1);
}
#[test]
fn test_change_summary() {
let summary = ChangeSummary {
hunk_count: 2,
lines_added: 5,
lines_removed: 3,
validation_passed: true,
validation_messages: vec![],
};
assert_eq!(summary.hunk_count, 2);
assert_eq!(summary.lines_added, 5);
assert_eq!(summary.lines_removed, 3);
assert!(summary.validation_passed);
}
#[test]
fn test_applied_file() {
let applied = AppliedFile {
path: "src/main.rs".to_string(),
blake3_first8: "a1b2c3d4".to_string(),
applied: true,
warnings: vec![],
};
assert_eq!(applied.path, "src/main.rs");
assert_eq!(applied.blake3_first8, "a1b2c3d4");
assert!(applied.applied);
}
#[test]
fn test_fixup_preview() {
let mut summary = HashMap::new();
summary.insert(
"src/main.rs".to_string(),
ChangeSummary {
hunk_count: 1,
lines_added: 2,
lines_removed: 1,
validation_passed: true,
validation_messages: vec![],
},
);
let preview = FixupPreview {
target_files: vec!["src/main.rs".to_string()],
change_summary: summary,
warnings: vec![],
all_valid: true,
};
assert_eq!(preview.target_files.len(), 1);
assert!(preview.all_valid);
assert!(preview.change_summary.contains_key("src/main.rs"));
}
#[test]
fn test_fixup_result() {
let result = FixupResult {
applied_files: vec![AppliedFile {
path: "src/main.rs".to_string(),
blake3_first8: "a1b2c3d4".to_string(),
applied: true,
warnings: vec![],
}],
failed_files: vec![],
warnings: vec![],
three_way_used: false,
};
assert_eq!(result.applied_files.len(), 1);
assert_eq!(result.failed_files.len(), 0);
assert!(!result.three_way_used);
}
}