1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-08-06 16:07:47 +00:00

Merge branch 'uutils:main' into mkdir-fix

This commit is contained in:
Pyokyeong Son 2022-02-18 14:04:16 +09:00 committed by GitHub
commit 6db5bf1652
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
69 changed files with 1051 additions and 1191 deletions

View file

@ -349,6 +349,10 @@ $ make UTILS='UTILITY_1 UTILITY_2' RUNTEST_ARGS='-v' busytest
### Comparing with GNU
Below is the evolution of how many GNU tests uutils passes. A more detailed
breakdown of the GNU test results of the main branch can be found
[in the user manual](https://uutils.github.io/coreutils-docs/user/test_coverage.html).
![Evolution over time](https://github.com/uutils/coreutils-tracking/blob/main/gnu-results.png?raw=true)
To run locally:

View file

@ -7,9 +7,6 @@
// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat seekable
#[cfg(test)]
mod dd_unit_tests;
mod datastructures;
use datastructures::*;
@ -1193,3 +1190,454 @@ General-Flags
")
)
}
#[cfg(test)]
mod tests {
use crate::datastructures::{IConvFlags, IFlags, OConvFlags};
use crate::ReadStat;
use crate::{block, calc_bsize, unblock, uu_app, Input, Output, OutputTrait};
use std::cmp;
use std::fs;
use std::fs::File;
use std::io;
use std::io::{BufReader, Read};
struct LazyReader<R: Read> {
src: R,
}
impl<R: Read> Read for LazyReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let reduced = cmp::max(buf.len() / 2, 1);
self.src.read(&mut buf[..reduced])
}
}
const NEWLINE: u8 = b'\n';
const SPACE: u8 = b' ';
#[test]
fn block_test_no_nl() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, 3u8];
let res = block(&buf, 4, &mut rs);
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, 3u8],]);
}
#[test]
fn block_test_no_nl_short_record() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, 3u8];
let res = block(&buf, 8, &mut rs);
assert_eq!(
res,
vec![vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],]
);
}
#[test]
fn block_test_no_nl_trunc() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, 3u8, 4u8];
let res = block(&buf, 4, &mut rs);
// Commented section(s) should be truncated and appear for reference only.
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, 3u8 /*, 4u8*/],]);
assert_eq!(rs.records_truncated, 1);
}
#[test]
fn block_test_nl_gt_cbs_trunc() {
let mut rs = ReadStat::default();
let buf = [
0u8, 1u8, 2u8, 3u8, 4u8, NEWLINE, 0u8, 1u8, 2u8, 3u8, 4u8, NEWLINE, 5u8, 6u8, 7u8, 8u8,
];
let res = block(&buf, 4, &mut rs);
assert_eq!(
res,
vec![
// Commented section(s) should be truncated and appear for reference only.
vec![0u8, 1u8, 2u8, 3u8],
// vec![4u8, SPACE, SPACE, SPACE],
vec![0u8, 1u8, 2u8, 3u8],
// vec![4u8, SPACE, SPACE, SPACE],
vec![5u8, 6u8, 7u8, 8u8],
]
);
assert_eq!(rs.records_truncated, 2);
}
#[test]
fn block_test_surrounded_nl() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, 3u8, NEWLINE, 4u8, 5u8, 6u8, 7u8, 8u8];
let res = block(&buf, 8, &mut rs);
assert_eq!(
res,
vec![
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
vec![4u8, 5u8, 6u8, 7u8, 8u8, SPACE, SPACE, SPACE],
]
);
}
#[test]
fn block_test_multiple_nl_same_cbs_block() {
let mut rs = ReadStat::default();
let buf = [
0u8, 1u8, 2u8, 3u8, NEWLINE, 4u8, NEWLINE, 5u8, 6u8, 7u8, 8u8, 9u8,
];
let res = block(&buf, 8, &mut rs);
assert_eq!(
res,
vec![
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
vec![4u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
vec![5u8, 6u8, 7u8, 8u8, 9u8, SPACE, SPACE, SPACE],
]
);
}
#[test]
fn block_test_multiple_nl_diff_cbs_block() {
let mut rs = ReadStat::default();
let buf = [
0u8, 1u8, 2u8, 3u8, NEWLINE, 4u8, 5u8, 6u8, 7u8, NEWLINE, 8u8, 9u8,
];
let res = block(&buf, 8, &mut rs);
assert_eq!(
res,
vec![
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
vec![4u8, 5u8, 6u8, 7u8, SPACE, SPACE, SPACE, SPACE],
vec![8u8, 9u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
]
);
}
#[test]
fn block_test_end_nl_diff_cbs_block() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, 3u8, NEWLINE];
let res = block(&buf, 4, &mut rs);
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, 3u8],]);
}
#[test]
fn block_test_end_nl_same_cbs_block() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, NEWLINE];
let res = block(&buf, 4, &mut rs);
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, SPACE]]);
}
#[test]
fn block_test_double_end_nl() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, NEWLINE, NEWLINE];
let res = block(&buf, 4, &mut rs);
assert_eq!(
res,
vec![vec![0u8, 1u8, 2u8, SPACE], vec![SPACE, SPACE, SPACE, SPACE],]
);
}
#[test]
fn block_test_start_nl() {
let mut rs = ReadStat::default();
let buf = [NEWLINE, 0u8, 1u8, 2u8, 3u8];
let res = block(&buf, 4, &mut rs);
assert_eq!(
res,
vec![vec![SPACE, SPACE, SPACE, SPACE], vec![0u8, 1u8, 2u8, 3u8],]
);
}
#[test]
fn block_test_double_surrounded_nl_no_trunc() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, 3u8, NEWLINE, NEWLINE, 4u8, 5u8, 6u8, 7u8];
let res = block(&buf, 8, &mut rs);
assert_eq!(
res,
vec![
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
vec![SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
vec![4u8, 5u8, 6u8, 7u8, SPACE, SPACE, SPACE, SPACE],
]
);
}
#[test]
fn block_test_double_surrounded_nl_double_trunc() {
let mut rs = ReadStat::default();
let buf = [
0u8, 1u8, 2u8, 3u8, NEWLINE, NEWLINE, 4u8, 5u8, 6u8, 7u8, 8u8,
];
let res = block(&buf, 4, &mut rs);
assert_eq!(
res,
vec![
// Commented section(s) should be truncated and appear for reference only.
vec![0u8, 1u8, 2u8, 3u8],
vec![SPACE, SPACE, SPACE, SPACE],
vec![4u8, 5u8, 6u8, 7u8 /*, 8u8*/],
]
);
assert_eq!(rs.records_truncated, 1);
}
#[test]
fn unblock_test_full_cbs() {
let buf = [0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8];
let res = unblock(&buf, 8);
assert_eq!(res, vec![0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, NEWLINE],);
}
#[test]
fn unblock_test_all_space() {
let buf = [SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE];
let res = unblock(&buf, 8);
assert_eq!(res, vec![NEWLINE],);
}
#[test]
fn unblock_test_decoy_spaces() {
let buf = [0u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, 7u8];
let res = unblock(&buf, 8);
assert_eq!(
res,
vec![0u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, 7u8, NEWLINE],
);
}
#[test]
fn unblock_test_strip_single_cbs() {
let buf = [0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE];
let res = unblock(&buf, 8);
assert_eq!(res, vec![0u8, 1u8, 2u8, 3u8, NEWLINE],);
}
#[test]
fn unblock_test_strip_multi_cbs() {
let buf = vec![
vec![0u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
vec![0u8, 1u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
vec![0u8, 1u8, 2u8, SPACE, SPACE, SPACE, SPACE, SPACE],
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
]
.into_iter()
.flatten()
.collect::<Vec<_>>();
let res = unblock(&buf, 8);
let exp = vec![
vec![0u8, NEWLINE],
vec![0u8, 1u8, NEWLINE],
vec![0u8, 1u8, 2u8, NEWLINE],
vec![0u8, 1u8, 2u8, 3u8, NEWLINE],
]
.into_iter()
.flatten()
.collect::<Vec<_>>();
assert_eq!(res, exp);
}
#[test]
fn bsize_test_primes() {
let (n, m) = (7901, 7919);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, n * m);
}
#[test]
fn bsize_test_rel_prime_obs_greater() {
let (n, m) = (7 * 5119, 13 * 5119);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, 7 * 13 * 5119);
}
#[test]
fn bsize_test_rel_prime_ibs_greater() {
let (n, m) = (13 * 5119, 7 * 5119);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, 7 * 13 * 5119);
}
#[test]
fn bsize_test_3fac_rel_prime() {
let (n, m) = (11 * 13 * 5119, 7 * 11 * 5119);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, 7 * 11 * 13 * 5119);
}
#[test]
fn bsize_test_ibs_greater() {
let (n, m) = (512 * 1024, 256 * 1024);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, n);
}
#[test]
fn bsize_test_obs_greater() {
let (n, m) = (256 * 1024, 512 * 1024);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, m);
}
#[test]
fn bsize_test_bs_eq() {
let (n, m) = (1024, 1024);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, m);
}
#[test]
#[should_panic]
fn test_nocreat_causes_failure_when_ofile_doesnt_exist() {
let args = vec![
String::from("dd"),
String::from("--conv=nocreat"),
String::from("--of=not-a-real.file"),
];
let matches = uu_app().try_get_matches_from(args).unwrap();
let _ = Output::<File>::new(&matches).unwrap();
}
#[test]
fn test_deadbeef_16_delayed() {
let input = Input {
src: LazyReader {
src: File::open("./test-resources/deadbeef-16.test").unwrap(),
},
non_ascii: false,
ibs: 16,
print_level: None,
count: None,
cflags: IConvFlags {
sync: Some(0),
..IConvFlags::default()
},
iflags: IFlags::default(),
};
let output = Output {
dst: File::create("./test-resources/FAILED-deadbeef-16-delayed.test").unwrap(),
obs: 32,
cflags: OConvFlags::default(),
};
output.dd_out(input).unwrap();
let tmp_fname = "./test-resources/FAILED-deadbeef-16-delayed.test";
let spec = File::open("./test-resources/deadbeef-16.spec").unwrap();
let res = File::open(tmp_fname).unwrap();
// Check test file isn't empty (unless spec file is too)
assert_eq!(
res.metadata().unwrap().len(),
spec.metadata().unwrap().len()
);
let spec = BufReader::new(spec);
let res = BufReader::new(res);
// Check all bytes match
for (b_res, b_spec) in res.bytes().zip(spec.bytes()) {
assert_eq!(b_res.unwrap(), b_spec.unwrap());
}
fs::remove_file(tmp_fname).unwrap();
}
#[test]
fn test_random_73k_test_lazy_fullblock() {
let input = Input {
src: LazyReader {
src: File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test")
.unwrap(),
},
non_ascii: false,
ibs: 521,
print_level: None,
count: None,
cflags: IConvFlags::default(),
iflags: IFlags {
fullblock: true,
..IFlags::default()
},
};
let output = Output {
dst: File::create("./test-resources/FAILED-random_73k_test_lazy_fullblock.test")
.unwrap(),
obs: 1031,
cflags: OConvFlags::default(),
};
output.dd_out(input).unwrap();
let tmp_fname = "./test-resources/FAILED-random_73k_test_lazy_fullblock.test";
let spec =
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap();
let res = File::open(tmp_fname).unwrap();
// Check test file isn't empty (unless spec file is too)
assert_eq!(
res.metadata().unwrap().len(),
spec.metadata().unwrap().len()
);
let spec = BufReader::new(spec);
let res = BufReader::new(res);
// Check all bytes match
for (b_res, b_spec) in res.bytes().zip(spec.bytes()) {
assert_eq!(b_res.unwrap(), b_spec.unwrap());
}
fs::remove_file(tmp_fname).unwrap();
}
}

