| use super::{copy_encode, decode_all, encode_all}; |
| use super::{Decoder, Encoder}; |
| |
| use partial_io::{PartialOp, PartialWrite}; |
| |
| use std::io; |
| use std::iter; |
| |
| #[test] |
| fn test_end_of_frame() { |
| use std::io::{Read, Write}; |
| |
| let mut enc = Encoder::new(Vec::new(), 1).unwrap(); |
| enc.write_all(b"foo").unwrap(); |
| let mut compressed = enc.finish().unwrap(); |
| |
| // Add footer/whatever to underlying storage. |
| compressed.push(0); |
| |
| // Drain zstd stream until end-of-frame. |
| let mut dec = Decoder::new(&compressed[..]).unwrap().single_frame(); |
| let mut buf = Vec::new(); |
| dec.read_to_end(&mut buf).unwrap(); |
| assert_eq!(&buf, b"foo", "Error decoding a single frame."); |
| } |
| |
| #[test] |
| fn test_concatenated_frames() { |
| let mut buffer = Vec::new(); |
| copy_encode(&b"foo"[..], &mut buffer, 1).unwrap(); |
| copy_encode(&b"bar"[..], &mut buffer, 2).unwrap(); |
| copy_encode(&b"baz"[..], &mut buffer, 3).unwrap(); |
| |
| assert_eq!( |
| &decode_all(&buffer[..]).unwrap(), |
| b"foobarbaz", |
| "Error decoding concatenated frames." |
| ); |
| } |
| |
| #[test] |
| fn test_flush() { |
| use std::io::Write; |
| |
| let buf = Vec::new(); |
| let mut z = Encoder::new(buf, 19).unwrap(); |
| |
| z.write_all(b"hello").unwrap(); |
| |
| z.flush().unwrap(); // Might corrupt stream |
| let buf = z.finish().unwrap(); |
| |
| let s = decode_all(&buf[..]).unwrap(); |
| assert_eq!(s, b"hello", "Error decoding after flush."); |
| } |
| |
| #[test] |
| fn test_try_finish() { |
| use std::io::Write; |
| let mut z = setup_try_finish(); |
| |
| z.get_mut().set_ops(iter::repeat(PartialOp::Unlimited)); |
| |
| // flush() should continue to work even though write() doesn't. |
| z.flush().unwrap(); |
| |
| let buf = match z.try_finish() { |
| Ok(buf) => buf.into_inner(), |
| Err((_z, e)) => panic!("try_finish failed with {:?}", e), |
| }; |
| |
| // Make sure the multiple try_finish calls didn't screw up the internal |
| // buffer and continued to produce valid compressed data. |
| assert_eq!(&decode_all(&buf[..]).unwrap(), b"hello", "Error decoding"); |
| } |
| |
| #[test] |
| #[should_panic] |
| fn test_write_after_try_finish() { |
| use std::io::Write; |
| let mut z = setup_try_finish(); |
| z.write_all(b"hello world").unwrap(); |
| } |
| |
| fn setup_try_finish() -> Encoder<'static, PartialWrite<Vec<u8>>> { |
| use std::io::Write; |
| |
| let buf = |
| PartialWrite::new(Vec::new(), iter::repeat(PartialOp::Unlimited)); |
| let mut z = Encoder::new(buf, 19).unwrap(); |
| |
| z.write_all(b"hello").unwrap(); |
| |
| z.get_mut() |
| .set_ops(iter::repeat(PartialOp::Err(io::ErrorKind::WouldBlock))); |
| |
| let (z, err) = z.try_finish().unwrap_err(); |
| assert_eq!( |
| err.kind(), |
| io::ErrorKind::WouldBlock, |
| "expected WouldBlock error" |
| ); |
| |
| z |
| } |
| |
| #[test] |
| fn test_failing_write() { |
| use std::io::Write; |
| |
| let buf = PartialWrite::new( |
| Vec::new(), |
| iter::repeat(PartialOp::Err(io::ErrorKind::WouldBlock)), |
| ); |
| let mut z = Encoder::new(buf, 1).unwrap(); |
| |
| // Fill in enough data to make sure the buffer gets written out. |
| let input = vec![b'b'; 128 * 1024]; |
| // This should work even though the inner writer rejects writes. |
| assert_eq!( |
| z.write(&input).unwrap(), |
| 128 * 1024, |
| "did not write all input buffer" |
| ); |
| |
| // The next write would fail (the buffer still has some data in it). |
| assert_eq!( |
| z.write(b"abc").unwrap_err().kind(), |
| io::ErrorKind::WouldBlock, |
| "expected WouldBlock error" |
| ); |
| |
| z.get_mut().set_ops(iter::repeat(PartialOp::Unlimited)); |
| |
| // This shouldn't have led to any corruption. |
| let buf = z.finish().unwrap().into_inner(); |
| assert_eq!( |
| &decode_all(&buf[..]).unwrap(), |
| &input, |
| "WouldBlock errors should not corrupt stream" |
| ); |
| } |
| |
| #[test] |
| fn test_invalid_frame() { |
| use std::io::Read; |
| |
| // I really hope this data is invalid... |
| let data = &[1u8, 2u8, 3u8, 4u8, 5u8]; |
| let mut dec = Decoder::new(&data[..]).unwrap(); |
| assert_eq!( |
| dec.read_to_end(&mut Vec::new()).err().map(|e| e.kind()), |
| Some(io::ErrorKind::Other), |
| "did not encounter expected 'invalid frame' error" |
| ); |
| } |
| |
| #[test] |
| fn test_incomplete_frame() { |
| use std::io::{Read, Write}; |
| |
| let mut enc = Encoder::new(Vec::new(), 1).unwrap(); |
| enc.write_all(b"This is a regular string").unwrap(); |
| let mut compressed = enc.finish().unwrap(); |
| |
| let half_size = compressed.len() - 2; |
| compressed.truncate(half_size); |
| |
| let mut dec = Decoder::new(&compressed[..]).unwrap(); |
| assert_eq!( |
| dec.read_to_end(&mut Vec::new()).err().map(|e| e.kind()), |
| Some(io::ErrorKind::UnexpectedEof), |
| "did not encounter expected EOF error" |
| ); |
| } |
| |
| #[test] |
| fn test_cli_compatibility() { |
| let input = include_bytes!("../../assets/example.txt.zst"); |
| |
| let output = decode_all(&input[..]).unwrap(); |
| |
| let expected = include_bytes!("../../assets/example.txt"); |
| |
| assert_eq!( |
| &output[..], |
| &expected[..], |
| "error decoding cli-compressed data" |
| ); |
| } |
| |
| #[cfg(feature = "legacy")] |
| #[test] |
| fn test_legacy() { |
| use std::fs; |
| use std::io::Read; |
| |
| // Read the content from that file |
| let expected = include_bytes!("../../assets/example.txt"); |
| |
| for version in &[5, 6, 7, 8] { |
| let filename = format!("assets/example.txt.v{}.zst", version); |
| let file = fs::File::open(filename).unwrap(); |
| let mut decoder = Decoder::new(file).unwrap(); |
| |
| let mut buffer = Vec::new(); |
| decoder.read_to_end(&mut buffer).unwrap(); |
| |
| assert_eq!( |
| &expected[..], |
| &buffer[..], |
| "error decompressing legacy version {}", |
| version |
| ); |
| } |
| } |
| |
| // Check that compressing+decompressing some data gives back the original |
| fn test_full_cycle(input: &[u8], level: i32) { |
| crate::test_cycle_unwrap( |
| input, |
| |data| encode_all(data, level), |
| |data| decode_all(data), |
| ); |
| } |
| |
| #[test] |
| fn test_empty() { |
| // Test compressing empty data |
| for level in 1..19 { |
| test_full_cycle(b"", level); |
| } |
| } |
| |
| #[test] |
| fn test_ll_source() { |
| // Where could I find some long text?... |
| let data = include_bytes!("../../zstd-safe/zstd-sys/src/bindings_zstd.rs"); |
| // Test a few compression levels. |
| // TODO: check them all? |
| for level in 1..5 { |
| // Test compressing actual data |
| test_full_cycle(data, level); |
| } |
| } |
| |
| #[test] |
| fn reader_to_writer() { |
| use std::io::{Read, Write}; |
| |
| let clear = include_bytes!("../../assets/example.txt"); |
| // Compress using reader |
| let mut encoder = super::read::Encoder::new(&clear[..], 1).unwrap(); |
| |
| let mut compressed_buffer = Vec::new(); |
| encoder.read_to_end(&mut compressed_buffer).unwrap(); |
| |
| // eprintln!("Compressed Buffer: {:?}", compressed_buffer); |
| |
| // Decompress using writer |
| let mut decompressed_buffer = Vec::new(); |
| let mut decoder = |
| super::write::Decoder::new(&mut decompressed_buffer).unwrap(); |
| decoder.write_all(&compressed_buffer[..]).unwrap(); |
| decoder.flush().unwrap(); |
| // eprintln!("{:?}", decompressed_buffer); |
| |
| assert_eq!(clear, &decompressed_buffer[..]); |
| } |