dd-lib 0.2.1

library functions for a clone of the unix coreutil dd
Documentation
use super::{
    read::{InnerReader, Reader},
    ErrHandler, *,
};
use opts;
use results::*;
use std::{
    io::{Cursor, Read, Seek, SeekFrom},
    iter::{once, repeat},
};

extern crate encoding8;

#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
struct MockErr;
impl std::io::Write for MockErr {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<(usize)> { Ok(buf.len()) }

    fn flush(&mut self) -> std::io::Result<()> { Ok(()) }
}

fn mockerr() -> ErrHandler<MockErr> {
    let o = opts::Opts::default();
    ErrHandler::new(MockErr, &o)
}

#[test]
fn test_standard() {
    let reader: Vec<u8> = LOREM_IPSUM.bytes().collect();
    let reader = InnerReader::R(Cursor::new(reader));
    let c = encoding8::ascii::to_uppercase;
    let mut w = Cursor::new(Vec::with_capacity(1000));

    copy::standard(Reader::basic(reader, 512), &mut w, c, mockerr()).unwrap();
    w.seek(SeekFrom::Start(0)).unwrap();
    let got: Vec<u8> = w.bytes().take(LOREM_IPSUM.len()).map(|b| b.unwrap()).collect();

    let want: Vec<u8> = LOREM_IPSUM.bytes().map(encoding8::ascii::to_uppercase).collect();
    assert_eq!(got, want);
}

fn reader<I: IntoIterator<Item = u8>>(it: I, block_size: usize) -> Reader<'static, Cursor<Vec<u8>>> {
    let v: Vec<u8> = it.into_iter().collect();

    Reader::basic(InnerReader::R(Cursor::new(v)), block_size)
}

#[test]
fn test_block() {
    const BLOCK_SIZE: usize = 10;

    let input = once(b'\n')
        .chain(repeat(b'a').take(BLOCK_SIZE - 5))
        .chain(repeat(b'\n').take(2))
        .chain(repeat(b'b').take(BLOCK_SIZE + 5))
        .chain(once(b'\n'))
        .chain(repeat(b'c').take(BLOCK_SIZE));
    let r = reader(input, BLOCK_SIZE);
    const WANT: &str = concat!("AAAAA", "     ", "BBBBB", "BBBBB", "CCCCC", "CCCCC");

    let mut w = Cursor::new(Vec::with_capacity(1000));

    let res = copy::block(r, &mut w, encoding8::ascii::to_uppercase, mockerr(), BLOCK_SIZE);
    if let Success::Block {
        truncated,
        padded,
        lines,
        block_size,
        ..
    } = res.unwrap()
    {
        assert_eq!(truncated, 1, "truncated={}, but should be {}", truncated, 2);
        assert_eq!(padded, 1, "padded = {}, but should be {}", padded, 1);
        assert_eq!(lines, 3, "total lines = {}, but should be {}", lines, 3);
        assert_eq!(BLOCK_SIZE, block_size);
    } else {
        unreachable!()
    };

    w.seek(SeekFrom::Start(0)).unwrap();
    let mut s = String::new();
    w.read_to_string(&mut s).unwrap();
    assert_eq!(WANT, s);
}
#[test]
fn test_unblock() {
    const BLOCK_SIZE: usize = 5;

    let input = concat!("aaaaa", "  ", "bbbbb", "ccccc", "      ", "dd");
    const WANT: &str = "AAAAA\nBBBBB\nCCCCC\nDD\n";
    let r = reader(input.bytes(), BLOCK_SIZE);
    let mut w = Cursor::new(Vec::with_capacity(1000));

    copy::unblock(r, &mut w, encoding8::ascii::to_uppercase, mockerr(), BLOCK_SIZE).unwrap();
    w.seek(SeekFrom::Start(0)).unwrap();
    let mut got: String = String::new();
    w.read_to_string(&mut got).unwrap();
    assert_eq!(WANT, got)
}

#[test]
fn test_limited_copy() {
    // perfectly divisible
    let block_size: usize = 5;
    let max_bytes: usize = 30;
    let r = reader(LOREM_IPSUM.bytes(), block_size);
    let mut w = Cursor::new(Vec::with_capacity(100));
    let (got, want): (Vec<u8>, Vec<u8>);

    if let Success::Bytes { bytes, .. } = copy::bytes(r, &mut w, &no_op, mockerr(), max_bytes).unwrap() {
        assert_eq!(bytes, max_bytes);
        w.seek(SeekFrom::Start(0)).unwrap();
        got = w.bytes().take(bytes).map(|b| b.unwrap()).collect();
        want = LOREM_IPSUM.bytes().take(max_bytes).collect();
    } else {
        panic!()
    }
    assert_eq!(want, got);

    // perfectly divisible
    let block_size = 4;
    let r = reader(LOREM_IPSUM.bytes(), block_size);
    let mut w = Cursor::new(Vec::with_capacity(100));

    copy::bytes(r, &mut w, &no_op, mockerr(), max_bytes).unwrap();
    w.seek(SeekFrom::Start(0)).unwrap();

    let got: Vec<u8> = w.bytes().take(max_bytes).map(|b| b.unwrap()).collect();
    let want: Vec<u8> = LOREM_IPSUM.bytes().take(max_bytes).collect();
    assert_eq!(want, got)
}

fn no_op<T>(t: T) -> T { t }

const LOREM_IPSUM: &str = concat!(
    "Lorem ipsum dolor sit amet ",
    "consectetur adipiscing elit, ",
    "sed do eiusmod tempor incididunt ut labore ",
    "et dolore magna aliqua. ",
    "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris ",
    "nisi ut aliquip ex ea commodo consequat. ",
    "Duis aute irure dolor instn reprehenderit in voluptate velit esse ",
    " cillum dolore eu fugiat nulla pariatur. ",
    "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \n"
);