I've been saying "PDSes seem easy enough, they're what, some CRUD to a db? I can do that in my sleep". well i'm sleeping rn so let's go
at main 8.7 kB view raw
1use image::{DynamicImage, ImageFormat}; 2use std::io::Cursor; 3use tranquil_pds::image::{ 4 DEFAULT_MAX_FILE_SIZE, ImageError, ImageProcessor, OutputFormat, THUMB_SIZE_FEED, 5 THUMB_SIZE_FULL, 6}; 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_format_support() { 42 let processor = ImageProcessor::new(); 43 44 let png = create_test_png(500, 500); 45 let result = processor.process(&png, "image/png").unwrap(); 46 assert_eq!(result.original.width, 500); 47 assert_eq!(result.original.height, 500); 48 49 let jpeg = create_test_jpeg(400, 300); 50 let result = processor.process(&jpeg, "image/jpeg").unwrap(); 51 assert_eq!(result.original.width, 400); 52 assert_eq!(result.original.height, 300); 53 54 let gif = create_test_gif(200, 200); 55 let result = processor.process(&gif, "image/gif").unwrap(); 56 assert_eq!(result.original.width, 200); 57 58 let webp = create_test_webp(300, 200); 59 let result = processor.process(&webp, "image/webp").unwrap(); 60 assert_eq!(result.original.width, 300); 61} 62 63#[test] 64fn test_thumbnail_generation() { 65 let processor = ImageProcessor::new(); 66 67 let small = create_test_png(100, 100); 68 let result = processor.process(&small, "image/png").unwrap(); 69 assert!( 70 result.thumbnail_feed.is_none(), 71 "Small image should not get feed thumbnail" 72 ); 73 assert!( 74 result.thumbnail_full.is_none(), 75 "Small image should not get full thumbnail" 76 ); 77 78 let medium = create_test_png(500, 500); 79 let result = processor.process(&medium, "image/png").unwrap(); 80 assert!( 81 result.thumbnail_feed.is_some(), 82 "Medium image should have feed thumbnail" 83 ); 84 assert!( 85 result.thumbnail_full.is_none(), 86 "Medium image should NOT have full thumbnail" 87 ); 88 89 let large = create_test_png(2000, 2000); 90 let result = processor.process(&large, "image/png").unwrap(); 91 assert!( 92 result.thumbnail_feed.is_some(), 93 "Large image should have feed thumbnail" 94 ); 95 assert!( 96 result.thumbnail_full.is_some(), 97 "Large image should have full thumbnail" 98 ); 99 let thumb = result.thumbnail_feed.unwrap(); 100 assert!(thumb.width <= THUMB_SIZE_FEED && thumb.height <= THUMB_SIZE_FEED); 101 let full = result.thumbnail_full.unwrap(); 102 assert!(full.width <= THUMB_SIZE_FULL && full.height <= THUMB_SIZE_FULL); 103 104 let at_feed = create_test_png(THUMB_SIZE_FEED, THUMB_SIZE_FEED); 105 let above_feed = create_test_png(THUMB_SIZE_FEED + 1, THUMB_SIZE_FEED + 1); 106 assert!( 107 processor 108 .process(&at_feed, "image/png") 109 .unwrap() 110 .thumbnail_feed 111 .is_none() 112 ); 113 assert!( 114 processor 115 .process(&above_feed, "image/png") 116 .unwrap() 117 .thumbnail_feed 118 .is_some() 119 ); 120 121 let at_full = create_test_png(THUMB_SIZE_FULL, THUMB_SIZE_FULL); 122 let above_full = create_test_png(THUMB_SIZE_FULL + 1, THUMB_SIZE_FULL + 1); 123 assert!( 124 processor 125 .process(&at_full, "image/png") 126 .unwrap() 127 .thumbnail_full 128 .is_none() 129 ); 130 assert!( 131 processor 132 .process(&above_full, "image/png") 133 .unwrap() 134 .thumbnail_full 135 .is_some() 136 ); 137 138 let disabled = ImageProcessor::new().with_thumbnails(false); 139 let result = disabled.process(&large, "image/png").unwrap(); 140 assert!(result.thumbnail_feed.is_none() && result.thumbnail_full.is_none()); 141} 142 143#[test] 144fn test_output_format_conversion() { 145 let png = create_test_png(300, 300); 146 let jpeg = create_test_jpeg(300, 300); 147 148 let webp_proc = ImageProcessor::new().with_output_format(OutputFormat::WebP); 149 assert_eq!( 150 webp_proc 151 .process(&png, "image/png") 152 .unwrap() 153 .original 154 .mime_type, 155 "image/webp" 156 ); 157 158 let jpeg_proc = ImageProcessor::new().with_output_format(OutputFormat::Jpeg); 159 assert_eq!( 160 jpeg_proc 161 .process(&png, "image/png") 162 .unwrap() 163 .original 164 .mime_type, 165 "image/jpeg" 166 ); 167 168 let png_proc = ImageProcessor::new().with_output_format(OutputFormat::Png); 169 assert_eq!( 170 png_proc 171 .process(&jpeg, "image/jpeg") 172 .unwrap() 173 .original 174 .mime_type, 175 "image/png" 176 ); 177} 178 179#[test] 180fn test_size_and_dimension_limits() { 181 assert_eq!(DEFAULT_MAX_FILE_SIZE, 10 * 1024 * 1024); 182 183 let max_dim = ImageProcessor::new().with_max_dimension(1000); 184 let large = create_test_png(2000, 2000); 185 let result = max_dim.process(&large, "image/png"); 186 assert!(matches!( 187 result, 188 Err(ImageError::TooLarge { 189 width: 2000, 190 height: 2000, 191 max_dimension: 1000 192 }) 193 )); 194 195 let max_file = ImageProcessor::new().with_max_file_size(100); 196 let data = create_test_png(500, 500); 197 let result = max_file.process(&data, "image/png"); 198 assert!(matches!( 199 result, 200 Err(ImageError::FileTooLarge { max_size: 100, .. }) 201 )); 202} 203 204#[test] 205fn test_error_handling() { 206 let processor = ImageProcessor::new(); 207 208 let result = processor.process(b"this is not an image", "application/octet-stream"); 209 assert!(matches!(result, Err(ImageError::UnsupportedFormat(_)))); 210 211 let result = processor.process(b"\x89PNG\r\n\x1a\ncorrupted data here", "image/png"); 212 assert!(matches!(result, Err(ImageError::DecodeError(_)))); 213} 214 215#[test] 216fn test_aspect_ratio_preservation() { 217 let processor = ImageProcessor::new(); 218 219 let landscape = create_test_png(1600, 800); 220 let result = processor.process(&landscape, "image/png").unwrap(); 221 let thumb = result.thumbnail_full.unwrap(); 222 let original_ratio = 1600.0 / 800.0; 223 let thumb_ratio = thumb.width as f64 / thumb.height as f64; 224 assert!((original_ratio - thumb_ratio).abs() < 0.1); 225 226 let portrait = create_test_png(800, 1600); 227 let result = processor.process(&portrait, "image/png").unwrap(); 228 let thumb = result.thumbnail_full.unwrap(); 229 let original_ratio = 800.0 / 1600.0; 230 let thumb_ratio = thumb.width as f64 / thumb.height as f64; 231 assert!((original_ratio - thumb_ratio).abs() < 0.1); 232} 233 234#[test] 235fn test_utilities_and_builder() { 236 assert!(ImageProcessor::is_supported_mime_type("image/jpeg")); 237 assert!(ImageProcessor::is_supported_mime_type("image/jpg")); 238 assert!(ImageProcessor::is_supported_mime_type("image/png")); 239 assert!(ImageProcessor::is_supported_mime_type("image/gif")); 240 assert!(ImageProcessor::is_supported_mime_type("image/webp")); 241 assert!(ImageProcessor::is_supported_mime_type("IMAGE/PNG")); 242 assert!(ImageProcessor::is_supported_mime_type("Image/Jpeg")); 243 assert!(!ImageProcessor::is_supported_mime_type("image/bmp")); 244 assert!(!ImageProcessor::is_supported_mime_type("image/tiff")); 245 assert!(!ImageProcessor::is_supported_mime_type("text/plain")); 246 247 let data = create_test_png(100, 100); 248 let processor = ImageProcessor::new(); 249 let result = processor.process(&data, "application/octet-stream"); 250 assert!(result.is_ok(), "Should detect PNG format from data"); 251 252 let jpeg = create_test_jpeg(100, 100); 253 let stripped = ImageProcessor::strip_exif(&jpeg).unwrap(); 254 assert!(!stripped.is_empty()); 255 256 let processor = ImageProcessor::new() 257 .with_max_dimension(2048) 258 .with_max_file_size(5 * 1024 * 1024) 259 .with_output_format(OutputFormat::Jpeg) 260 .with_thumbnails(true); 261 let data = create_test_png(500, 500); 262 let result = processor.process(&data, "image/png").unwrap(); 263 assert_eq!(result.original.mime_type, "image/jpeg"); 264 assert!(!result.original.data.is_empty()); 265 assert!(result.original.width > 0 && result.original.height > 0); 266}