this repo has no description
1use bspds::image::{ImageProcessor, ImageError, OutputFormat, THUMB_SIZE_FEED, THUMB_SIZE_FULL, DEFAULT_MAX_FILE_SIZE}; 2use image::{DynamicImage, ImageFormat}; 3use std::io::Cursor; 4fn create_test_png(width: u32, height: u32) -> Vec<u8> { 5 let img = DynamicImage::new_rgb8(width, height); 6 let mut buf = Vec::new(); 7 img.write_to(&mut Cursor::new(&mut buf), ImageFormat::Png).unwrap(); 8 buf 9} 10fn create_test_jpeg(width: u32, height: u32) -> Vec<u8> { 11 let img = DynamicImage::new_rgb8(width, height); 12 let mut buf = Vec::new(); 13 img.write_to(&mut Cursor::new(&mut buf), ImageFormat::Jpeg).unwrap(); 14 buf 15} 16fn create_test_gif(width: u32, height: u32) -> Vec<u8> { 17 let img = DynamicImage::new_rgb8(width, height); 18 let mut buf = Vec::new(); 19 img.write_to(&mut Cursor::new(&mut buf), ImageFormat::Gif).unwrap(); 20 buf 21} 22fn create_test_webp(width: u32, height: u32) -> Vec<u8> { 23 let img = DynamicImage::new_rgb8(width, height); 24 let mut buf = Vec::new(); 25 img.write_to(&mut Cursor::new(&mut buf), ImageFormat::WebP).unwrap(); 26 buf 27} 28#[test] 29fn test_process_png() { 30 let processor = ImageProcessor::new(); 31 let data = create_test_png(500, 500); 32 let result = processor.process(&data, "image/png").unwrap(); 33 assert_eq!(result.original.width, 500); 34 assert_eq!(result.original.height, 500); 35} 36#[test] 37fn test_process_jpeg() { 38 let processor = ImageProcessor::new(); 39 let data = create_test_jpeg(400, 300); 40 let result = processor.process(&data, "image/jpeg").unwrap(); 41 assert_eq!(result.original.width, 400); 42 assert_eq!(result.original.height, 300); 43} 44#[test] 45fn test_process_gif() { 46 let processor = ImageProcessor::new(); 47 let data = create_test_gif(200, 200); 48 let result = processor.process(&data, "image/gif").unwrap(); 49 assert_eq!(result.original.width, 200); 50 assert_eq!(result.original.height, 200); 51} 52#[test] 53fn test_process_webp() { 54 let processor = ImageProcessor::new(); 55 let data = create_test_webp(300, 200); 56 let result = processor.process(&data, "image/webp").unwrap(); 57 assert_eq!(result.original.width, 300); 58 assert_eq!(result.original.height, 200); 59} 60#[test] 61fn test_thumbnail_feed_size() { 62 let processor = ImageProcessor::new(); 63 let data = create_test_png(800, 600); 64 let result = processor.process(&data, "image/png").unwrap(); 65 let thumb = result.thumbnail_feed.expect("Should generate feed thumbnail for large image"); 66 assert!(thumb.width <= THUMB_SIZE_FEED); 67 assert!(thumb.height <= THUMB_SIZE_FEED); 68} 69#[test] 70fn test_thumbnail_full_size() { 71 let processor = ImageProcessor::new(); 72 let data = create_test_png(2000, 1500); 73 let result = processor.process(&data, "image/png").unwrap(); 74 let thumb = result.thumbnail_full.expect("Should generate full thumbnail for large image"); 75 assert!(thumb.width <= THUMB_SIZE_FULL); 76 assert!(thumb.height <= THUMB_SIZE_FULL); 77} 78#[test] 79fn test_no_thumbnail_small_image() { 80 let processor = ImageProcessor::new(); 81 let data = create_test_png(100, 100); 82 let result = processor.process(&data, "image/png").unwrap(); 83 assert!(result.thumbnail_feed.is_none(), "Small image should not get feed thumbnail"); 84 assert!(result.thumbnail_full.is_none(), "Small image should not get full thumbnail"); 85} 86#[test] 87fn test_webp_conversion() { 88 let processor = ImageProcessor::new().with_output_format(OutputFormat::WebP); 89 let data = create_test_png(300, 300); 90 let result = processor.process(&data, "image/png").unwrap(); 91 assert_eq!(result.original.mime_type, "image/webp"); 92} 93#[test] 94fn test_jpeg_output_format() { 95 let processor = ImageProcessor::new().with_output_format(OutputFormat::Jpeg); 96 let data = create_test_png(300, 300); 97 let result = processor.process(&data, "image/png").unwrap(); 98 assert_eq!(result.original.mime_type, "image/jpeg"); 99} 100#[test] 101fn test_png_output_format() { 102 let processor = ImageProcessor::new().with_output_format(OutputFormat::Png); 103 let data = create_test_jpeg(300, 300); 104 let result = processor.process(&data, "image/jpeg").unwrap(); 105 assert_eq!(result.original.mime_type, "image/png"); 106} 107#[test] 108fn test_max_dimension_enforced() { 109 let processor = ImageProcessor::new().with_max_dimension(1000); 110 let data = create_test_png(2000, 2000); 111 let result = processor.process(&data, "image/png"); 112 assert!(matches!(result, Err(ImageError::TooLarge { .. }))); 113 if let Err(ImageError::TooLarge { width, height, max_dimension }) = result { 114 assert_eq!(width, 2000); 115 assert_eq!(height, 2000); 116 assert_eq!(max_dimension, 1000); 117 } 118} 119#[test] 120fn test_file_size_limit() { 121 let processor = ImageProcessor::new().with_max_file_size(100); 122 let data = create_test_png(500, 500); 123 let result = processor.process(&data, "image/png"); 124 assert!(matches!(result, Err(ImageError::FileTooLarge { .. }))); 125 if let Err(ImageError::FileTooLarge { size, max_size }) = result { 126 assert!(size > 100); 127 assert_eq!(max_size, 100); 128 } 129} 130#[test] 131fn test_default_max_file_size() { 132 assert_eq!(DEFAULT_MAX_FILE_SIZE, 10 * 1024 * 1024); 133} 134#[test] 135fn test_unsupported_format_rejected() { 136 let processor = ImageProcessor::new(); 137 let data = b"this is not an image"; 138 let result = processor.process(data, "application/octet-stream"); 139 assert!(matches!(result, Err(ImageError::UnsupportedFormat(_)))); 140} 141#[test] 142fn test_corrupted_image_handling() { 143 let processor = ImageProcessor::new(); 144 let data = b"\x89PNG\r\n\x1a\ncorrupted data here"; 145 let result = processor.process(data, "image/png"); 146 assert!(matches!(result, Err(ImageError::DecodeError(_)))); 147} 148#[test] 149fn test_aspect_ratio_preserved_landscape() { 150 let processor = ImageProcessor::new(); 151 let data = create_test_png(1600, 800); 152 let result = processor.process(&data, "image/png").unwrap(); 153 let thumb = result.thumbnail_full.expect("Should have thumbnail"); 154 let original_ratio = 1600.0 / 800.0; 155 let thumb_ratio = thumb.width as f64 / thumb.height as f64; 156 assert!((original_ratio - thumb_ratio).abs() < 0.1, "Aspect ratio should be preserved"); 157} 158#[test] 159fn test_aspect_ratio_preserved_portrait() { 160 let processor = ImageProcessor::new(); 161 let data = create_test_png(800, 1600); 162 let result = processor.process(&data, "image/png").unwrap(); 163 let thumb = result.thumbnail_full.expect("Should have thumbnail"); 164 let original_ratio = 800.0 / 1600.0; 165 let thumb_ratio = thumb.width as f64 / thumb.height as f64; 166 assert!((original_ratio - thumb_ratio).abs() < 0.1, "Aspect ratio should be preserved"); 167} 168#[test] 169fn test_mime_type_detection_auto() { 170 let processor = ImageProcessor::new(); 171 let data = create_test_png(100, 100); 172 let result = processor.process(&data, "application/octet-stream"); 173 assert!(result.is_ok(), "Should detect PNG format from data"); 174} 175#[test] 176fn test_is_supported_mime_type() { 177 assert!(ImageProcessor::is_supported_mime_type("image/jpeg")); 178 assert!(ImageProcessor::is_supported_mime_type("image/jpg")); 179 assert!(ImageProcessor::is_supported_mime_type("image/png")); 180 assert!(ImageProcessor::is_supported_mime_type("image/gif")); 181 assert!(ImageProcessor::is_supported_mime_type("image/webp")); 182 assert!(ImageProcessor::is_supported_mime_type("IMAGE/PNG")); 183 assert!(ImageProcessor::is_supported_mime_type("Image/Jpeg")); 184 assert!(!ImageProcessor::is_supported_mime_type("image/bmp")); 185 assert!(!ImageProcessor::is_supported_mime_type("image/tiff")); 186 assert!(!ImageProcessor::is_supported_mime_type("text/plain")); 187 assert!(!ImageProcessor::is_supported_mime_type("application/json")); 188} 189#[test] 190fn test_strip_exif() { 191 let data = create_test_jpeg(100, 100); 192 let result = ImageProcessor::strip_exif(&data); 193 assert!(result.is_ok()); 194 let stripped = result.unwrap(); 195 assert!(!stripped.is_empty()); 196} 197#[test] 198fn test_with_thumbnails_disabled() { 199 let processor = ImageProcessor::new().with_thumbnails(false); 200 let data = create_test_png(2000, 2000); 201 let result = processor.process(&data, "image/png").unwrap(); 202 assert!(result.thumbnail_feed.is_none(), "Thumbnails should be disabled"); 203 assert!(result.thumbnail_full.is_none(), "Thumbnails should be disabled"); 204} 205#[test] 206fn test_builder_chaining() { 207 let processor = ImageProcessor::new() 208 .with_max_dimension(2048) 209 .with_max_file_size(5 * 1024 * 1024) 210 .with_output_format(OutputFormat::Jpeg) 211 .with_thumbnails(true); 212 let data = create_test_png(500, 500); 213 let result = processor.process(&data, "image/png").unwrap(); 214 assert_eq!(result.original.mime_type, "image/jpeg"); 215} 216#[test] 217fn test_processed_image_fields() { 218 let processor = ImageProcessor::new(); 219 let data = create_test_png(500, 500); 220 let result = processor.process(&data, "image/png").unwrap(); 221 assert!(!result.original.data.is_empty()); 222 assert!(!result.original.mime_type.is_empty()); 223 assert!(result.original.width > 0); 224 assert!(result.original.height > 0); 225} 226#[test] 227fn test_only_feed_thumbnail_for_medium_images() { 228 let processor = ImageProcessor::new(); 229 let data = create_test_png(500, 500); 230 let result = processor.process(&data, "image/png").unwrap(); 231 assert!(result.thumbnail_feed.is_some(), "Should have feed thumbnail"); 232 assert!(result.thumbnail_full.is_none(), "Should NOT have full thumbnail for 500px image"); 233} 234#[test] 235fn test_both_thumbnails_for_large_images() { 236 let processor = ImageProcessor::new(); 237 let data = create_test_png(2000, 2000); 238 let result = processor.process(&data, "image/png").unwrap(); 239 assert!(result.thumbnail_feed.is_some(), "Should have feed thumbnail"); 240 assert!(result.thumbnail_full.is_some(), "Should have full thumbnail for 2000px image"); 241} 242#[test] 243fn test_exact_threshold_boundary_feed() { 244 let processor = ImageProcessor::new(); 245 let at_threshold = create_test_png(THUMB_SIZE_FEED, THUMB_SIZE_FEED); 246 let result = processor.process(&at_threshold, "image/png").unwrap(); 247 assert!(result.thumbnail_feed.is_none(), "Exact threshold should not generate thumbnail"); 248 let above_threshold = create_test_png(THUMB_SIZE_FEED + 1, THUMB_SIZE_FEED + 1); 249 let result = processor.process(&above_threshold, "image/png").unwrap(); 250 assert!(result.thumbnail_feed.is_some(), "Above threshold should generate thumbnail"); 251} 252#[test] 253fn test_exact_threshold_boundary_full() { 254 let processor = ImageProcessor::new(); 255 let at_threshold = create_test_png(THUMB_SIZE_FULL, THUMB_SIZE_FULL); 256 let result = processor.process(&at_threshold, "image/png").unwrap(); 257 assert!(result.thumbnail_full.is_none(), "Exact threshold should not generate thumbnail"); 258 let above_threshold = create_test_png(THUMB_SIZE_FULL + 1, THUMB_SIZE_FULL + 1); 259 let result = processor.process(&above_threshold, "image/png").unwrap(); 260 assert!(result.thumbnail_full.is_some(), "Above threshold should generate thumbnail"); 261}