View file

@ -1,351 +0,0 @@
// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat
use super::*;
#[cfg(unix)]
macro_rules! make_block_test (
( $test_id:ident, $test_name:expr, $src:expr, $block:expr, $spec:expr ) =>
{
make_spec_test!($test_id,
$test_name,
Input {
src: $src,
non_ascii: false,
ibs: 512,
print_level: None,
count: None,
cflags: IConvFlags {
block: $block,
..IConvFlags::default()
},
iflags: IFlags::default(),
},
Output {
dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(),
obs: 512,
cflags: OConvFlags::default(),
},
$spec,
format!("./test-resources/FAILED-{}.test", $test_name)
);
};
);
#[cfg(unix)]
macro_rules! make_unblock_test (
( $test_id:ident, $test_name:expr, $src:expr, $unblock:expr, $spec:expr ) =>
{
make_spec_test!($test_id,
$test_name,
Input {
src: $src,
non_ascii: false,
ibs: 512,
print_level: None,
count: None,
cflags: IConvFlags {
unblock: $unblock,
..IConvFlags::default()
},
iflags: IFlags::default(),
},
Output {
dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(),
obs: 512,
cflags: OConvFlags::default(),
},
$spec,
format!("./test-resources/FAILED-{}.test", $test_name)
);
};
);
#[test]
fn block_test_no_nl() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, 3u8];
let res = block(&buf, 4, &mut rs);
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, 3u8],]);
}
#[test]
fn block_test_no_nl_short_record() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, 3u8];
let res = block(&buf, 8, &mut rs);
assert_eq!(
res,
vec![vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],]
);
}
#[test]
fn block_test_no_nl_trunc() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, 3u8, 4u8];
let res = block(&buf, 4, &mut rs);
// Commented section(s) should be truncated and appear for reference only.
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, 3u8 /*, 4u8*/],]);
assert_eq!(rs.records_truncated, 1);
}
#[test]
fn block_test_nl_gt_cbs_trunc() {
let mut rs = ReadStat::default();
let buf = [
0u8, 1u8, 2u8, 3u8, 4u8, NEWLINE, 0u8, 1u8, 2u8, 3u8, 4u8, NEWLINE, 5u8, 6u8, 7u8, 8u8,
];
let res = block(&buf, 4, &mut rs);
assert_eq!(
res,
vec![
// Commented section(s) should be truncated and appear for reference only.
vec![0u8, 1u8, 2u8, 3u8],
// vec![4u8, SPACE, SPACE, SPACE],
vec![0u8, 1u8, 2u8, 3u8],
// vec![4u8, SPACE, SPACE, SPACE],
vec![5u8, 6u8, 7u8, 8u8],
]
);
assert_eq!(rs.records_truncated, 2);
}
#[test]
fn block_test_surrounded_nl() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, 3u8, NEWLINE, 4u8, 5u8, 6u8, 7u8, 8u8];
let res = block(&buf, 8, &mut rs);
assert_eq!(
res,
vec![
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
vec![4u8, 5u8, 6u8, 7u8, 8u8, SPACE, SPACE, SPACE],
]
);
}
#[test]
fn block_test_multiple_nl_same_cbs_block() {
let mut rs = ReadStat::default();
let buf = [
0u8, 1u8, 2u8, 3u8, NEWLINE, 4u8, NEWLINE, 5u8, 6u8, 7u8, 8u8, 9u8,
];
let res = block(&buf, 8, &mut rs);
assert_eq!(
res,
vec![
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
vec![4u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
vec![5u8, 6u8, 7u8, 8u8, 9u8, SPACE, SPACE, SPACE],
]
);
}
#[test]
fn block_test_multiple_nl_diff_cbs_block() {
let mut rs = ReadStat::default();
let buf = [
0u8, 1u8, 2u8, 3u8, NEWLINE, 4u8, 5u8, 6u8, 7u8, NEWLINE, 8u8, 9u8,
];
let res = block(&buf, 8, &mut rs);
assert_eq!(
res,
vec![
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
vec![4u8, 5u8, 6u8, 7u8, SPACE, SPACE, SPACE, SPACE],
vec![8u8, 9u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
]
);
}
#[test]
fn block_test_end_nl_diff_cbs_block() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, 3u8, NEWLINE];
let res = block(&buf, 4, &mut rs);
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, 3u8],]);
}
#[test]
fn block_test_end_nl_same_cbs_block() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, NEWLINE];
let res = block(&buf, 4, &mut rs);
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, SPACE]]);
}
#[test]
fn block_test_double_end_nl() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, NEWLINE, NEWLINE];
let res = block(&buf, 4, &mut rs);
assert_eq!(
res,
vec![vec![0u8, 1u8, 2u8, SPACE], vec![SPACE, SPACE, SPACE, SPACE],]
);
}
#[test]
fn block_test_start_nl() {
let mut rs = ReadStat::default();
let buf = [NEWLINE, 0u8, 1u8, 2u8, 3u8];
let res = block(&buf, 4, &mut rs);
assert_eq!(
res,
vec![vec![SPACE, SPACE, SPACE, SPACE], vec![0u8, 1u8, 2u8, 3u8],]
);
}
#[test]
fn block_test_double_surrounded_nl_no_trunc() {
let mut rs = ReadStat::default();
let buf = [0u8, 1u8, 2u8, 3u8, NEWLINE, NEWLINE, 4u8, 5u8, 6u8, 7u8];
let res = block(&buf, 8, &mut rs);
assert_eq!(
res,
vec![
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
vec![SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
vec![4u8, 5u8, 6u8, 7u8, SPACE, SPACE, SPACE, SPACE],
]
);
}
#[test]
fn block_test_double_surrounded_nl_double_trunc() {
let mut rs = ReadStat::default();
let buf = [
0u8, 1u8, 2u8, 3u8, NEWLINE, NEWLINE, 4u8, 5u8, 6u8, 7u8, 8u8,
];
let res = block(&buf, 4, &mut rs);
assert_eq!(
res,
vec![
// Commented section(s) should be truncated and appear for reference only.
vec![0u8, 1u8, 2u8, 3u8],
vec![SPACE, SPACE, SPACE, SPACE],
vec![4u8, 5u8, 6u8, 7u8 /*, 8u8*/],
]
);
assert_eq!(rs.records_truncated, 1);
}
#[cfg(unix)]
make_block_test!(
block_cbs16,
"block-cbs-16",
File::open("./test-resources/dd-block-cbs16.test").unwrap(),
Some(16),
File::open("./test-resources/dd-block-cbs16.spec").unwrap()
);
#[cfg(unix)]
make_block_test!(
block_cbs16_as_cbs8,
"block-cbs-16-as-cbs8",
File::open("./test-resources/dd-block-cbs16.test").unwrap(),
Some(8),
File::open("./test-resources/dd-block-cbs8.spec").unwrap()
);
#[cfg(unix)]
make_block_test!(
block_consecutive_nl,
"block-consecutive-nl",
File::open("./test-resources/dd-block-consecutive-nl.test").unwrap(),
Some(16),
File::open("./test-resources/dd-block-consecutive-nl-cbs16.spec").unwrap()
);
#[test]
fn unblock_test_full_cbs() {
let buf = [0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8];
let res = unblock(&buf, 8);
assert_eq!(res, vec![0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, NEWLINE],);
}
#[test]
fn unblock_test_all_space() {
let buf = [SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE];
let res = unblock(&buf, 8);
assert_eq!(res, vec![NEWLINE],);
}
#[test]
fn unblock_test_decoy_spaces() {
let buf = [0u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, 7u8];
let res = unblock(&buf, 8);
assert_eq!(
res,
vec![0u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, 7u8, NEWLINE],
);
}
#[test]
fn unblock_test_strip_single_cbs() {
let buf = [0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE];
let res = unblock(&buf, 8);
assert_eq!(res, vec![0u8, 1u8, 2u8, 3u8, NEWLINE],);
}
#[test]
fn unblock_test_strip_multi_cbs() {
let buf = vec![
vec![0u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
vec![0u8, 1u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
vec![0u8, 1u8, 2u8, SPACE, SPACE, SPACE, SPACE, SPACE],
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
]
.into_iter()
.flatten()
.collect::<Vec<_>>();
let res = unblock(&buf, 8);
let exp = vec![
vec![0u8, NEWLINE],
vec![0u8, 1u8, NEWLINE],
vec![0u8, 1u8, 2u8, NEWLINE],
vec![0u8, 1u8, 2u8, 3u8, NEWLINE],
]
.into_iter()
.flatten()
.collect::<Vec<_>>();
assert_eq!(res, exp);
}
#[cfg(unix)]
make_unblock_test!(
unblock_multi_16,
"unblock-multi-16",
File::open("./test-resources/dd-unblock-cbs16.test").unwrap(),
Some(16),
File::open("./test-resources/dd-unblock-cbs16.spec").unwrap()
);
#[cfg(unix)]
make_unblock_test!(
unblock_multi_16_as_8,
"unblock-multi-16-as-8",
File::open("./test-resources/dd-unblock-cbs16.test").unwrap(),
Some(8),
File::open("./test-resources/dd-unblock-cbs8.spec").unwrap()
);

View file

@ -1,106 +0,0 @@
// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat
use super::*;
macro_rules! make_sync_test (
( $test_id:ident, $test_name:expr, $src:expr, $sync:expr, $ibs:expr, $obs:expr, $spec:expr ) =>
{
make_spec_test!($test_id,
$test_name,
Input {
src: $src,
non_ascii: false,
ibs: $ibs,
print_level: None,
count: None,
cflags: IConvFlags {
sync: $sync,
..IConvFlags::default()
},
iflags: IFlags::default(),
},
Output {
dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(),
obs: $obs,
cflags: OConvFlags::default(),
},
$spec,
format!("./test-resources/FAILED-{}.test", $test_name)
);
};
);
// Zeros
make_sync_test!(
zeros_4k_conv_sync_obs_gt_ibs,
"zeros_4k_conv_sync_obs_gt_ibs",
File::open("./test-resources/zeros-620f0b67a91f7f74151bc5be745b7110.test").unwrap(),
Some(0u8),
521,
1031,
File::open("./test-resources/gnudd-conv-sync-ibs-521-obs-1031-zeros.spec").unwrap()
);
make_sync_test!(
zeros_4k_conv_sync_ibs_gt_obs,
"zeros_4k_conv_sync_ibs_gt_obs",
File::open("./test-resources/zeros-620f0b67a91f7f74151bc5be745b7110.test").unwrap(),
Some(0u8),
1031,
521,
File::open("./test-resources/gnudd-conv-sync-ibs-1031-obs-521-zeros.spec").unwrap()
);
// Deadbeef
make_sync_test!(
deadbeef_32k_conv_sync_obs_gt_ibs,
"deadbeef_32k_conv_sync_obs_gt_ibs",
File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap(),
Some(0u8),
521,
1031,
File::open("./test-resources/gnudd-conv-sync-ibs-521-obs-1031-deadbeef.spec").unwrap()
);
make_sync_test!(
deadbeef_32k_conv_sync_ibs_gt_obs,
"deadbeef_32k_conv_sync_ibs_gt_obs",
File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap(),
Some(0u8),
1031,
521,
File::open("./test-resources/gnudd-conv-sync-ibs-1031-obs-521-deadbeef.spec").unwrap()
);
// Random
make_sync_test!(
random_73k_test_bs_prime_obs_gt_ibs_sync,
"random-73k-test-bs-prime-obs-gt-ibs-sync",
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
Some(0u8),
521,
1031,
File::open("./test-resources/gnudd-conv-sync-ibs-521-obs-1031-random.spec").unwrap()
);
make_sync_test!(
random_73k_test_bs_prime_ibs_gt_obs_sync,
"random-73k-test-bs-prime-ibs-gt-obs-sync",
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
Some(0u8),
1031,
521,
File::open("./test-resources/gnudd-conv-sync-ibs-1031-obs-521-random.spec").unwrap()
);
make_sync_test!(
deadbeef_16_delayed,
"deadbeef-16-delayed",
LazyReader {
src: File::open("./test-resources/deadbeef-16.test").unwrap()
},
Some(0u8),
16,
32,
File::open("./test-resources/deadbeef-16.spec").unwrap()
);

View file

@ -1,233 +0,0 @@
// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat
use super::*;
macro_rules! make_conv_test (
( $test_id:ident, $test_name:expr, $src:expr, $ctable:expr, $spec:expr ) =>
{
make_spec_test!($test_id,
$test_name,
Input {
src: $src,
non_ascii: false,
ibs: 512,
print_level: None,
count: None,
cflags: icf!($ctable),
iflags: IFlags::default(),
},
Output {
dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(),
obs: 512,
cflags: OConvFlags::default(),
},
$spec,
format!("./test-resources/FAILED-{}.test", $test_name)
);
};
);
macro_rules! make_icf_test (
( $test_id:ident, $test_name:expr, $src:expr, $icf:expr, $spec:expr ) =>
{
make_spec_test!($test_id,
$test_name,
Input {
src: $src,
non_ascii: false,
ibs: 512,
print_level: None,
count: None,
cflags: $icf,
iflags: IFlags::default(),
},
Output {
dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(),
obs: 512,
cflags: OConvFlags::default(),
},
$spec,
format!("./test-resources/FAILED-{}.test", $test_name)
);
};
);
make_conv_test!(
atoe_conv_spec_test,
"atoe-conv-spec-test",
File::open("./test-resources/seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test").unwrap(),
Some(&ASCII_TO_EBCDIC),
File::open("./test-resources/gnudd-conv-atoe-seq-byte-values.spec").unwrap()
);
make_conv_test!(
etoa_conv_spec_test,
"etoa-conv-spec-test",
File::open("./test-resources/seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test").unwrap(),
Some(&EBCDIC_TO_ASCII),
File::open("./test-resources/gnudd-conv-etoa-seq-byte-values.spec").unwrap()
);
make_conv_test!(
atoibm_conv_spec_test,
"atoibm-conv-spec-test",
File::open("./test-resources/seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test").unwrap(),
Some(&ASCII_TO_IBM),
File::open("./test-resources/gnudd-conv-atoibm-seq-byte-values.spec").unwrap()
);
make_conv_test!(
lcase_ascii_to_ucase_ascii,
"lcase_ascii_to_ucase_ascii",
File::open("./test-resources/lcase-ascii.test").unwrap(),
Some(&ASCII_LCASE_TO_UCASE),
File::open("./test-resources/ucase-ascii.test").unwrap()
);
make_conv_test!(
ucase_ascii_to_lcase_ascii,
"ucase_ascii_to_lcase_ascii",
File::open("./test-resources/ucase-ascii.test").unwrap(),
Some(&ASCII_UCASE_TO_LCASE),
File::open("./test-resources/lcase-ascii.test").unwrap()
);
make_conv_test!(
// conv=ebcdic,ucase
atoe_and_ucase_conv_spec_test,
"atoe-and-ucase-conv-spec-test",
File::open("./test-resources/seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test").unwrap(),
Some(&ASCII_TO_EBCDIC_LCASE_TO_UCASE),
File::open("./test-resources/ucase-ebcdic.test").unwrap()
);
make_conv_test!(
// conv=ebcdic,lcase
atoe_and_lcase_conv_spec_test,
"atoe-and-lcase-conv-spec-test",
File::open("./test-resources/seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test").unwrap(),
Some(&ASCII_TO_EBCDIC_UCASE_TO_LCASE),
File::open("./test-resources/lcase-ebcdic.test").unwrap()
);
make_conv_test!(
// conv=ibm,ucase
atoibm_and_ucase_conv_spec_test,
"atoibm-and-ucase-conv-spec-test",
File::open("./test-resources/seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test").unwrap(),
Some(&ASCII_TO_IBM_UCASE_TO_LCASE),
File::open("./test-resources/lcase-ibm.test").unwrap()
);
make_conv_test!(
// conv=ibm,lcase
atoibm_and_lcase_conv_spec_test,
"atoibm-and-lcase-conv-spec-test",
File::open("./test-resources/seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test").unwrap(),
Some(&ASCII_TO_IBM_LCASE_TO_UCASE),
File::open("./test-resources/ucase-ibm.test").unwrap()
);
#[test]
fn all_valid_ascii_ebcdic_ascii_roundtrip_conv_test() {
// ASCII->EBCDIC
let test_name = "all-valid-ascii-to-ebcdic";
let tmp_fname_ae = format!("./test-resources/FAILED-{}.test", test_name);
let i = Input {
src: File::open(
"./test-resources/all-valid-ascii-chars-37eff01866ba3f538421b30b7cbefcac.test",
)
.unwrap(),
non_ascii: false,
ibs: 128,
print_level: None,
count: None,
cflags: icf!(Some(&ASCII_TO_EBCDIC)),
iflags: IFlags::default(),
};
let o = Output {
dst: File::create(&tmp_fname_ae).unwrap(),
obs: 1024,
cflags: OConvFlags::default(),
};
o.dd_out(i).unwrap();
// EBCDIC->ASCII
let test_name = "all-valid-ebcdic-to-ascii";
let tmp_fname_ea = format!("./test-resources/FAILED-{}.test", test_name);
let i = Input {
src: File::open(&tmp_fname_ae).unwrap(),
non_ascii: false,
ibs: 256,
print_level: None,
count: None,
cflags: icf!(Some(&EBCDIC_TO_ASCII)),
iflags: IFlags::default(),
};
let o = Output {
dst: File::create(&tmp_fname_ea).unwrap(),
obs: 1024,
cflags: OConvFlags::default(),
};
o.dd_out(i).unwrap();
// Final Comparison
let res = File::open(&tmp_fname_ea).unwrap();
let spec =
File::open("./test-resources/all-valid-ascii-chars-37eff01866ba3f538421b30b7cbefcac.test")
.unwrap();
assert_eq!(
res.metadata().unwrap().len(),
spec.metadata().unwrap().len()
);
let res = BufReader::new(res);
let spec = BufReader::new(spec);
let res = BufReader::new(res);
// Check all bytes match
for (b_res, b_spec) in res.bytes().zip(spec.bytes()) {
assert_eq!(b_res.unwrap(), b_spec.unwrap());
}
fs::remove_file(&tmp_fname_ae).unwrap();
fs::remove_file(&tmp_fname_ea).unwrap();
}
make_icf_test!(
swab_256_test,
"swab-256",
File::open("./test-resources/seq-byte-values.test").unwrap(),
IConvFlags {
ctable: None,
block: None,
unblock: None,
swab: true,
sync: None,
noerror: false,
},
File::open("./test-resources/seq-byte-values-swapped.test").unwrap()
);
make_icf_test!(
swab_257_test,
"swab-257",
File::open("./test-resources/seq-byte-values-odd.test").unwrap(),
IConvFlags {
ctable: None,
block: None,
unblock: None,
swab: true,
sync: None,
noerror: false,
},
File::open("./test-resources/seq-byte-values-odd.spec").unwrap()
);

View file

@ -1,89 +0,0 @@
// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat
use super::*;
mod block_unblock_tests;
mod conv_sync_tests;
mod conversion_tests;
mod sanity_tests;
use std::fs;
use std::io::prelude::*;
use std::io::BufReader;
struct LazyReader<R: Read> {
src: R,
}
impl<R: Read> Read for LazyReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let reduced = cmp::max(buf.len() / 2, 1);
self.src.read(&mut buf[..reduced])
}
}
#[macro_export]
macro_rules! icf (
( $ctable:expr ) =>
{
IConvFlags {
ctable: $ctable,
..IConvFlags::default()
}
};
);
#[macro_export]
macro_rules! make_spec_test (
( $test_id:ident, $test_name:expr, $src:expr ) =>
{
// When spec not given, output should match input
make_spec_test!($test_id, $test_name, $src, $src);
};
( $test_id:ident, $test_name:expr, $src:expr, $spec:expr ) =>
{
make_spec_test!($test_id,
$test_name,
Input {
src: $src,
non_ascii: false,
ibs: 512,
print_level: None,
count: None,
cflags: IConvFlags::default(),
iflags: IFlags::default(),
},
Output {
dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(),
obs: 512,
cflags: OConvFlags::default(),
},
$spec,
format!("./test-resources/FAILED-{}.test", $test_name)
);
};
( $test_id:ident, $test_name:expr, $i:expr, $o:expr, $spec:expr, $tmp_fname:expr ) =>
{
#[test]
fn $test_id()
{
$o.dd_out($i).unwrap();
let res = File::open($tmp_fname).unwrap();
// Check test file isn't empty (unless spec file is too)
assert_eq!(res.metadata().unwrap().len(), $spec.metadata().unwrap().len());
let spec = BufReader::new($spec);
let res = BufReader::new(res);
// Check all bytes match
for (b_res, b_spec) in res.bytes().zip(spec.bytes())
{
assert_eq!(b_res.unwrap(),
b_spec.unwrap());
}
fs::remove_file($tmp_fname).unwrap();
}
};
);

View file

@ -1,316 +0,0 @@
// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat
use super::*;
const DST_PLACEHOLDER: Vec<u8> = Vec::new();
macro_rules! make_io_test (
( $test_id:ident, $test_name:expr, $i:expr, $o:expr, $spec:expr ) =>
{
make_spec_test!($test_id,
$test_name,
$i,
Output {
dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(),
obs: $o.obs,
cflags: $o.cflags,
},
$spec,
format!("./test-resources/FAILED-{}.test", $test_name)
);
};
);
make_spec_test!(
zeros_4k_test,
"zeros-4k",
File::open("./test-resources/zeros-620f0b67a91f7f74151bc5be745b7110.test").unwrap()
);
make_spec_test!(
ones_4k_test,
"ones-4k",
File::open("./test-resources/ones-6ae59e64850377ee5470c854761551ea.test").unwrap()
);
make_spec_test!(
deadbeef_32k_test,
"deadbeef-32k",
File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap()
);
make_spec_test!(
random_73k_test,
"random-73k",
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap()
);
make_io_test!(
random_73k_test_not_a_multiple_obs_gt_ibs,
"random-73k-not-a-multiple-obs-gt-ibs",
Input {
src: File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
non_ascii: false,
ibs: 521,
print_level: None,
count: None,
cflags: IConvFlags::default(),
iflags: IFlags::default(),
},
Output {
dst: DST_PLACEHOLDER,
obs: 1031,
cflags: OConvFlags::default(),
},
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap()
);
make_io_test!(
random_73k_test_obs_lt_not_a_multiple_ibs,
"random-73k-obs-lt-not-a-multiple-ibs",
Input {
src: File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
non_ascii: false,
ibs: 1031,
print_level: None,
count: None,
cflags: IConvFlags::default(),
iflags: IFlags::default(),
},
Output {
dst: DST_PLACEHOLDER,
obs: 521,
cflags: OConvFlags::default(),
},
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap()
);
make_io_test!(
deadbeef_all_32k_test_count_reads,
"deadbeef_all_32k_test_count_reads",
Input {
src: File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap(),
non_ascii: false,
ibs: 1024,
print_level: None,
count: Some(CountType::Reads(32)),
cflags: IConvFlags::default(),
iflags: IFlags::default(),
},
Output {
dst: DST_PLACEHOLDER,
obs: 1024,
cflags: OConvFlags::default(),
},
File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap()
);
make_io_test!(
deadbeef_all_32k_test_count_bytes,
"deadbeef_all_32k_test_count_bytes",
Input {
src: File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap(),
non_ascii: false,
ibs: 531,
print_level: None,
count: Some(CountType::Bytes(32 * 1024)),
cflags: IConvFlags::default(),
iflags: IFlags::default(),
},
Output {
dst: DST_PLACEHOLDER,
obs: 1031,
cflags: OConvFlags::default(),
},
File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap()
);
make_io_test!(
deadbeef_32k_to_16k_test_count_reads,
"deadbeef_32k_test_count_reads",
Input {
src: File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap(),
non_ascii: false,
ibs: 1024,
print_level: None,
count: Some(CountType::Reads(16)),
cflags: IConvFlags::default(),
iflags: IFlags::default(),
},
Output {
dst: DST_PLACEHOLDER,
obs: 1031,
cflags: OConvFlags::default(),
},
File::open("./test-resources/gnudd-deadbeef-first-16k.spec").unwrap()
);
make_io_test!(
deadbeef_32k_to_12345_test_count_bytes,
"deadbeef_32k_to_12345_test_count_bytes",
Input {
src: File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap(),
non_ascii: false,
ibs: 531,
print_level: None,
count: Some(CountType::Bytes(12345)),
cflags: IConvFlags::default(),
iflags: IFlags::default(),
},
Output {
dst: DST_PLACEHOLDER,
obs: 1031,
cflags: OConvFlags::default(),
},
File::open("./test-resources/gnudd-deadbeef-first-12345.spec").unwrap()
);
make_io_test!(
random_73k_test_count_reads,
"random-73k-test-count-reads",
Input {
src: File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
non_ascii: false,
ibs: 1024,
print_level: None,
count: Some(CountType::Reads(32)),
cflags: IConvFlags::default(),
iflags: IFlags::default(),
},
Output {
dst: DST_PLACEHOLDER,
obs: 1024,
cflags: OConvFlags::default(),
},
File::open("./test-resources/gnudd-random-first-32k.spec").unwrap()
);
make_io_test!(
random_73k_test_count_bytes,
"random-73k-test-count-bytes",
Input {
src: File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
non_ascii: false,
ibs: 521,
print_level: None,
count: Some(CountType::Bytes(32 * 1024)),
cflags: IConvFlags::default(),
iflags: IFlags::default(),
},
Output {
dst: DST_PLACEHOLDER,
obs: 1031,
cflags: OConvFlags::default(),
},
File::open("./test-resources/gnudd-random-first-32k.spec").unwrap()
);
make_io_test!(
random_73k_test_lazy_fullblock,
"random-73k-test-lazy-fullblock",
Input {
src: LazyReader {
src: File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test")
.unwrap()
},
non_ascii: false,
ibs: 521,
print_level: None,
count: None,
cflags: IConvFlags::default(),
iflags: IFlags {
fullblock: true,
..IFlags::default()
},
},
Output {
dst: DST_PLACEHOLDER,
obs: 1031,
cflags: OConvFlags::default(),
},
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap()
);
// Test internal buffer size fn
#[test]
fn bsize_test_primes() {
let (n, m) = (7901, 7919);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, n * m);
}
#[test]
fn bsize_test_rel_prime_obs_greater() {
let (n, m) = (7 * 5119, 13 * 5119);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, 7 * 13 * 5119);
}
#[test]
fn bsize_test_rel_prime_ibs_greater() {
let (n, m) = (13 * 5119, 7 * 5119);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, 7 * 13 * 5119);
}
#[test]
fn bsize_test_3fac_rel_prime() {
let (n, m) = (11 * 13 * 5119, 7 * 11 * 5119);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, 7 * 11 * 13 * 5119);
}
#[test]
fn bsize_test_ibs_greater() {
let (n, m) = (512 * 1024, 256 * 1024);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, n);
}
#[test]
fn bsize_test_obs_greater() {
let (n, m) = (256 * 1024, 512 * 1024);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, m);
}
#[test]
fn bsize_test_bs_eq() {
let (n, m) = (1024, 1024);
let res = calc_bsize(n, m);
assert!(res % n == 0);
assert!(res % m == 0);
assert_eq!(res, m);
}
#[test]
#[should_panic]
fn test_nocreat_causes_failure_when_ofile_doesnt_exist() {
let args = vec![
String::from("dd"),
String::from("--conv=nocreat"),
String::from("--of=not-a-real.file"),
];
let matches = uu_app().try_get_matches_from(args).unwrap();
let _ = Output::<File>::new(&matches).unwrap();
}

