justcsv 0.2.0

Simple CSV-file reader/writer
Documentation
mod error;
mod parse;
mod reader;
mod writer;

pub use error::{Error, Result};
pub use reader::{CsvReader, CsvReaderConfig};
pub use writer::{CsvWriter, CsvWriterConfig, NewLine};

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn reader_works() {
        let buf = "1,2,3\n4,5,6".as_bytes();
        let mut reader = reader::CsvReader::new(buf);
        assert_eq!(
            vec!["1", "2", "3"],
            reader.next().unwrap().unwrap().into_vec()
        );
        assert_eq!(
            vec!["4", "5", "6"],
            reader.next().unwrap().unwrap().into_vec()
        );
        assert!(reader.next().is_none())
    }

    #[test]
    fn empty_reader() {
        let buf = "".as_bytes();
        let mut reader = reader::CsvReader::new(buf);
        assert!(dbg!(reader.next()).is_none());
    }

    #[test]
    fn escaped_read() {
        let buf = "\"1\",2,3\r\n4, \"5\",6".as_bytes();
        let mut reader = reader::CsvReader::new(buf);
        assert_eq!(
            vec!["1", "2", "3"],
            reader.next().unwrap().unwrap().into_vec()
        );
        assert_eq!(
            vec!["4", "5", "6"],
            reader.next().unwrap().unwrap().into_vec()
        );
        assert!(reader.next().is_none())
    }

    #[test]
    fn multiline_read() {
        let buf = "\"1\",2,3\r\n4, \"everybody needs\nmilk\",6".as_bytes();
        let mut reader = reader::CsvReader::new(buf);
        assert_eq!(
            vec!["1", "2", "3"],
            reader.next().unwrap().unwrap().into_vec()
        );
        assert_eq!(
            vec!["4", "everybody needs\nmilk", "6"],
            reader.next().unwrap().unwrap().into_vec()
        );
        assert!(reader.next().is_none())
    }

    #[test]
    fn quoted_read_fail() {
        let buf =
            "\"1\",2,3\r\n4, \"everybody needs\nmilk,6\r\nsome other stuff which is never read"
                .as_bytes();
        let mut reader = reader::CsvReader::new(buf);
        assert_eq!(
            vec!["1", "2", "3"],
            reader.next().unwrap().unwrap().into_vec()
        );
        assert!(reader.next().unwrap().is_err());
        assert!(reader.next().is_none())
    }

    #[test]
    fn read_last_line() {
        let buf = "1,2,3\r\n4,5,\r\n".as_bytes();
        let mut reader = reader::CsvReader::new(buf);
        assert_eq!(
            vec!["1", "2", "3"],
            reader.next().unwrap().unwrap().into_vec()
        );
        assert_eq!(
            vec!["4", "5", ""],
            reader.next().unwrap().unwrap().into_vec()
        );
        assert!(reader.next().is_none())
    }

    #[test]
    fn read_bad_escaping() {
        let buf = "1,2,3\r\n4,\"5\"xyz,6\r\n\"7\",8,9".as_bytes();
        let mut reader = reader::CsvReader::new(buf);
        assert_eq!(
            vec!["1", "2", "3"],
            reader.next().unwrap().unwrap().into_vec()
        );
        assert!(reader.next().unwrap().is_err());
        assert_eq!(
            vec!["7", "8", "9"],
            reader.next().unwrap().unwrap().into_vec()
        )
    }

    #[test]
    fn read_headers() {
        let buf = "Col 1,Col 2, \"Col 3\"\r\n1,2,3\r\n4,\"5\",6".as_bytes();
        let mut reader = reader::CsvReader::with_config(
            buf,
            CsvReaderConfig {
                has_headers: true,
                ..Default::default()
            },
        );
        assert_eq!(
            vec!["Col 1", "Col 2", "Col 3"],
            reader.headers().unwrap().to_vec()
        );
        assert_eq!(
            vec!["1", "2", "3"],
            reader.next().unwrap().unwrap().into_vec()
        );
        assert_eq!(
            vec!["4", "5", "6"],
            reader.next().unwrap().unwrap().into_vec()
        );
    }

    #[test]
    fn writer_works() {
        let mut buf = Vec::new();
        let row = vec!["1", "2", "3"];
        let mut writer = CsvWriter::new(&mut buf);
        writer.write_row(&row).unwrap();
        writer.write_row(["4", "5\"abc\"X", "6\n\tagain"]).unwrap();
        assert_eq!(
            b"1,2,3\r\n4,\"5\"\"abc\"\"X\",\"6\n\tagain\"",
            buf.as_slice()
        );
    }
}