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).unwrap();
12 buf
13}
14
15fn create_test_jpeg(width: u32, height: u32) -> Vec<u8> {
16 let img = DynamicImage::new_rgb8(width, height);
17 let mut buf = Vec::new();
18 img.write_to(&mut Cursor::new(&mut buf), ImageFormat::Jpeg).unwrap();
19 buf
20}
21
22fn create_test_gif(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::Gif).unwrap();
26 buf
27}
28
29fn create_test_webp(width: u32, height: u32) -> Vec<u8> {
30 let img = DynamicImage::new_rgb8(width, height);
31 let mut buf = Vec::new();
32 img.write_to(&mut Cursor::new(&mut buf), ImageFormat::WebP).unwrap();
33 buf
34}
35
36#[test]
37fn test_format_support() {
38 let processor = ImageProcessor::new();
39
40 let png = create_test_png(500, 500);
41 let result = processor.process(&png, "image/png").unwrap();
42 assert_eq!(result.original.width, 500);
43 assert_eq!(result.original.height, 500);
44
45 let jpeg = create_test_jpeg(400, 300);
46 let result = processor.process(&jpeg, "image/jpeg").unwrap();
47 assert_eq!(result.original.width, 400);
48 assert_eq!(result.original.height, 300);
49
50 let gif = create_test_gif(200, 200);
51 let result = processor.process(&gif, "image/gif").unwrap();
52 assert_eq!(result.original.width, 200);
53
54 let webp = create_test_webp(300, 200);
55 let result = processor.process(&webp, "image/webp").unwrap();
56 assert_eq!(result.original.width, 300);
57}
58
59#[test]
60fn test_thumbnail_generation() {
61 let processor = ImageProcessor::new();
62
63 let small = create_test_png(100, 100);
64 let result = processor.process(&small, "image/png").unwrap();
65 assert!(result.thumbnail_feed.is_none(), "Small image should not get feed thumbnail");
66 assert!(result.thumbnail_full.is_none(), "Small image should not get full thumbnail");
67
68 let medium = create_test_png(500, 500);
69 let result = processor.process(&medium, "image/png").unwrap();
70 assert!(result.thumbnail_feed.is_some(), "Medium image should have feed thumbnail");
71 assert!(result.thumbnail_full.is_none(), "Medium image should NOT have full thumbnail");
72
73 let large = create_test_png(2000, 2000);
74 let result = processor.process(&large, "image/png").unwrap();
75 assert!(result.thumbnail_feed.is_some(), "Large image should have feed thumbnail");
76 assert!(result.thumbnail_full.is_some(), "Large image should have full thumbnail");
77 let thumb = result.thumbnail_feed.unwrap();
78 assert!(thumb.width <= THUMB_SIZE_FEED && thumb.height <= THUMB_SIZE_FEED);
79 let full = result.thumbnail_full.unwrap();
80 assert!(full.width <= THUMB_SIZE_FULL && full.height <= THUMB_SIZE_FULL);
81
82 let at_feed = create_test_png(THUMB_SIZE_FEED, THUMB_SIZE_FEED);
83 let above_feed = create_test_png(THUMB_SIZE_FEED + 1, THUMB_SIZE_FEED + 1);
84 assert!(processor.process(&at_feed, "image/png").unwrap().thumbnail_feed.is_none());
85 assert!(processor.process(&above_feed, "image/png").unwrap().thumbnail_feed.is_some());
86
87 let at_full = create_test_png(THUMB_SIZE_FULL, THUMB_SIZE_FULL);
88 let above_full = create_test_png(THUMB_SIZE_FULL + 1, THUMB_SIZE_FULL + 1);
89 assert!(processor.process(&at_full, "image/png").unwrap().thumbnail_full.is_none());
90 assert!(processor.process(&above_full, "image/png").unwrap().thumbnail_full.is_some());
91
92 let disabled = ImageProcessor::new().with_thumbnails(false);
93 let result = disabled.process(&large, "image/png").unwrap();
94 assert!(result.thumbnail_feed.is_none() && result.thumbnail_full.is_none());
95}
96
97#[test]
98fn test_output_format_conversion() {
99 let png = create_test_png(300, 300);
100 let jpeg = create_test_jpeg(300, 300);
101
102 let webp_proc = ImageProcessor::new().with_output_format(OutputFormat::WebP);
103 assert_eq!(webp_proc.process(&png, "image/png").unwrap().original.mime_type, "image/webp");
104
105 let jpeg_proc = ImageProcessor::new().with_output_format(OutputFormat::Jpeg);
106 assert_eq!(jpeg_proc.process(&png, "image/png").unwrap().original.mime_type, "image/jpeg");
107
108 let png_proc = ImageProcessor::new().with_output_format(OutputFormat::Png);
109 assert_eq!(png_proc.process(&jpeg, "image/jpeg").unwrap().original.mime_type, "image/png");
110}
111
112#[test]
113fn test_size_and_dimension_limits() {
114 assert_eq!(DEFAULT_MAX_FILE_SIZE, 10 * 1024 * 1024);
115
116 let max_dim = ImageProcessor::new().with_max_dimension(1000);
117 let large = create_test_png(2000, 2000);
118 let result = max_dim.process(&large, "image/png");
119 assert!(matches!(result, Err(ImageError::TooLarge { width: 2000, height: 2000, max_dimension: 1000 })));
120
121 let max_file = ImageProcessor::new().with_max_file_size(100);
122 let data = create_test_png(500, 500);
123 let result = max_file.process(&data, "image/png");
124 assert!(matches!(result, Err(ImageError::FileTooLarge { max_size: 100, .. })));
125}
126
127#[test]
128fn test_error_handling() {
129 let processor = ImageProcessor::new();
130
131 let result = processor.process(b"this is not an image", "application/octet-stream");
132 assert!(matches!(result, Err(ImageError::UnsupportedFormat(_))));
133
134 let result = processor.process(b"\x89PNG\r\n\x1a\ncorrupted data here", "image/png");
135 assert!(matches!(result, Err(ImageError::DecodeError(_))));
136}
137
138#[test]
139fn test_aspect_ratio_preservation() {
140 let processor = ImageProcessor::new();
141
142 let landscape = create_test_png(1600, 800);
143 let result = processor.process(&landscape, "image/png").unwrap();
144 let thumb = result.thumbnail_full.unwrap();
145 let original_ratio = 1600.0 / 800.0;
146 let thumb_ratio = thumb.width as f64 / thumb.height as f64;
147 assert!((original_ratio - thumb_ratio).abs() < 0.1);
148
149 let portrait = create_test_png(800, 1600);
150 let result = processor.process(&portrait, "image/png").unwrap();
151 let thumb = result.thumbnail_full.unwrap();
152 let original_ratio = 800.0 / 1600.0;
153 let thumb_ratio = thumb.width as f64 / thumb.height as f64;
154 assert!((original_ratio - thumb_ratio).abs() < 0.1);
155}
156
157#[test]
158fn test_utilities_and_builder() {
159 assert!(ImageProcessor::is_supported_mime_type("image/jpeg"));
160 assert!(ImageProcessor::is_supported_mime_type("image/jpg"));
161 assert!(ImageProcessor::is_supported_mime_type("image/png"));
162 assert!(ImageProcessor::is_supported_mime_type("image/gif"));
163 assert!(ImageProcessor::is_supported_mime_type("image/webp"));
164 assert!(ImageProcessor::is_supported_mime_type("IMAGE/PNG"));
165 assert!(ImageProcessor::is_supported_mime_type("Image/Jpeg"));
166 assert!(!ImageProcessor::is_supported_mime_type("image/bmp"));
167 assert!(!ImageProcessor::is_supported_mime_type("image/tiff"));
168 assert!(!ImageProcessor::is_supported_mime_type("text/plain"));
169
170 let data = create_test_png(100, 100);
171 let processor = ImageProcessor::new();
172 let result = processor.process(&data, "application/octet-stream");
173 assert!(result.is_ok(), "Should detect PNG format from data");
174
175 let jpeg = create_test_jpeg(100, 100);
176 let stripped = ImageProcessor::strip_exif(&jpeg).unwrap();
177 assert!(!stripped.is_empty());
178
179 let processor = ImageProcessor::new()
180 .with_max_dimension(2048)
181 .with_max_file_size(5 * 1024 * 1024)
182 .with_output_format(OutputFormat::Jpeg)
183 .with_thumbnails(true);
184 let data = create_test_png(500, 500);
185 let result = processor.process(&data, "image/png").unwrap();
186 assert_eq!(result.original.mime_type, "image/jpeg");
187 assert!(!result.original.data.is_empty());
188 assert!(result.original.width > 0 && result.original.height > 0);
189}