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