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:
commit
6db5bf1652
69 changed files with 1051 additions and 1191 deletions
|
@ -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).
|
||||
|
||||

|
||||
|
||||
To run locally:
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
);
|
|
@ -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()
|
||||
);
|
|
@ -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()
|
||||
);
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
);
|
|
@ -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();
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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!()
|
||||
|
|
|
@ -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
BIN
tests/fixtures/dd/deadbeef-16.spec
vendored
Normal file
Binary file not shown.
1
tests/fixtures/dd/deadbeef-16.test
vendored
Normal file
1
tests/fixtures/dd/deadbeef-16.test
vendored
Normal 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>
|
BIN
tests/fixtures/dd/random-5828891cb1230748e146f34223bbd3b5.test
vendored
Normal file
BIN
tests/fixtures/dd/random-5828891cb1230748e146f34223bbd3b5.test
vendored
Normal file
Binary file not shown.
1
tests/fixtures/split/twohundredfortyonebytes.txt
vendored
Normal file
1
tests/fixtures/split/twohundredfortyonebytes.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
Loading…
Add table
Add a link
Reference in a new issue