Skip to content

Commit 8a69893

Browse files
author
Gunter Schmidt
committed
Feat: Update Cmp
* use clap parser * internationalization of error and info messages, e.g. --help * moved tests into tests by-util * separated and moved benches * adapted fuzzer * common parser error handling for all modules * some fixes, e.g. error on selection of a directory
1 parent 52d3360 commit 8a69893

31 files changed

Lines changed: 6071 additions & 1384 deletions

Cargo.lock

Lines changed: 271 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,9 @@ feat_common_core = [
6363
"cmp", "diff"
6464
]
6565

66-
# default = ["feat_bench_not_diff"]
67-
# Turn bench for diffutils cmp off
68-
feat_bench_not_cmp = []
6966
# Turn bench for diffutils diff off
7067
feat_bench_not_diff = []
7168

72-
7369
[workspace]
7470
resolver = "3"
7571
members = [
@@ -78,7 +74,7 @@ members = [
7874
# "src/uu/stdbuf/src/libstdbuf",
7975
"src/uudiff",
8076
# "src/uucore_procs",
81-
# "tests/uutests",
77+
"tests/uutests",
8278
# "fuzz", # TODO fuzz
8379
]
8480

@@ -98,7 +94,7 @@ version = "0.5.1"
9894

9995
[workspace.dependencies]
10096
assert_cmd = "2.2.0"
101-
# bytecount = "0.6.9"
97+
bytecount = "0.6.9"
10298
chrono = "0.4.0"
10399
clap = { version = "4.6", features = ["wrap_help", "cargo", "color"] }
104100
const_format = "0.2.35"
@@ -116,22 +112,24 @@ predicates = "3.1.0"
116112
pretty_assertions = "1.4.0"
117113
rand = "0.10.0"
118114
regex = "1.10.4"
119-
115+
rlimit = "0.11.0"
120116
same-file = "1.0.6"
121117
tempfile = "3.27.0"
122118
textwrap = { version = "0.16.1", features = ["terminal_size"] }
123119
thiserror = "2.0.3"
124120
unicode-width = "0.2.0"
125-
uucore = "0.7.0"
126-
uudiff = { package = "uudiff", path = "src/uudiff" }
127-
# sdiff = {package = "uu_sdiff", path = "src/uu/sdiff" }
121+
xattr = "1.3.1"
128122

129123
# Fluent dependencies
130124
fluent = "0.17.0"
131125
fluent-bundle = "0.16.0"
132126
unic-langid = "0.9.6"
133127
fluent-syntax = "0.12.0"
134128

129+
uucore = { version = "0.7.0", features = ["parser-size"]}
130+
uudiff = { package = "uudiff", path = "src/uudiff" }
131+
uutests = { version = "0.5.1", package = "uutests", path = "tests/uutests" }
132+
135133
[dependencies]
136134
# clap_complete = { workspace = true, optional = true }
137135
# clap_mangen = { workspace = true, optional = true }
@@ -160,7 +158,7 @@ predicates.workspace = true
160158
rand.workspace = true
161159
regex.workspace = true
162160
tempfile.workspace = true
163-
# uutests.workspace = true
161+
uutests.workspace = true
164162

165163
[build-dependencies]
166164
phf_codegen.workspace = true

benches/bench-diffutils.rs

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -19,65 +19,6 @@ const NUM_DIFF: u64 = 4;
1919
const MB: u64 = 1_000;
2020
const CHANGE_CHAR: u8 = b'#';
2121

22-
#[cfg(not(feature = "feat_bench_not_cmp"))]
23-
mod diffutils_cmp {
24-
use std::hint::black_box;
25-
26-
use divan::Bencher;
27-
28-
use crate::{FILE_SIZE_KILO_BYTES, binary, prepare::*};
29-
30-
#[divan::bench(args = FILE_SIZE_KILO_BYTES)]
31-
fn cmp_compare_files_equal(bencher: Bencher, kb: u64) {
32-
let (from, to) = get_context().get_test_files_equal(kb);
33-
let cmd = format!("cmp {from} {to}");
34-
let opts = str_to_options(&cmd).into_iter().peekable();
35-
let params = cmp::parse_params(opts).unwrap();
36-
37-
bencher
38-
// .with_inputs(|| prepare::cmp_params_identical_testfiles(lines))
39-
.with_inputs(|| params.clone())
40-
.bench_refs(|params| black_box(cmp::cmp_compare(&params).unwrap()));
41-
}
42-
43-
// bench the actual compare; cmp exits on first difference
44-
#[divan::bench(args = FILE_SIZE_KILO_BYTES)]
45-
fn cmp_compare_files_different(bencher: Bencher, bytes: u64) {
46-
let (from, to) = get_context().get_test_files_different(bytes);
47-
let cmd = format!("cmp {from} {to} -s");
48-
let opts = str_to_options(&cmd).into_iter().peekable();
49-
let params = cmp::parse_params(opts).unwrap();
50-
51-
bencher
52-
// .with_inputs(|| prepare::cmp_params_identical_testfiles(lines))
53-
.with_inputs(|| params.clone())
54-
.bench_refs(|params| black_box(cmp::cmp_compare(&params).unwrap()));
55-
}
56-
57-
// bench original GNU cmp
58-
#[divan::bench(args = FILE_SIZE_KILO_BYTES)]
59-
fn cmd_cmp_gnu_equal(bencher: Bencher, bytes: u64) {
60-
let (from, to) = get_context().get_test_files_equal(bytes);
61-
let args_str = format!("{from} {to}");
62-
bencher
63-
// .with_inputs(|| prepare::cmp_params_identical_testfiles(lines))
64-
.with_inputs(|| args_str.clone())
65-
.bench_refs(|cmd_args| binary::bench_binary("cmp", cmd_args));
66-
}
67-
68-
// bench the compiled release version
69-
#[divan::bench(args = FILE_SIZE_KILO_BYTES)]
70-
fn cmd_cmp_release_equal(bencher: Bencher, bytes: u64) {
71-
let (from, to) = get_context().get_test_files_equal(bytes);
72-
let args_str = format!("cmp {from} {to}");
73-
74-
bencher
75-
// .with_inputs(|| prepare::cmp_params_identical_testfiles(lines))
76-
.with_inputs(|| args_str.clone())
77-
.bench_refs(|cmd_args| binary::bench_binary("target/release/diffutils", cmd_args));
78-
}
79-
}
80-
8122
#[cfg(not(feature = "feat_bench_not_diff"))]
8223
mod diffutils_diff {
8324
// use std::hint::black_box;
@@ -131,24 +72,6 @@ mod parser {
13172

13273
use crate::prepare::str_to_options;
13374

134-
// bench the time it takes to parse the command line arguments
135-
#[divan::bench]
136-
fn cmp_parser(bencher: Bencher) {
137-
let cmd = "cmd file_1.txt file_2.txt -bl n10M --ignore-initial=100KiB:1MiB";
138-
let args = str_to_options(&cmd).into_iter().peekable();
139-
bencher
140-
.with_inputs(|| args.clone())
141-
.bench_values(|data| black_box(cmp::parse_params(data)));
142-
}
143-
144-
// // test the impact on the benchmark if not converting the cmd to Vec<OsString> (doubles for parse)
145-
// #[divan::bench]
146-
// fn cmp_parser_no_prepare() {
147-
// let cmd = "cmd file_1.txt file_2.txt -bl n10M --ignore-initial=100KiB:1MiB";
148-
// let args = str_to_options(&cmd).into_iter().peekable();
149-
// let _ = cmp::parse_params(args);
150-
// }
151-
15275
// bench the time it takes to parse the command line arguments
15376
#[divan::bench]
15477
fn diff_parser(bencher: Bencher) {

fuzz/Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fuzz/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ libfuzzer-sys = "0.4.7"
1313
diffutils = { path = "../" }
1414
uu_cmp = { path = "../src/uu/cmp" }
1515
uu_diff = { path = "../src/uu/diff" }
16+
uudiff = { path = "../src/uudiff" }
1617

1718
# Prevent this from interfering with workspaces
1819
[workspace]

fuzz/fuzz_targets/fuzz_cmp.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
#[macro_use]
33
extern crate libfuzzer_sys;
44

5+
use std::convert::TryFrom;
56
use std::ffi::OsString;
67
use std::fs::File;
78
use std::io::Write;
89

10+
use uu_cmp::params_cmp::Params;
11+
use uudiff::utils::CompareOk;
12+
913
fn os(s: &str) -> OsString {
1014
OsString::from(s)
1115
}
@@ -28,15 +32,23 @@ fuzz_target!(|x: (Vec<u8>, Vec<u8>)| {
2832
.write_all(&to)
2933
.unwrap();
3034

35+
// let params =
36+
// uu_cmp::parse_params(args).unwrap_or_else(|e| panic!("Failed to parse params: {}", e));
37+
let matches = uudiff::clap_localization::handle_clap_result_with_exit_code(
38+
uu_cmp::params_cmp::uu_app(),
39+
args,
40+
2,
41+
)
42+
.unwrap_or_else(|e| panic!("Failed to parse params: {}", e));
3143
let params =
32-
uu_cmp::parse_params(args).unwrap_or_else(|e| panic!("Failed to parse params: {}", e));
33-
let ret = uu_cmp::cmp(&params);
34-
if from == to && !matches!(ret, Ok(uu_cmp::Cmp::Equal)) {
44+
Params::try_from(matches).unwrap_or_else(|e| panic!("Failed to parse params: {}", e));
45+
let ret = uu_cmp::cmp_compare(&params);
46+
if from == to && !matches!(ret, Ok(CompareOk::Equal)) {
3547
panic!(
3648
"target/fuzz.cmp.a and target/fuzz.cmp.b are equal, but cmp returned {:?}.",
3749
ret
3850
);
39-
} else if from != to && !matches!(ret, Ok(uu_cmp::Cmp::Different)) {
51+
} else if from != to && !matches!(ret, Ok(CompareOk::Different)) {
4052
panic!(
4153
"target/fuzz.cmp.a and target/fuzz.cmp.b are different, but cmp returned {:?}.",
4254
ret

fuzz/fuzz_targets/fuzz_cmp_args.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,30 @@
33
extern crate libfuzzer_sys;
44

55
use libfuzzer_sys::Corpus;
6-
use std::ffi::OsString;
6+
use std::{convert::TryFrom, ffi::OsString};
7+
use uu_cmp::params_cmp::Params;
78

89
fn os(s: &str) -> OsString {
910
OsString::from(s)
1011
}
1112

12-
fuzz_target!(|x: Vec<OsString>| -> Corpus {
13-
if x.len() > 6 {
13+
fuzz_target!(|args: Vec<OsString>| -> Corpus {
14+
if args.len() > 6 {
1415
// Make sure we try to parse an option when we get longer args. x[0] will be
1516
// the executable name.
16-
if ![os("-l"), os("-b"), os("-s"), os("-n"), os("-i")].contains(&x[1]) {
17+
if ![os("-l"), os("-b"), os("-s"), os("-n"), os("-i")].contains(&args[1]) {
1718
return Corpus::Reject;
1819
}
1920
}
20-
let _ = uu_cmp::parse_params(x.into_iter().peekable());
21+
// not sure what this does, mostly empty args
22+
// dbg!(&args);
23+
// let _ = uu_cmp::parse_params(x.into_iter().peekable());
24+
if let Ok(matches) = uudiff::clap_localization::handle_clap_result_with_exit_code(
25+
uu_cmp::params_cmp::uu_app(),
26+
args,
27+
2,
28+
) {
29+
let _params = Params::try_from(matches);
30+
}
2131
Corpus::Keep
2232
});

src/uu/cmp/Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ path = "src/main.rs"
2525
path = "src/cmp.rs"
2626

2727
[features]
28-
# default = ["feat_run_binary_bench" ]
28+
default = ["feat_run_binary_bench" ]
2929
# The cmd benchmarks start the binaries and take a lot of runtime on the github checks.
3030
# Only run them locally.
3131
feat_run_binary_bench = []
3232

3333

3434
[dependencies]
35-
# bytecount.workspace = true
35+
bytecount.workspace = true
3636
clap.workspace = true
3737
diff_crate.workspace = true
3838
fluent.workspace = true
@@ -55,3 +55,6 @@ tempfile.workspace = true
5555
# for flamegraph
5656
# debug = true
5757

58+
[[bench]]
59+
name = "cmp_bench"
60+
harness = false

0 commit comments

Comments
 (0)