View file

@ -130,14 +130,7 @@ impl Display for ExtendedBigDecimal {
}
ExtendedBigDecimal::Infinity => f32::INFINITY.fmt(f),
ExtendedBigDecimal::MinusInfinity => f32::NEG_INFINITY.fmt(f),
ExtendedBigDecimal::MinusZero => {
// FIXME In Rust version 1.53.0 and later, the display
// of floats was updated to allow displaying negative
// zero. See
// https://github.com/rust-lang/rust/pull/78618. Currently,
// this just formats "0.0".
(0.0f32).fmt(f)
}
ExtendedBigDecimal::MinusZero => (-0.0f32).fmt(f),
ExtendedBigDecimal::Nan => "nan".fmt(f),
}
}
@ -280,11 +273,6 @@ mod tests {
assert_eq!(format!("{}", ExtendedBigDecimal::Infinity), "inf");
assert_eq!(format!("{}", ExtendedBigDecimal::MinusInfinity), "-inf");
assert_eq!(format!("{}", ExtendedBigDecimal::Nan), "nan");
// FIXME In Rust version 1.53.0 and later, the display of floats
// was updated to allow displaying negative zero. Until then, we
// just display `MinusZero` as "0.0".
//
// assert_eq!(format!("{}", ExtendedBigDecimal::MinusZero), "-0.0");
//
assert_eq!(format!("{}", ExtendedBigDecimal::MinusZero), "-0");
}
}

