extern crate libdeflater; use std::fs::File; use std::io::Read; use std::vec::Vec; use std::error::Error; use std::thread; use libdeflater::{Compressor, CompressionLvl, CompressionError, Decompressor, DecompressionError, CompressionLvlError}; use flate2; // decompression #[test] fn test_can_create_new_decompressor() { Decompressor::new(); } fn read_fixture(pth: &str) -> Vec { let mut f = File::open(pth).unwrap(); let mut content = Vec::new(); f.read_to_end(&mut content).unwrap(); content } fn read_fixture_content() -> Vec { read_fixture("tests/hello") } fn fixture_content_size() -> usize { read_fixture_content().len() } fn read_fixture_gz() -> Vec { read_fixture("tests/hello.gz") } fn read_fixture_gz_with_bad_magic_num() -> Vec { let mut data = read_fixture_gz(); // beats having to have an extra fixture file data[0] = 0x00; data } fn read_fixture_gz_with_bad_crc32() -> Vec { let mut data = read_fixture_gz(); let crc32_start = data.len()-8; // beats having to have an extra fixture file data[crc32_start] = data[crc32_start] + 1; data } fn read_fixture_gz_with_bad_isize() -> Vec { let mut data = read_fixture_gz(); let isize_start = data.len()-4; // beats having to have an extra fixture file data[isize_start] = data[isize_start] + 1; data } fn read_fixture_zlib() -> Vec { read_fixture("tests/hello.zz") } fn read_fixture_zlib_with_bad_cmf_field() -> Vec { const BAD_CM: u8 = 9; // RFC1950: val == 8 for deflate const BAD_CINFO: u8 = 8; // RFC1950: vals > 7 disallowed const BAD_CMF: u8 = ((BAD_CM << 4) & 0xf0) | (BAD_CINFO & 0x0f); let mut data = read_fixture_zlib(); data[0] = BAD_CMF; data } fn read_fixture_zlib_with_bad_adler32_checksum() -> Vec { let mut data = read_fixture_zlib(); let adler32_start = data.len() - 4; data[adler32_start] = data[adler32_start] + 1; data } fn read_fixture_deflate() -> Vec { read_fixture("tests/hello.deflate") } #[test] fn test_decompression_error_derives_error() { let bd = DecompressionError::BadData; let _e = (&bd) as &(dyn Error); } #[test] fn test_can_send_decompressor_to_another_thread() { // note: this is a compile-time test: it just ensures that a // `Decompressor` can be sent between threads easily (i.e. that // `Decompressor` implements `Send`) let mut decompressor = Decompressor::new(); let t = thread::spawn(move || { let content = read_fixture_gz(); let mut decompressed = Vec::new(); decompressed.resize(fixture_content_size(), 0); decompressor.gzip_decompress(&content, &mut decompressed).unwrap(); }); t.join().unwrap() } #[test] fn test_can_send_compressor_to_another_thread() { // note: this is a compile-time test: it just ensures that a // Compressor can be sent between threads easily (i.e. that // `Compressor` implements `Send`) let mut compressor = Compressor::new(CompressionLvl::default()); let t = thread::spawn(move || { let in_data = read_fixture_content(); let mut out_data = Vec::new(); let out_max_sz = compressor.deflate_compress_bound(in_data.len()); out_data.resize(out_max_sz, 0); compressor.deflate_compress(&in_data, &mut out_data).unwrap(); }); t.join().unwrap() } // gz decompression #[test] fn test_calling_gzip_decompress_with_valid_args_works() { let mut decompressor = Decompressor::new(); let content = read_fixture_gz(); let mut decompressed = Vec::new(); decompressed.resize(fixture_content_size(), 0); decompressor.gzip_decompress(&content, &mut decompressed).unwrap(); } #[test] fn test_calling_gzip_decompress_with_undersized_outbuf_returns_insufficient_space() { let result = { let mut decompressor = Decompressor::new(); let content = read_fixture_gz(); let mut decompressed = Vec::new(); decompressor.gzip_decompress(&content, &mut decompressed) }; assert_eq!(result.unwrap_err(), DecompressionError::InsufficientSpace); } #[test] fn test_calling_gzip_decompress_with_valid_buf_fills_buf_with_expected_content() { let decompressed = { let mut decompressor = Decompressor::new(); let content = read_fixture_gz(); let mut decompressed = Vec::new(); decompressed.resize(fixture_content_size(), 0); decompressor.gzip_decompress(&content, &mut decompressed).unwrap(); decompressed }; let expected_content = read_fixture_content(); assert_eq!(decompressed, expected_content); } #[test] fn test_calling_gzip_decompress_with_oversized_buf_returns_correct_size() { const OVERSIZED_FACTOR: usize = 2; let sz = { let mut decompressor = Decompressor::new(); let content = read_fixture_gz(); let mut decompressed = Vec::new(); decompressed.resize(OVERSIZED_FACTOR*fixture_content_size(), 0); let sz = decompressor.gzip_decompress(&content, &mut decompressed).unwrap(); sz }; assert_eq!(sz, fixture_content_size()); } #[test] fn test_calling_gzip_decompress_with_bad_magic_num_returns_bad_data() { let mut decompressor = Decompressor::new(); let content = read_fixture_gz_with_bad_magic_num(); let mut decompressed = Vec::new(); decompressed.resize(fixture_content_size(), 0); let result = decompressor.gzip_decompress(&content, &mut decompressed); assert_eq!(result.unwrap_err(), DecompressionError::BadData); } #[test] fn test_calling_gzip_decompress_with_corrupted_crc32_returns_bad_data() { let mut decompressor = Decompressor::new(); let content = read_fixture_gz_with_bad_crc32(); let mut decompressed = Vec::new(); decompressed.resize(fixture_content_size(), 0); let result = decompressor.gzip_decompress(&content, &mut decompressed); assert_eq!(result.unwrap_err(), DecompressionError::BadData); } #[test] fn test_calling_gzip_decompress_with_corrupted_isize_returns_bad_data() { let mut decompressor = Decompressor::new(); let content = read_fixture_gz_with_bad_isize(); let mut decompressed = Vec::new(); decompressed.resize(fixture_content_size(), 0); let result = decompressor.gzip_decompress(&content, &mut decompressed); assert_eq!(result.unwrap_err(), DecompressionError::BadData); } // zlib decompression #[test] fn test_calling_zlib_decompress_with_valid_args_works() { let mut decompressor = Decompressor::new(); let content = read_fixture_zlib(); let mut decompressed = Vec::new(); decompressed.resize(fixture_content_size(), 0); decompressor.zlib_decompress(&content, &mut decompressed).unwrap(); } #[test] fn test_calling_zlib_decompress_with_undersized_outbuf_returns_insufficient_space() { let result = { let mut decompressor = Decompressor::new(); let content = read_fixture_zlib(); let mut decompressed = Vec::with_capacity(0); decompressor.zlib_decompress(&content, &mut decompressed) }; assert_eq!(result.unwrap_err(), DecompressionError::InsufficientSpace); } #[test] fn test_calling_zlib_decompress_with_valid_buf_fills_buf_with_expected_content() { let decompressed_content = { let mut decompressor = Decompressor::new(); let content = read_fixture_zlib(); let mut decompressed = Vec::new(); decompressed.resize(fixture_content_size(), 0); decompressor.zlib_decompress(&content, &mut decompressed).unwrap(); decompressed }; let expected_content = read_fixture_content(); assert_eq!(decompressed_content, expected_content); } #[test] fn test_calling_zlib_decompress_with_oversized_buf_returns_correct_size() { const OVERSIZED_FACTOR: usize = 2; let sz = { let mut decompressor = Decompressor::new(); let content = read_fixture_zlib(); let mut decompressed = Vec::new(); decompressed.resize(OVERSIZED_FACTOR*fixture_content_size(), 0); let sz = decompressor.zlib_decompress(&content, &mut decompressed).unwrap(); sz }; assert_eq!(sz, fixture_content_size()); } #[test] fn test_calling_zlib_decompress_with_bad_cmf_field_returns_bad_data() { let ret = { let mut decompressor = Decompressor::new(); let content = read_fixture_zlib_with_bad_cmf_field(); let mut decompressed = Vec::new(); decompressed.resize(fixture_content_size(), 0); decompressor.zlib_decompress(&content, &mut decompressed) }; assert_eq!(ret.unwrap_err(), DecompressionError::BadData); } #[test] fn test_calling_zlib_decompress_with_bad_adler32_checksum_returns_bad_data() { let ret = { let mut decompressor = Decompressor::new(); let content = read_fixture_zlib_with_bad_adler32_checksum(); let mut decompressed = Vec::new(); decompressed.resize(fixture_content_size(), 0); decompressor.zlib_decompress(&content, &mut decompressed) }; assert_eq!(ret.unwrap_err(), DecompressionError::BadData); } // DEFLATE decompression #[test] fn test_calling_deflate_decompress_with_valid_args_works() { let mut decompressor = Decompressor::new(); let content = read_fixture_deflate(); let mut decompressed = Vec::new(); decompressed.resize(fixture_content_size(), 0); decompressor.deflate_decompress(&content, &mut decompressed).unwrap(); } #[test] fn test_calling_deflate_decompress_with_undersized_outbuf_returns_insufficient_space() { let result = { let mut decompressor = Decompressor::new(); let content = read_fixture_deflate(); let mut decompressed = Vec::with_capacity(0); decompressor.deflate_decompress(&content, &mut decompressed) }; assert_eq!(result.unwrap_err(), DecompressionError::InsufficientSpace); } #[test] fn test_calling_deflate_decompress_with_valid_buf_fills_buf_with_expected_content() { let decompressed_content = { let mut decompressor = Decompressor::new(); let content = read_fixture_deflate(); let mut decompressed = Vec::new(); decompressed.resize(fixture_content_size(), 0); decompressor.deflate_decompress(&content, &mut decompressed).unwrap(); decompressed }; let expected_content = read_fixture_content(); assert_eq!(decompressed_content, expected_content); } #[test] fn test_calling_deflate_decompress_with_oversized_buf_returns_correct_size() { const OVERSIZED_FACTOR: usize = 2; let sz = { let mut decompressor = Decompressor::new(); let content = read_fixture_deflate(); let mut decompressed = Vec::new(); decompressed.resize(OVERSIZED_FACTOR*fixture_content_size(), 0); let sz = decompressor.deflate_decompress(&content, &mut decompressed).unwrap(); sz }; assert_eq!(sz, fixture_content_size()); } // compression #[test] fn test_compression_lvl_new_returns_ok_for_0() { // see issuse #21 - some use-cases require uncompressed blocks CompressionLvl::new(0).unwrap(); } #[test] fn test_compression_lvl_new_returns_ok_for_7() { CompressionLvl::new(7).unwrap(); } #[test] fn test_compression_lvl_new_returns_err_for_13() { // If libdeflate changes in the future this test will need to be // scrapped, but it's ok as a smoke test let ret = CompressionLvl::new(13).unwrap_err(); assert_eq!(ret, CompressionLvlError::InvalidValue); } #[test] fn test_compressor_with_fastest_compression_lvl_calls_with_no_panics() { Compressor::new(CompressionLvl::fastest()); } #[test] fn test_compressor_with_default_compression_lvl_calls_with_no_panics() { Compressor::new(CompressionLvl::default()); } #[test] fn test_compressor_with_best_compression_lvl_calls_with_no_panics() { Compressor::new(CompressionLvl::best()); } #[test] fn test_compression_iter_starts_at_compression_lvl_zero() { let val = CompressionLvl::iter().next().unwrap(); assert_eq!(val, CompressionLvl::fastest()); assert_eq!(val, CompressionLvl::new(0).unwrap()); } #[test] fn test_compressor_with_compression_lvl_can_be_called_with_all_lvls_with_no_panics() { for lvl in CompressionLvl::iter() { Compressor::new(lvl); } } // compress DEFLATE #[test] fn test_compressor_deflate_compress_bound_returns_nonzero_when_given_nonzero_input() { let returned_bound = { let mut compressor = Compressor::new(CompressionLvl::default()); compressor.deflate_compress_bound(1) }; assert_ne!(returned_bound, 0); } #[test] fn test_compressor_deflate_compress_with_valid_args_does_not_panic() { let mut compressor = Compressor::new(CompressionLvl::default()); let in_data = read_fixture_content(); let mut out_data = Vec::new(); let out_max_sz = compressor.deflate_compress_bound(in_data.len()); out_data.resize(out_max_sz, 0); compressor.deflate_compress(&in_data, &mut out_data).unwrap(); } #[test] fn test_compressor_deflate_compress_with_undersized_buf_returns_insufficient_space() { let ret = { let mut compressor = Compressor::new(CompressionLvl::default()); let in_data = read_fixture_content(); let mut out_data = Vec::new(); compressor.deflate_compress(&in_data, &mut out_data) }; assert_eq!(ret.unwrap_err(), CompressionError::InsufficientSpace); } #[test] fn test_compressor_deflate_compress_with_correct_args_returns_a_nonzero_size() { let ret = { let mut compressor = Compressor::new(CompressionLvl::default()); let in_data = read_fixture_content(); let mut out_data = Vec::new(); let out_max_sz = compressor.deflate_compress_bound(in_data.len()); out_data.resize(out_max_sz, 0); compressor.deflate_compress(&in_data, &mut out_data).unwrap() }; assert_ne!(0, ret); } #[test] fn test_compressor_deflate_compress_with_correct_args_resized_outbuf_to_return_val_produces_nonempty_nonzero_data() { // This is, give or take, essentially how users *should* use the // lib for raw DEFLATE compressions let compressed_data = { let mut compressor = Compressor::new(CompressionLvl::default()); let in_data = read_fixture_content(); let mut out_data = Vec::new(); let out_max_sz = compressor.deflate_compress_bound(in_data.len()); out_data.resize(out_max_sz, 0); let sz = compressor.deflate_compress(&in_data, &mut out_data).unwrap(); out_data.resize(sz, 0); out_data }; assert_ne!(compressed_data.len(), 0); assert!(compressed_data.iter().any(|byte| *byte != 0x00)); } // compress zlib #[test] fn test_compressor_zlib_compress_bound_returns_nonzero_when_given_nonzero_input() { let returned_bound = { let mut compressor = Compressor::new(CompressionLvl::default()); compressor.zlib_compress_bound(1) }; assert_ne!(returned_bound, 0); } #[test] fn test_compressor_compresss_zlib_with_valid_args_does_not_panic() { let mut compressor = Compressor::new(CompressionLvl::default()); let in_data = read_fixture_content(); let mut out_data = Vec::new(); let out_max_sz = compressor.zlib_compress_bound(in_data.len()); out_data.resize(out_max_sz, 0); compressor.zlib_compress(&in_data, &mut out_data).unwrap(); } #[test] fn test_compressor_zlib_compress_with_undersized_outbuf_returns_insufficient_space() { let ret = { let mut compressor = Compressor::new(CompressionLvl::default()); let in_data = read_fixture_content(); let mut out_data = Vec::new(); compressor.zlib_compress(&in_data, &mut out_data) }; assert_eq!(ret.unwrap_err(), CompressionError::InsufficientSpace); } #[test] fn test_compressor_zlib_compress_with_correct_args_returns_nonzero_size() { let ret = { let mut compressor = Compressor::new(CompressionLvl::default()); let in_data = read_fixture_content(); let mut out_data = Vec::new(); let out_max_sz = compressor.zlib_compress_bound(in_data.len()); out_data.resize(out_max_sz, 0); compressor.zlib_compress(&in_data, &mut out_data).unwrap() }; assert_ne!(ret, 0); } #[test] fn test_compressor_zlib_compress_with_correct_args_resized_outbuf_to_return_val_produces_nonempty_nonzero_data() { // This is, give or take, essentially how users *should* use the // lib for zlib compressions let compressed_data = { let mut compressor = Compressor::new(CompressionLvl::default()); let in_data = read_fixture_content(); let mut out_data = Vec::new(); let out_max_sz = compressor.zlib_compress_bound(in_data.len()); out_data.resize(out_max_sz, 0); let sz = compressor.zlib_compress(&in_data, &mut out_data).unwrap(); out_data.resize(sz, 0); out_data }; assert_ne!(compressed_data.len(), 0); assert!(compressed_data.iter().any(|byte| *byte != 0x00)); } // compress gzip #[test] fn test_compressor_gzip_compress_bound_returns_nonzero_when_given_nonzero_input() { let returned_bound = { let mut compressor = Compressor::new(CompressionLvl::default()); compressor.gzip_compress_bound(1) }; assert_ne!(returned_bound, 0); } #[test] fn test_compressor_compresss_gzip_with_valid_args_does_not_panic() { let mut compressor = Compressor::new(CompressionLvl::default()); let in_data = read_fixture_content(); let mut out_data = Vec::new(); let out_max_sz = compressor.gzip_compress_bound(in_data.len()); out_data.resize(out_max_sz, 0); compressor.gzip_compress(&in_data, &mut out_data).unwrap(); } #[test] fn test_compressor_gzip_compress_with_undersized_outbuf_returns_insufficient_space() { let ret = { let mut compressor = Compressor::new(CompressionLvl::default()); let in_data = read_fixture_content(); let mut out_data = Vec::new(); compressor.gzip_compress(&in_data, &mut out_data) }; assert_eq!(ret.unwrap_err(), CompressionError::InsufficientSpace); } #[test] fn test_compressor_gzip_compress_with_correct_args_returns_nonzero_size() { let ret = { let mut compressor = Compressor::new(CompressionLvl::default()); let in_data = read_fixture_content(); let mut out_data = Vec::new(); let out_max_sz = compressor.gzip_compress_bound(in_data.len()); out_data.resize(out_max_sz, 0); compressor.gzip_compress(&in_data, &mut out_data).unwrap() }; assert_ne!(ret, 0); } #[test] fn test_compressor_gzip_compress_with_correct_args_resized_outbuf_to_return_val_produces_nonempty_nonzero_data() { // This is, give or take, essentially how users *should* use the // lib for gzip compressions let compressed_data = { let mut compressor = Compressor::new(CompressionLvl::default()); let in_data = read_fixture_content(); let mut out_data = Vec::new(); let out_max_sz = compressor.gzip_compress_bound(in_data.len()); out_data.resize(out_max_sz, 0); let sz = compressor.gzip_compress(&in_data, &mut out_data).unwrap(); out_data.resize(sz, 0); out_data }; assert_ne!(compressed_data.len(), 0); assert!(compressed_data.iter().any(|byte| *byte != 0x00)); } // compress + decompress (full-cycle tests) #[test] fn test_zlib_compress_then_zlib_decompress_works_and_produces_the_same_input_data() { let input_data = read_fixture_content(); let compression_buf = { let mut compressor = Compressor::new(CompressionLvl::default()); let mut compression_buf = Vec::new(); let compressed_max_sz = compressor.zlib_compress_bound(input_data.len()); compression_buf.resize(compressed_max_sz, 0); let compressed_sz = compressor.zlib_compress(&input_data, &mut compression_buf).unwrap(); compression_buf.resize(compressed_sz, 0); compression_buf }; let decompressed_buf = { let mut decompressor = Decompressor::new(); let mut decompressed_buf = Vec::new(); decompressed_buf.resize(input_data.len(), 0); let decompressed_sz = decompressor.zlib_decompress(&compression_buf, &mut decompressed_buf).unwrap(); assert_eq!(decompressed_sz, input_data.len()); decompressed_buf }; assert_eq!(input_data, decompressed_buf); } #[test] fn test_deflate_compress_then_deflate_decompress_works_and_produces_the_same_input_data() { let input_data = read_fixture_content(); let compression_buf = { let mut compressor = Compressor::new(CompressionLvl::default()); let mut compression_buf = Vec::new(); let compressed_max_sz = compressor.deflate_compress_bound(input_data.len()); compression_buf.resize(compressed_max_sz, 0); let compressed_sz = compressor.deflate_compress(&input_data, &mut compression_buf).unwrap(); compression_buf.resize(compressed_sz, 0); compression_buf }; let decompressed_buf = { let mut decompressor = Decompressor::new(); let mut decompressed_buf = Vec::new(); decompressed_buf.resize(input_data.len(), 0); let decompressed_sz = decompressor.deflate_decompress(&compression_buf, &mut decompressed_buf).unwrap(); assert_eq!(decompressed_sz, input_data.len()); decompressed_buf }; assert_eq!(input_data, decompressed_buf); } #[test] fn test_gzip_compress_then_gzip_decompress_works_and_produces_the_same_input_data() { let input_data = read_fixture_content(); let compression_buf = { let mut compressor = Compressor::new(CompressionLvl::default()); let mut compression_buf = Vec::new(); let compressed_max_sz = compressor.gzip_compress_bound(input_data.len()); compression_buf.resize(compressed_max_sz, 0); let compressed_sz = compressor.gzip_compress(&input_data, &mut compression_buf).unwrap(); compression_buf.resize(compressed_sz, 0); compression_buf }; let decompressed_buf = { let mut decompressor = Decompressor::new(); let mut decompressed_buf = Vec::new(); decompressed_buf.resize(input_data.len(), 0); let decompressed_sz = decompressor.gzip_decompress(&compression_buf, &mut decompressed_buf).unwrap(); assert_eq!(decompressed_sz, input_data.len()); decompressed_buf }; assert_eq!(input_data, decompressed_buf); } // crc32 #[test] fn test_use_crc32_reader_to_compute_crc32_of_fixture_returns_same_crc32_as_flate2() { // This assumes that flate2's crc32 implementation returns a // correct value, which is a pretty safe assumption. let input_data = read_fixture_content(); let flate2_crc32 = { let mut crc = flate2::Crc::new(); crc.update(&input_data); crc.sum() }; let libdeflate_crc32 = { let mut crc = libdeflater::Crc::new(); crc.update(&input_data); crc.sum() }; assert_eq!(flate2_crc32, libdeflate_crc32); } #[test] fn test_use_crc32_convenience_method_returns_same_crc32_as_flate2() { // This assumes that flate2's crc32 implementation returns a // correct value, which is a pretty safe assumption. let input_data = read_fixture_content(); let flate2_crc32 = { let mut crc = flate2::Crc::new(); crc.update(&input_data); crc.sum() }; let libdeflate_crc32 = libdeflater::crc32(&input_data); assert_eq!(flate2_crc32, libdeflate_crc32); } // adler32 #[test] fn test_use_adler32_reader_to_compute_adler32_of_fixture_returns_same_adler32_as_adler32_crate( ) { // This assumes that adler32 crate implementation returns a // correct value, which is a pretty safe assumption. let input_data = read_fixture_content(); let crate_adler32 = { let mut adler32 = adler32::RollingAdler32::new(); adler32.update_buffer(&input_data); adler32.update_buffer(&input_data); adler32.hash() }; let libdeflate_adler32 = { let mut adler32 = libdeflater::Adler32::new(); adler32.update(&input_data); adler32.update(&input_data); adler32.sum() }; assert_eq!(crate_adler32, libdeflate_adler32); } #[test] fn test_use_adler32_convenience_method_returns_same_adler32_as_adler32_crate() { // This assumes that adler32 crate implementation returns a // correct value, which is a pretty safe assumption. let input_data = read_fixture_content(); let crate_adler32 = { let mut adler32 = adler32::RollingAdler32::new(); adler32.update_buffer(&input_data); adler32.hash() }; let libdeflate_adler32 = libdeflater::adler32(&input_data); assert_eq!(crate_adler32, libdeflate_adler32); }