use super::{CompressionError, Compressor};
use std::io::Read;
#[derive(Debug, Clone)]
pub struct BrotliCompressor {
level: u32,
}
impl BrotliCompressor {
pub fn new() -> Self {
Self { level: 6 }
}
pub fn with_level(level: u32) -> Self {
Self { level }
}
pub fn level(&self) -> u32 {
self.level
}
}
impl Default for BrotliCompressor {
fn default() -> Self {
Self::new()
}
}
impl Compressor for BrotliCompressor {
fn compress(&self, data: &[u8]) -> Result<Vec<u8>, CompressionError> {
let mut compressed = Vec::new();
let mut compressor = brotli::CompressorReader::new(
data, 4096, self.level, 22, );
compressor
.read_to_end(&mut compressed)
.map_err(|e| CompressionError::CompressionFailed(e.to_string()))?;
Ok(compressed)
}
fn decompress(&self, compressed: &[u8]) -> Result<Vec<u8>, CompressionError> {
let mut decompressed = Vec::new();
let mut decompressor = brotli::Decompressor::new(compressed, 4096);
decompressor
.read_to_end(&mut decompressed)
.map_err(|e| CompressionError::DecompressionFailed(e.to_string()))?;
Ok(decompressed)
}
fn name(&self) -> &'static str {
"brotli"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_brotli_compress_decompress() {
let compressor = BrotliCompressor::new();
let data = b"Hello, World! This is test data for Brotli compression.";
let compressed = compressor.compress(data).unwrap();
let decompressed = compressor.decompress(&compressed).unwrap();
assert_eq!(data, decompressed.as_slice());
}
#[test]
fn test_brotli_compression_ratio() {
let compressor = BrotliCompressor::new();
let data = b"A".repeat(1000);
let compressed = compressor.compress(&data).unwrap();
assert!(compressed.len() < data.len() / 10);
}
#[test]
fn test_brotli_with_level() {
let low_compression = BrotliCompressor::with_level(1);
let high_compression = BrotliCompressor::with_level(11);
let data = b"Test data for compression level comparison.".repeat(10);
let low_compressed = low_compression.compress(&data).unwrap();
let high_compressed = high_compression.compress(&data).unwrap();
assert!(high_compressed.len() <= low_compressed.len());
assert_eq!(low_compression.decompress(&low_compressed).unwrap(), data);
assert_eq!(high_compression.decompress(&high_compressed).unwrap(), data);
}
#[test]
fn test_brotli_empty_data() {
let compressor = BrotliCompressor::new();
let data = b"";
let compressed = compressor.compress(data).unwrap();
let decompressed = compressor.decompress(&compressed).unwrap();
assert_eq!(data, decompressed.as_slice());
}
#[test]
fn test_brotli_large_data() {
let compressor = BrotliCompressor::new();
let data = vec![b'X'; 100_000];
let compressed = compressor.compress(&data).unwrap();
let decompressed = compressor.decompress(&compressed).unwrap();
assert_eq!(data, decompressed);
assert!(compressed.len() < 1000);
}
#[test]
fn test_brotli_name() {
let compressor = BrotliCompressor::new();
assert_eq!(compressor.name(), "brotli");
}
#[test]
fn test_brotli_level_getter() {
let compressor = BrotliCompressor::with_level(9);
assert_eq!(compressor.level(), 9);
}
#[test]
fn test_brotli_default() {
let compressor = BrotliCompressor::default();
assert_eq!(compressor.level(), 6);
}
#[test]
fn test_brotli_fast_compression() {
let compressor = BrotliCompressor::with_level(0);
let data = b"Test data for fast compression";
let compressed = compressor.compress(data).unwrap();
let decompressed = compressor.decompress(&compressed).unwrap();
assert_eq!(data, decompressed.as_slice());
}
}