View file

@ -198,27 +198,15 @@ fn done_printing<T: Zero + PartialOrd>(next: &T, increment: &T, last: &T) -> boo
}
/// Write a big decimal formatted according to the given parameters.
///
/// This method is an adapter to support displaying negative zero on
/// Rust versions earlier than 1.53.0. After that version, we should be
/// able to display negative zero using the default formatting provided
/// by `-0.0f32`, for example.
fn write_value_float(
writer: &mut impl Write,
value: &ExtendedBigDecimal,
width: usize,
precision: usize,
is_first_iteration: bool,
_is_first_iteration: bool,
) -> std::io::Result<()> {
let value_as_str = if *value == ExtendedBigDecimal::MinusZero && is_first_iteration {
format!(
"-{value:>0width$.precision$}",
value = value,
width = if width > 0 { width - 1 } else { width },
precision = precision,
)
} else if *value == ExtendedBigDecimal::Infinity || *value == ExtendedBigDecimal::MinusInfinity
{
let value_as_str =
if *value == ExtendedBigDecimal::Infinity || *value == ExtendedBigDecimal::MinusInfinity {
format!(
"{value:>width$.precision$}",
value = value,

View file

@ -13,12 +13,13 @@
//!
//! ```rust,ignore
//! use crate::filenames::FilenameIterator;
//! use crate::filenames::SuffixType;
//!
//! let prefix = "chunk_".to_string();
//! let suffix = ".txt".to_string();
//! let width = 2;
//! let use_numeric_suffix = false;
//! let it = FilenameIterator::new(prefix, suffix, width, use_numeric_suffix);
//! let suffix_type = SuffixType::Alphabetic;
//! let it = FilenameIterator::new(prefix, suffix, width, suffix_type);
//!
//! assert_eq!(it.next().unwrap(), "chunk_aa.txt");
//! assert_eq!(it.next().unwrap(), "chunk_ab.txt");
@ -28,6 +29,30 @@ use crate::number::DynamicWidthNumber;
use crate::number::FixedWidthNumber;
use crate::number::Number;
/// The format to use for suffixes in the filename for each output chunk.
#[derive(Clone, Copy)]
pub enum SuffixType {
/// Lowercase ASCII alphabetic characters.
Alphabetic,
/// Decimal numbers.
NumericDecimal,
/// Hexadecimal numbers.
NumericHexadecimal,
}
impl SuffixType {
/// The radix to use when representing the suffix string as digits.
fn radix(&self) -> u8 {
match self {
SuffixType::Alphabetic => 26,
SuffixType::NumericDecimal => 10,
SuffixType::NumericHexadecimal => 16,
}
}
}
/// Compute filenames from a given index.
///
/// This iterator yields filenames for use with ``split``.
@ -42,8 +67,8 @@ use crate::number::Number;
/// width in characters. In that case, after the iterator yields each
/// string of that width, the iterator is exhausted.
///
/// Finally, if `use_numeric_suffix` is `true`, then numbers will be
/// used instead of lowercase ASCII alphabetic characters.
/// Finally, `suffix_type` controls which type of suffix to produce,
/// alphabetic or numeric.
///
/// # Examples
///
@ -52,28 +77,30 @@ use crate::number::Number;
///
/// ```rust,ignore
/// use crate::filenames::FilenameIterator;
/// use crate::filenames::SuffixType;
///
/// let prefix = "chunk_".to_string();
/// let suffix = ".txt".to_string();
/// let width = 2;
/// let use_numeric_suffix = false;
/// let it = FilenameIterator::new(prefix, suffix, width, use_numeric_suffix);
/// let suffix_type = SuffixType::Alphabetic;
/// let it = FilenameIterator::new(prefix, suffix, width, suffix_type);
///
/// assert_eq!(it.next().unwrap(), "chunk_aa.txt");
/// assert_eq!(it.next().unwrap(), "chunk_ab.txt");
/// assert_eq!(it.next().unwrap(), "chunk_ac.txt");
/// ```
///
/// For numeric filenames, set `use_numeric_suffix` to `true`:
/// For decimal numeric filenames, use `SuffixType::NumericDecimal`:
///
/// ```rust,ignore
/// use crate::filenames::FilenameIterator;
/// use crate::filenames::SuffixType;
///
/// let prefix = "chunk_".to_string();
/// let suffix = ".txt".to_string();
/// let width = 2;
/// let use_numeric_suffix = true;
/// let it = FilenameIterator::new(prefix, suffix, width, use_numeric_suffix);
/// let suffix_type = SuffixType::NumericDecimal;
/// let it = FilenameIterator::new(prefix, suffix, width, suffix_type);
///
/// assert_eq!(it.next().unwrap(), "chunk_00.txt");
/// assert_eq!(it.next().unwrap(), "chunk_01.txt");
@ -91,9 +118,9 @@ impl<'a> FilenameIterator<'a> {
prefix: &'a str,
additional_suffix: &'a str,
suffix_length: usize,
use_numeric_suffix: bool,
suffix_type: SuffixType,
) -> FilenameIterator<'a> {
let radix = if use_numeric_suffix { 10 } else { 26 };
let radix = suffix_type.radix();
let number = if suffix_length == 0 {
Number::DynamicWidth(DynamicWidthNumber::new(radix))
} else {
@ -130,39 +157,40 @@ impl<'a> Iterator for FilenameIterator<'a> {
mod tests {
use crate::filenames::FilenameIterator;
use crate::filenames::SuffixType;
#[test]
fn test_filename_iterator_alphabetic_fixed_width() {
let mut it = FilenameIterator::new("chunk_", ".txt", 2, false);
let mut it = FilenameIterator::new("chunk_", ".txt", 2, SuffixType::Alphabetic);
assert_eq!(it.next().unwrap(), "chunk_aa.txt");
assert_eq!(it.next().unwrap(), "chunk_ab.txt");
assert_eq!(it.next().unwrap(), "chunk_ac.txt");
let mut it = FilenameIterator::new("chunk_", ".txt", 2, false);
let mut it = FilenameIterator::new("chunk_", ".txt", 2, SuffixType::Alphabetic);
assert_eq!(it.nth(26 * 26 - 1).unwrap(), "chunk_zz.txt");
assert_eq!(it.next(), None);
}
#[test]
fn test_filename_iterator_numeric_fixed_width() {
let mut it = FilenameIterator::new("chunk_", ".txt", 2, true);
let mut it = FilenameIterator::new("chunk_", ".txt", 2, SuffixType::NumericDecimal);
assert_eq!(it.next().unwrap(), "chunk_00.txt");
assert_eq!(it.next().unwrap(), "chunk_01.txt");
assert_eq!(it.next().unwrap(), "chunk_02.txt");
let mut it = FilenameIterator::new("chunk_", ".txt", 2, true);
let mut it = FilenameIterator::new("chunk_", ".txt", 2, SuffixType::NumericDecimal);
assert_eq!(it.nth(10 * 10 - 1).unwrap(), "chunk_99.txt");
assert_eq!(it.next(), None);
}
#[test]
fn test_filename_iterator_alphabetic_dynamic_width() {
let mut it = FilenameIterator::new("chunk_", ".txt", 0, false);
let mut it = FilenameIterator::new("chunk_", ".txt", 0, SuffixType::Alphabetic);
assert_eq!(it.next().unwrap(), "chunk_aa.txt");
assert_eq!(it.next().unwrap(), "chunk_ab.txt");
assert_eq!(it.next().unwrap(), "chunk_ac.txt");
let mut it = FilenameIterator::new("chunk_", ".txt", 0, false);
let mut it = FilenameIterator::new("chunk_", ".txt", 0, SuffixType::Alphabetic);
assert_eq!(it.nth(26 * 25 - 1).unwrap(), "chunk_yz.txt");
assert_eq!(it.next().unwrap(), "chunk_zaaa.txt");
assert_eq!(it.next().unwrap(), "chunk_zaab.txt");
@ -170,12 +198,12 @@ mod tests {
#[test]
fn test_filename_iterator_numeric_dynamic_width() {
let mut it = FilenameIterator::new("chunk_", ".txt", 0, true);
let mut it = FilenameIterator::new("chunk_", ".txt", 0, SuffixType::NumericDecimal);
assert_eq!(it.next().unwrap(), "chunk_00.txt");
assert_eq!(it.next().unwrap(), "chunk_01.txt");
assert_eq!(it.next().unwrap(), "chunk_02.txt");
let mut it = FilenameIterator::new("chunk_", ".txt", 0, true);
let mut it = FilenameIterator::new("chunk_", ".txt", 0, SuffixType::NumericDecimal);
assert_eq!(it.nth(10 * 9 - 1).unwrap(), "chunk_89.txt");
assert_eq!(it.next().unwrap(), "chunk_9000.txt");
assert_eq!(it.next().unwrap(), "chunk_9001.txt");

View file

@ -40,13 +40,19 @@ impl Error for Overflow {}
/// specifically for the `split` program. See the
/// [`DynamicWidthNumber`] documentation for more information.
///
/// Numbers of radix 10 are displayable and rendered as decimal
/// numbers (for example, "00" or "917"). Numbers of radix 26 are
/// displayable and rendered as lowercase ASCII alphabetic characters
/// (for example, "aa" or "zax"). Numbers of other radices cannot be
/// displayed. The display of a [`DynamicWidthNumber`] includes a
/// prefix whose length depends on the width of the number. See the
/// [`DynamicWidthNumber`] documentation for more information.
/// Numbers of radix
///
/// * 10 are displayable and rendered as decimal numbers (for example,
/// "00" or "917"),
/// * 16 are displayable and rendered as hexadecimal numbers (for example,
/// "00" or "e7f"),
/// * 26 are displayable and rendered as lowercase ASCII alphabetic
/// characters (for example, "aa" or "zax").
///
/// Numbers of other radices cannot be displayed. The display of a
/// [`DynamicWidthNumber`] includes a prefix whose length depends on
/// the width of the number. See the [`DynamicWidthNumber`]
/// documentation for more information.
///
/// The digits of a number are accessible via the [`Number::digits`]
/// method. The digits are represented as a [`Vec<u8>`] with the most
@ -169,12 +175,12 @@ impl Display for Number {
///
/// # Displaying
///
/// This number is only displayable if `radix` is 10 or `radix` is
/// 26. If `radix` is 10, then the digits are concatenated and
/// displayed as a fixed-width decimal number. If `radix` is 26, then
/// each digit is translated to the corresponding lowercase ASCII
/// alphabetic character (that is, 'a', 'b', 'c', etc.) and
/// concatenated.
/// This number is only displayable if `radix` is 10, 26, or 26. If
/// `radix` is 10 or 16, then the digits are concatenated and
/// displayed as a fixed-width decimal or hexadecimal number,
/// respectively. If `radix` is 26, then each digit is translated to
/// the corresponding lowercase ASCII alphabetic character (that is,
/// 'a', 'b', 'c', etc.) and concatenated.
#[derive(Clone)]
pub struct FixedWidthNumber {
radix: u8,
@ -228,6 +234,14 @@ impl Display for FixedWidthNumber {
let digits: String = self.digits.iter().map(|d| (b'0' + d) as char).collect();
write!(f, "{}", digits)
}
16 => {
let digits: String = self
.digits
.iter()
.map(|d| (if *d < 10 { b'0' + d } else { b'a' + (d - 10) }) as char)
.collect();
write!(f, "{}", digits)
}
26 => {
let digits: String = self.digits.iter().map(|d| (b'a' + d) as char).collect();
write!(f, "{}", digits)
@ -264,14 +278,15 @@ impl Display for FixedWidthNumber {
///
/// # Displaying
///
/// This number is only displayable if `radix` is 10 or `radix` is
/// 26. If `radix` is 10, then the digits are concatenated and
/// displayed as a fixed-width decimal number with a prefix of `n - 2`
/// instances of the character '9', where `n` is the number of digits.
/// If `radix` is 26, then each digit is translated to the
/// corresponding lowercase ASCII alphabetic character (that is, 'a',
/// 'b', 'c', etc.) and concatenated with a prefix of `n - 2`
/// instances of the character 'z'.
/// This number is only displayable if `radix` is 10, 16, or 26. If
/// `radix` is 10 or 16, then the digits are concatenated and
/// displayed as a fixed-width decimal or hexadecimal number,
/// respectively, with a prefix of `n - 2` instances of the character
/// '9' of 'f', respectively, where `n` is the number of digits. If
/// `radix` is 26, then each digit is translated to the corresponding
/// lowercase ASCII alphabetic character (that is, 'a', 'b', 'c',
/// etc.) and concatenated with a prefix of `n - 2` instances of the
/// character 'z'.
///
/// This notion of displaying the number is specific to the `split`
/// program.
@ -349,6 +364,21 @@ impl Display for DynamicWidthNumber {
digits = digits,
)
}
16 => {
let num_fill_chars = self.digits.len() - 2;
let digits: String = self
.digits
.iter()
.map(|d| (if *d < 10 { b'0' + d } else { b'a' + (d - 10) }) as char)
.collect();
write!(
f,
"{empty:f<num_fill_chars$}{digits}",
empty = "",
num_fill_chars = num_fill_chars,
digits = digits,
)
}
26 => {
let num_fill_chars = self.digits.len() - 2;
let digits: String = self.digits.iter().map(|d| (b'a' + d) as char).collect();
@ -424,7 +454,7 @@ mod tests {
}
#[test]
fn test_dynamic_width_number_display_numeric() {
fn test_dynamic_width_number_display_numeric_decimal() {
fn num(n: usize) -> Number {
let mut number = Number::DynamicWidth(DynamicWidthNumber::new(10));
for _ in 0..n {
@ -444,6 +474,30 @@ mod tests {
assert_eq!(format!("{}", num(10 * 99 + 1)), "990001");
}
#[test]
fn test_dynamic_width_number_display_numeric_hexadecimal() {
fn num(n: usize) -> Number {
let mut number = Number::DynamicWidth(DynamicWidthNumber::new(16));
for _ in 0..n {
number.increment().unwrap()
}
number
}
assert_eq!(format!("{}", num(0)), "00");
assert_eq!(format!("{}", num(15)), "0f");
assert_eq!(format!("{}", num(16)), "10");
assert_eq!(format!("{}", num(17)), "11");
assert_eq!(format!("{}", num(18)), "12");
assert_eq!(format!("{}", num(16 * 15 - 1)), "ef");
assert_eq!(format!("{}", num(16 * 15)), "f000");
assert_eq!(format!("{}", num(16 * 15 + 1)), "f001");
assert_eq!(format!("{}", num(16 * 255 - 1)), "feff");
assert_eq!(format!("{}", num(16 * 255)), "ff0000");
assert_eq!(format!("{}", num(16 * 255 + 1)), "ff0001");
}
#[test]
fn test_fixed_width_number_increment() {
let mut n = Number::FixedWidth(FixedWidthNumber::new(3, 2));
@ -493,7 +547,7 @@ mod tests {
}
#[test]
fn test_fixed_width_number_display_numeric() {
fn test_fixed_width_number_display_numeric_decimal() {
fn num(n: usize) -> Result<Number, Overflow> {
let mut number = Number::FixedWidth(FixedWidthNumber::new(10, 2));
for _ in 0..n {
@ -510,4 +564,23 @@ mod tests {
assert_eq!(format!("{}", num(10 * 10 - 1).unwrap()), "99");
assert!(num(10 * 10).is_err());
}
#[test]
fn test_fixed_width_number_display_numeric_hexadecimal() {
fn num(n: usize) -> Result<Number, Overflow> {
let mut number = Number::FixedWidth(FixedWidthNumber::new(16, 2));
for _ in 0..n {
number.increment()?;
}
Ok(number)
}
assert_eq!(format!("{}", num(0).unwrap()), "00");
assert_eq!(format!("{}", num(15).unwrap()), "0f");
assert_eq!(format!("{}", num(17).unwrap()), "11");
assert_eq!(format!("{}", num(16 * 15 - 1).unwrap()), "ef");
assert_eq!(format!("{}", num(16 * 15).unwrap()), "f0");
assert_eq!(format!("{}", num(16 * 16 - 1).unwrap()), "ff");
assert!(num(16 * 16).is_err());
}
}

View file

@ -12,6 +12,7 @@ mod number;
mod platform;
use crate::filenames::FilenameIterator;
use crate::filenames::SuffixType;
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
use std::env;
use std::fmt;
@ -31,6 +32,7 @@ static OPT_ADDITIONAL_SUFFIX: &str = "additional-suffix";
static OPT_FILTER: &str = "filter";
static OPT_NUMBER: &str = "number";
static OPT_NUMERIC_SUFFIXES: &str = "numeric-suffixes";
static OPT_HEX_SUFFIXES: &str = "hex-suffixes";
static OPT_SUFFIX_LENGTH: &str = "suffix-length";
static OPT_DEFAULT_SUFFIX_LENGTH: &str = "0";
static OPT_VERBOSE: &str = "verbose";
@ -142,6 +144,14 @@ pub fn uu_app<'a>() -> App<'a> {
.default_value(OPT_DEFAULT_SUFFIX_LENGTH)
.help("use suffixes of length N (default 2)"),
)
.arg(
Arg::new(OPT_HEX_SUFFIXES)
.short('x')
.long(OPT_HEX_SUFFIXES)
.takes_value(true)
.default_missing_value("0")
.help("use hex suffixes starting at 0, not alphabetic"),
)
.arg(
Arg::new(OPT_VERBOSE)
.long(OPT_VERBOSE)
@ -250,13 +260,24 @@ impl Strategy {
}
}
/// Parse the suffix type from the command-line arguments.
fn suffix_type_from(matches: &ArgMatches) -> SuffixType {
if matches.occurrences_of(OPT_NUMERIC_SUFFIXES) > 0 {
SuffixType::NumericDecimal
} else if matches.occurrences_of(OPT_HEX_SUFFIXES) > 0 {
SuffixType::NumericHexadecimal
} else {
SuffixType::Alphabetic
}
}
/// Parameters that control how a file gets split.
///
/// You can convert an [`ArgMatches`] instance into a [`Settings`]
/// instance by calling [`Settings::from`].
struct Settings {
prefix: String,
numeric_suffix: bool,
suffix_type: SuffixType,
suffix_length: usize,
additional_suffix: String,
input: String,
@ -324,7 +345,7 @@ impl Settings {
suffix_length: suffix_length_str
.parse()
.map_err(|_| SettingsError::SuffixLength(suffix_length_str.to_string()))?,
numeric_suffix: matches.occurrences_of(OPT_NUMERIC_SUFFIXES) > 0,
suffix_type: suffix_type_from(matches),
additional_suffix,
verbose: matches.occurrences_of("verbose") > 0,
strategy: Strategy::from(matches).map_err(SettingsError::Strategy)?,
@ -384,7 +405,7 @@ impl<'a> ByteChunkWriter<'a> {
&settings.prefix,
&settings.additional_suffix,
settings.suffix_length,
settings.numeric_suffix,
settings.suffix_type,
);
let filename = filename_iterator.next()?;
if settings.verbose {
@ -512,7 +533,7 @@ impl<'a> LineChunkWriter<'a> {
&settings.prefix,
&settings.additional_suffix,
settings.suffix_length,
settings.numeric_suffix,
settings.suffix_type,
);
let filename = filename_iterator.next()?;
if settings.verbose {
@ -604,7 +625,7 @@ where
&settings.prefix,
&settings.additional_suffix,
settings.suffix_length,
settings.numeric_suffix,
settings.suffix_type,
);
// Create one writer for each chunk. This will create each

View file

@ -702,5 +702,364 @@ fn test_partial_records_out() {
.stderr_is("1+1 records in\n1+1 records out\n");
}
// conv=[ascii,ebcdic,ibm], conv=[ucase,lcase], conv=[block,unblock], conv=sync
// TODO: Move conv tests from unit test module
#[test]
fn test_block_cbs16() {
new_ucmd!()
.args(&["conv=block", "cbs=16"])
.pipe_in_fixture("dd-block-cbs16.test")
.succeeds()
.stdout_is_fixture_bytes("dd-block-cbs16.spec");
}
#[test]
fn test_block_cbs16_as_cbs8() {
new_ucmd!()
.args(&["conv=block", "cbs=8"])
.pipe_in_fixture("dd-block-cbs16.test")
.succeeds()
.stdout_is_fixture_bytes("dd-block-cbs8.spec");
}
#[test]
fn test_block_consecutive_nl() {
new_ucmd!()
.args(&["conv=block", "cbs=16"])
.pipe_in_fixture("dd-block-consecutive-nl.test")
.succeeds()
.stdout_is_fixture_bytes("dd-block-consecutive-nl-cbs16.spec");
}
#[test]
fn test_unblock_multi_16() {
new_ucmd!()
.args(&["conv=unblock", "cbs=16"])
.pipe_in_fixture("dd-unblock-cbs16.test")
.succeeds()
.stdout_is_fixture_bytes("dd-unblock-cbs16.spec");
}
#[test]
fn test_unblock_multi_16_as_8() {
new_ucmd!()
.args(&["conv=unblock", "cbs=8"])
.pipe_in_fixture("dd-unblock-cbs16.test")
.succeeds()
.stdout_is_fixture_bytes("dd-unblock-cbs8.spec");
}
#[test]
fn test_atoe_conv_spec_test() {
new_ucmd!()
.args(&["conv=ebcdic"])
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
.succeeds()
.stdout_is_fixture_bytes("gnudd-conv-atoe-seq-byte-values.spec");
}
#[test]
fn test_etoa_conv_spec_test() {
new_ucmd!()
.args(&["conv=ascii"])
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
.succeeds()
.stdout_is_fixture_bytes("gnudd-conv-etoa-seq-byte-values.spec");
}
#[test]
fn test_atoibm_conv_spec_test() {
new_ucmd!()
.args(&["conv=ibm"])
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
.succeeds()
.stdout_is_fixture_bytes("gnudd-conv-atoibm-seq-byte-values.spec");
}
#[test]
fn test_lcase_ascii_to_ucase_ascii() {
new_ucmd!()
.args(&["conv=ucase"])
.pipe_in_fixture("lcase-ascii.test")
.succeeds()
.stdout_is_fixture_bytes("ucase-ascii.test");
}
#[test]
fn test_ucase_ascii_to_lcase_ascii() {
new_ucmd!()
.args(&["conv=lcase"])
.pipe_in_fixture("ucase-ascii.test")
.succeeds()
.stdout_is_fixture_bytes("lcase-ascii.test");
}
#[test]
fn test_atoe_and_ucase_conv_spec_test() {
new_ucmd!()
.args(&["conv=ebcdic,ucase"])
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
.succeeds()
.stdout_is_fixture_bytes("ucase-ebcdic.test");
}
#[test]
fn test_atoe_and_lcase_conv_spec_test() {
new_ucmd!()
.args(&["conv=ebcdic,lcase"])
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
.succeeds()
.stdout_is_fixture_bytes("lcase-ebcdic.test");
}
// TODO I think uppercase and lowercase are unintentionally swapped in
// the code that parses the command-line arguments. See this line from
// `parseargs.rs`:
//
// (ConvFlag::FmtAtoI, ConvFlag::UCase) => Some(&ASCII_TO_IBM_UCASE_TO_LCASE),
// (ConvFlag::FmtAtoI, ConvFlag::LCase) => Some(&ASCII_TO_IBM_LCASE_TO_UCASE),
//
// If my reading is correct and that is a typo, then the
// UCASE_TO_LCASE and LCASE_TO_UCASE in those lines should be swapped,
// and the expected output for the following two tests should be
// updated accordingly.
#[test]
fn test_atoibm_and_ucase_conv_spec_test() {
new_ucmd!()
.args(&["conv=ibm,ucase"])
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
.succeeds()
.stdout_is_fixture_bytes("lcase-ibm.test");
}
#[test]
fn test_atoibm_and_lcase_conv_spec_test() {
new_ucmd!()
.args(&["conv=ibm,lcase"])
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
.succeeds()
.stdout_is_fixture_bytes("ucase-ibm.test");
}
#[test]
fn test_swab_256_test() {
new_ucmd!()
.args(&["conv=swab"])
.pipe_in_fixture("seq-byte-values.test")
.succeeds()
.stdout_is_fixture_bytes("seq-byte-values-swapped.test");
}
#[test]
fn test_swab_257_test() {
new_ucmd!()
.args(&["conv=swab"])
.pipe_in_fixture("seq-byte-values-odd.test")
.succeeds()
.stdout_is_fixture_bytes("seq-byte-values-odd.spec");
}
#[test]
fn test_zeros_4k_conv_sync_obs_gt_ibs() {
new_ucmd!()
.args(&["conv=sync", "ibs=521", "obs=1031"])
.pipe_in_fixture("zeros-620f0b67a91f7f74151bc5be745b7110.test")
.succeeds()
.stdout_is_fixture_bytes("gnudd-conv-sync-ibs-521-obs-1031-zeros.spec");
}
#[test]
fn test_zeros_4k_conv_sync_ibs_gt_obs() {
new_ucmd!()
.args(&["conv=sync", "ibs=1031", "obs=521"])
.pipe_in_fixture("zeros-620f0b67a91f7f74151bc5be745b7110.test")
.succeeds()
.stdout_is_fixture_bytes("gnudd-conv-sync-ibs-1031-obs-521-zeros.spec");
}
#[test]
fn test_deadbeef_32k_conv_sync_obs_gt_ibs() {
new_ucmd!()
.args(&[
"conv=sync",
"ibs=521",
"obs=1031",
"if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test",
])
.succeeds()
.stdout_is_fixture_bytes("gnudd-conv-sync-ibs-521-obs-1031-deadbeef.spec");
}
#[test]
fn test_deadbeef_32k_conv_sync_ibs_gt_obs() {
new_ucmd!()
.args(&[
"conv=sync",
"ibs=1031",
"obs=521",
"if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test",
])
.succeeds()
.stdout_is_fixture_bytes("gnudd-conv-sync-ibs-1031-obs-521-deadbeef.spec");
}
#[test]
fn test_random_73k_test_bs_prime_obs_gt_ibs_sync() {
new_ucmd!()
.args(&[
"conv=sync",
"ibs=521",
"obs=1031",
"if=random-5828891cb1230748e146f34223bbd3b5.test",
])
.succeeds()
.stdout_is_fixture_bytes("gnudd-conv-sync-ibs-521-obs-1031-random.spec");
}
#[test]
fn test_random_73k_test_bs_prime_ibs_gt_obs_sync() {
new_ucmd!()
.args(&[
"conv=sync",
"ibs=1031",
"obs=521",
"if=random-5828891cb1230748e146f34223bbd3b5.test",
])
.succeeds()
.stdout_is_fixture_bytes("gnudd-conv-sync-ibs-1031-obs-521-random.spec");
}
#[test]
fn test_identity() {
new_ucmd!()
.args(&["if=zeros-620f0b67a91f7f74151bc5be745b7110.test"])
.succeeds()
.stdout_is_fixture_bytes("zeros-620f0b67a91f7f74151bc5be745b7110.test");
new_ucmd!()
.args(&["if=ones-6ae59e64850377ee5470c854761551ea.test"])
.succeeds()
.stdout_is_fixture_bytes("ones-6ae59e64850377ee5470c854761551ea.test");
new_ucmd!()
.args(&["if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test"])
.succeeds()
.stdout_is_fixture_bytes("deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test");
new_ucmd!()
.args(&["if=random-5828891cb1230748e146f34223bbd3b5.test"])
.succeeds()
.stdout_is_fixture_bytes("random-5828891cb1230748e146f34223bbd3b5.test");
}
#[test]
fn test_random_73k_test_not_a_multiple_obs_gt_ibs() {
new_ucmd!()
.args(&[
"ibs=521",
"obs=1031",
"if=random-5828891cb1230748e146f34223bbd3b5.test",
])
.succeeds()
.stdout_is_fixture_bytes("random-5828891cb1230748e146f34223bbd3b5.test");
}
#[test]
fn test_random_73k_test_obs_lt_not_a_multiple_ibs() {
new_ucmd!()
.args(&[
"ibs=1031",
"obs=521",
"if=random-5828891cb1230748e146f34223bbd3b5.test",
])
.succeeds()
.stdout_is_fixture_bytes("random-5828891cb1230748e146f34223bbd3b5.test");
}
#[test]
fn test_deadbeef_all_32k_test_count_reads() {
new_ucmd!()
.args(&[
"bs=1024",
"count=32",
"if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test",
])
.succeeds()
.stdout_is_fixture_bytes("deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test");
}
#[test]
fn test_deadbeef_all_32k_test_count_bytes() {
new_ucmd!()
.args(&[
"ibs=531",
"obs=1031",
"count=32x1024",
"oflag=count_bytes",
"if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test",
])
.succeeds()
.stdout_is_fixture_bytes("deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test");
}
#[test]
fn test_deadbeef_32k_to_16k_test_count_reads() {
new_ucmd!()
.args(&[
"ibs=1024",
"obs=1031",
"count=16",
"if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test",
])
.succeeds()
.stdout_is_fixture_bytes("gnudd-deadbeef-first-16k.spec");
}
#[test]
fn test_deadbeef_32k_to_12345_test_count_bytes() {
new_ucmd!()
.args(&[
"ibs=531",
"obs=1031",
"count=12345",
"iflag=count_bytes",
"if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test",
])
.succeeds()
.stdout_is_fixture_bytes("gnudd-deadbeef-first-12345.spec");
}
#[test]
fn test_random_73k_test_count_reads() {
new_ucmd!()
.args(&[
"bs=1024",
"count=32",
"if=random-5828891cb1230748e146f34223bbd3b5.test",
])
.succeeds()
.stdout_is_fixture_bytes("gnudd-random-first-32k.spec");
}
#[test]
fn test_random_73k_test_count_bytes() {
new_ucmd!()
.args(&[
"ibs=521",
"obs=1031",
"count=32x1024",
"iflag=count_bytes",
"if=random-5828891cb1230748e146f34223bbd3b5.test",
])
.succeeds()
.stdout_is_fixture_bytes("gnudd-random-first-32k.spec");
}
#[test]
fn test_all_valid_ascii_ebcdic_ascii_roundtrip_conv_test() {
let tmp = new_ucmd!()
.args(&["ibs=128", "obs=1024", "conv=ebcdic"])
.pipe_in_fixture("all-valid-ascii-chars-37eff01866ba3f538421b30b7cbefcac.test")
.succeeds()
.stdout_move_bytes();
new_ucmd!()
.args(&["ibs=256", "obs=1024", "conv=ascii"])
.pipe_in(tmp)
.succeeds()
.stdout_is_fixture_bytes("all-valid-ascii-chars-37eff01866ba3f538421b30b7cbefcac.test");
}

View file

@ -2,7 +2,7 @@
// *
// * For the full copyright and license information, please view the LICENSE
// * file that was distributed with this source code.
// spell-checker:ignore xzaaa sixhundredfiftyonebytes ninetyonebytes asciilowercase fghij klmno pqrst uvwxyz fivelines
// spell-checker:ignore xzaaa sixhundredfiftyonebytes ninetyonebytes asciilowercase fghij klmno pqrst uvwxyz fivelines twohundredfortyonebytes
extern crate rand;
extern crate regex;
@ -409,6 +409,28 @@ fn test_numeric_dynamic_suffix_length() {
assert_eq!(file_read(&at, "x9000"), "a");
}
#[test]
fn test_hex_dynamic_suffix_length() {
let (at, mut ucmd) = at_and_ucmd!();
// Split into chunks of one byte each, use hexadecimal digits
// instead of letters as file suffixes.
//
// The input file has (16^2) - 16 + 1 = 241 bytes. This is just
// enough to force `split` to dynamically increase the length of
// the filename for the very last chunk.
//
// x00, x01, x02, ..., xed, xee, xef, xf000
//
ucmd.args(&["-x", "-b", "1", "twohundredfortyonebytes.txt"])
.succeeds();
for i in 0..240 {
let filename = format!("x{:02x}", i);
let contents = file_read(&at, &filename);
assert_eq!(contents, "a");
}
assert_eq!(file_read(&at, "xf000"), "a");
}
#[test]
fn test_suffixes_exhausted() {
new_ucmd!()

View file

@ -265,6 +265,28 @@ impl CmdResult {
let contents = read_scenario_fixture(&self.tmpd, file_rel_path);
self.stdout_is(String::from_utf8(contents).unwrap())
}
/// Assert that the bytes of stdout exactly match those of the given file.
///
/// Contrast this with [`CmdResult::stdout_is_fixture`], which
/// decodes the contents of the file as a UTF-8 [`String`] before
/// comparison with stdout.
///
/// # Examples
///
/// Use this method in a unit test like this:
///
/// ```rust,ignore
/// #[test]
/// fn test_something() {
/// new_ucmd!().succeeds().stdout_is_fixture_bytes("expected.bin");
/// }
/// ```
pub fn stdout_is_fixture_bytes<T: AsRef<OsStr>>(&self, file_rel_path: T) -> &Self {
let contents = read_scenario_fixture(&self.tmpd, file_rel_path);
self.stdout_is_bytes(contents)
}
/// like stdout_is_fixture(...), but replaces the data in fixture file based on values provided in template_vars
/// command output
pub fn stdout_is_templated_fixture<T: AsRef<OsStr>>(

BIN
tests/fixtures/dd/deadbeef-16.spec vendored Normal file

Binary file not shown.

1
tests/fixtures/dd/deadbeef-16.test vendored Normal file
View file

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

View file

@ -0,0 +1 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa