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