1use crate::Origin;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct DiffLine {
6 end_of_file: bool,
7 line: String,
8 new_line_number: Option<u32>,
9 old_line_number: Option<u32>,
10 origin: Origin,
11}
12
13impl DiffLine {
14 #[inline]
16 #[must_use]
17 pub fn new(
18 origin: Origin,
19 line: &str,
20 old_line_number: Option<u32>,
21 new_line_number: Option<u32>,
22 end_of_file: bool,
23 ) -> Self {
24 Self {
25 end_of_file,
26 line: if end_of_file {
28 line.replace("\n\\ No newline at end of file\n", "")
29 }
30 else {
31 String::from(line)
32 },
33 new_line_number,
34 old_line_number,
35 origin,
36 }
37 }
38
39 #[inline]
41 #[must_use]
42 pub const fn origin(&self) -> Origin {
43 self.origin
44 }
45
46 #[inline]
48 #[must_use]
49 pub fn line(&self) -> &str {
50 self.line.as_str()
51 }
52
53 #[inline]
55 #[must_use]
56 pub const fn old_line_number(&self) -> Option<u32> {
57 self.old_line_number
58 }
59
60 #[inline]
62 #[must_use]
63 pub const fn new_line_number(&self) -> Option<u32> {
64 self.new_line_number
65 }
66
67 #[inline]
69 #[must_use]
70 pub const fn end_of_file(&self) -> bool {
71 self.end_of_file
72 }
73
74 pub(crate) fn from(diff_line: &git2::DiffLine<'_>) -> Self {
75 Self::new(
76 Origin::from(diff_line.origin_value()),
77 std::str::from_utf8(diff_line.content()).unwrap_or("<INVALID UTF8>"),
78 diff_line.old_lineno(),
79 diff_line.new_lineno(),
80 diff_line.origin_value() == git2::DiffLineType::ContextEOFNL
81 || diff_line.origin_value() == git2::DiffLineType::AddEOFNL
82 || diff_line.origin_value() == git2::DiffLineType::DeleteEOFNL,
83 )
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use claim::assert_some_eq;
90 use parking_lot::Mutex;
91
92 use super::*;
93
94 fn create_diff_line() -> DiffLine {
95 DiffLine::new(Origin::Addition, "Line", Some(1), Some(2), false)
96 }
97
98 #[test]
99 fn origin() {
100 assert_eq!(create_diff_line().origin(), Origin::Addition);
101 }
102
103 #[test]
104 fn line() {
105 assert_eq!(create_diff_line().line(), "Line");
106 }
107
108 #[test]
109 fn old_line_number() {
110 assert_some_eq!(create_diff_line().old_line_number(), 1);
111 }
112
113 #[test]
114 fn new_line_number() {
115 assert_some_eq!(create_diff_line().new_line_number(), 2);
116 }
117
118 #[test]
119 fn end_of_file() {
120 assert!(!create_diff_line().end_of_file());
121 }
122
123 #[test]
124 fn new_without_end_of_file() {
125 let diff_line = DiffLine::new(
126 Origin::Addition,
127 "This is a line\n\\ No newline at end of file\n",
128 None,
129 None,
130 false,
131 );
132 assert_eq!(diff_line.line(), "This is a line\n\\ No newline at end of file\n");
133 assert!(!diff_line.end_of_file());
134 }
135
136 #[test]
137 fn new_with_end_of_file() {
138 let diff_line = DiffLine::new(
139 Origin::Addition,
140 "This is a line\n\\ No newline at end of file\n",
141 None,
142 None,
143 true,
144 );
145 assert_eq!(diff_line.line(), "This is a line");
146 assert!(diff_line.end_of_file());
147 }
148
149 #[test]
150 fn from_diff_lines() {
151 let diff = git2::Diff::from_buffer(
152 [
153 "diff --git a/file.rs b/file.rs",
154 "index 493c0dd..4e07a6e 100644",
155 "--- a/file.rs",
156 "+++ b/file.rs",
157 "@@ -1,2 +1,2 @@ context",
158 " context",
159 "-deleted",
160 "+added",
161 "",
162 ]
163 .join("\n")
164 .as_bytes(),
165 )
166 .unwrap();
167
168 let lines = Mutex::new(vec![]);
169 diff.print(git2::DiffFormat::Patch, |_, _, diff_line| {
170 lines.lock().push(DiffLine::from(&diff_line));
171 true
172 })
173 .unwrap();
174
175 let file_header = [
176 "diff --git a/file.rs b/file.rs",
177 "index 493c0dd..4e07a6e 100644",
178 "--- a/file.rs",
179 "+++ b/file.rs",
180 "",
181 ]
182 .join("\n");
183 let expected = [
184 DiffLine::new(Origin::Header, file_header.as_str(), None, None, false),
185 DiffLine::new(Origin::Header, "@@ -1,2 +1,2 @@ context\n", None, None, false),
186 DiffLine::new(Origin::Context, "context\n", Some(1), Some(1), false),
187 DiffLine::new(Origin::Deletion, "deleted\n", Some(2), None, false),
188 DiffLine::new(Origin::Addition, "added\n", None, Some(2), false),
189 ];
190 assert_eq!(lines.into_inner(), expected);
191 }
192}