Skip to content

Commit 9431d81

Browse files
committed
Add side by side diff (partial)
Create the diff -y utility, this time introducing tests and changes focused mainly on the construction of the utility and issues related to alignment and response tabulation. New parameters were introduced such as the size of the total width of the output in the parameters. A new calculation was introduced to determine the size of the output columns and the maximum total column size. The tab and spacing mechanism has the same behavior as the original diff, with tabs and spaces formatted in the same way. - Introducing tests for the diff 'main' function - Introducing fuzzing for side diff utility - Introducing tests for internal mechanisms - Modular functions that allow consistent changes across the entire project
1 parent 1374279 commit 9431d81

File tree

6 files changed

+1327
-136
lines changed

6 files changed

+1327
-136
lines changed

fuzz/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,8 @@ path = "fuzz_targets/fuzz_ed.rs"
4747
test = false
4848
doc = false
4949

50-
50+
[[bin]]
51+
name = "fuzz_side"
52+
path = "fuzz_targets/fuzz_side.rs"
53+
test = false
54+
doc = false

fuzz/fuzz_targets/fuzz_side.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#![no_main]
2+
#[macro_use]
3+
extern crate libfuzzer_sys;
4+
5+
use diffutilslib::side_diff;
6+
7+
use std::fs::File;
8+
use std::io::Write;
9+
use diffutilslib::params::Params;
10+
11+
fuzz_target!(|x: (Vec<u8>, Vec<u8>, /* usize, usize */ bool)| {
12+
let (original, new, /* width, tabsize, */ expand) = x;
13+
14+
// if width == 0 || tabsize == 0 {
15+
// return;
16+
// }
17+
18+
let params = Params {
19+
// width,
20+
// tabsize,
21+
expand_tabs: expand,
22+
..Default::default()
23+
};
24+
let mut output_buf = vec![];
25+
side_diff::diff(&original, &new, &mut output_buf, &params);
26+
File::create("target/fuzz.file.original")
27+
.unwrap()
28+
.write_all(&original)
29+
.unwrap();
30+
File::create("target/fuzz.file.new")
31+
.unwrap()
32+
.write_all(&new)
33+
.unwrap();
34+
File::create("target/fuzz.file")
35+
.unwrap()
36+
.write_all(&original)
37+
.unwrap();
38+
File::create("target/fuzz.diff")
39+
.unwrap()
40+
.write_all(&output_buf)
41+
.unwrap();
42+
});

src/diff.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{context_diff, ed_diff, normal_diff, side_diff, unified_diff};
99
use std::env::ArgsOs;
1010
use std::ffi::OsString;
1111
use std::fs;
12-
use std::io::{self, Read, Write};
12+
use std::io::{self, stdout, Read, Write};
1313
use std::iter::Peekable;
1414
use std::process::{exit, ExitCode};
1515

@@ -79,7 +79,10 @@ pub fn main(opts: Peekable<ArgsOs>) -> ExitCode {
7979
eprintln!("{error}");
8080
exit(2);
8181
}),
82-
Format::SideBySide => side_diff::diff(&from_content, &to_content),
82+
Format::SideBySide => {
83+
let mut output = stdout().lock();
84+
side_diff::diff(&from_content, &to_content, &mut output, &params)
85+
}
8386
};
8487
if params.brief && !result.is_empty() {
8588
println!(

src/params.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub struct Params {
2525
pub brief: bool,
2626
pub expand_tabs: bool,
2727
pub tabsize: usize,
28+
pub width: usize,
2829
}
2930

3031
impl Default for Params {
@@ -39,6 +40,7 @@ impl Default for Params {
3940
brief: false,
4041
expand_tabs: false,
4142
tabsize: 8,
43+
width: 130,
4244
}
4345
}
4446
}
@@ -58,6 +60,7 @@ pub fn parse_params<I: Iterator<Item = OsString>>(mut opts: Peekable<I>) -> Resu
5860
let mut format = None;
5961
let mut context = None;
6062
let tabsize_re = Regex::new(r"^--tabsize=(?<num>\d+)$").unwrap();
63+
let width_re = Regex::new(r"--width=(?P<long>\d+)$").unwrap();
6164
while let Some(param) = opts.next() {
6265
let next_param = opts.peek();
6366
if param == "--" {
@@ -109,6 +112,27 @@ pub fn parse_params<I: Iterator<Item = OsString>>(mut opts: Peekable<I>) -> Resu
109112
format = Some(Format::SideBySide);
110113
continue;
111114
}
115+
if width_re.is_match(param.to_string_lossy().as_ref()) {
116+
let param = param.into_string().unwrap();
117+
let width_str: &str = width_re
118+
.captures(param.as_str())
119+
.unwrap()
120+
.name("long")
121+
.unwrap()
122+
.as_str();
123+
124+
params.width = match width_str.parse::<usize>() {
125+
Ok(num) => {
126+
if num == 0 {
127+
return Err("invalid width «0»".to_string());
128+
}
129+
130+
num
131+
}
132+
Err(_) => return Err(format!("invalid width «{width_str}»")),
133+
};
134+
continue;
135+
}
112136
if tabsize_re.is_match(param.to_string_lossy().as_ref()) {
113137
// Because param matches the regular expression,
114138
// it is safe to assume it is valid UTF-8.
@@ -120,9 +144,16 @@ pub fn parse_params<I: Iterator<Item = OsString>>(mut opts: Peekable<I>) -> Resu
120144
.unwrap()
121145
.as_str();
122146
params.tabsize = match tabsize_str.parse::<usize>() {
123-
Ok(num) => num,
147+
Ok(num) => {
148+
if num == 0 {
149+
return Err("invalid tabsize «0»".to_string());
150+
}
151+
152+
num
153+
}
124154
Err(_) => return Err(format!("invalid tabsize «{tabsize_str}»")),
125155
};
156+
126157
continue;
127158
}
128159
match match_context_diff_params(&param, next_param, format) {
@@ -712,11 +743,11 @@ mod tests {
712743
executable: os("diff"),
713744
from: os("foo"),
714745
to: os("bar"),
715-
tabsize: 0,
746+
tabsize: 1,
716747
..Default::default()
717748
}),
718749
parse_params(
719-
[os("diff"), os("--tabsize=0"), os("foo"), os("bar")]
750+
[os("diff"), os("--tabsize=1"), os("foo"), os("bar")]
720751
.iter()
721752
.cloned()
722753
.peekable()

0 commit comments

Comments
 (0)