use image::{Rgb, RgbImage};
use sharpy::{EdgeMethod, Image};
fn create_test_image() -> RgbImage {
let mut img = RgbImage::new(256, 256);
for y in 0..256 {
for x in 0..256 {
let value = if x < 128 {
if y < 128 {
if (x / 16 + y / 16) % 2 == 0 {
64
} else {
192
}
} else {
(x * 2) as u8
}
} else {
if y < 128 {
y as u8
} else {
128
}
};
img.put_pixel(x as u32, y as u32, Rgb([value, value, value]));
}
}
img
}
fn calculate_mse(img1: &RgbImage, img2: &RgbImage) -> f64 {
assert_eq!(img1.dimensions(), img2.dimensions());
let mut sum = 0.0;
let pixels = (img1.width() * img1.height()) as f64;
for (p1, p2) in img1.pixels().zip(img2.pixels()) {
for i in 0..3 {
let diff = p1[i] as f64 - p2[i] as f64;
sum += diff * diff;
}
}
sum / (pixels * 3.0)
}
fn measure_edge_strength(img: &RgbImage) -> f64 {
let (width, height) = img.dimensions();
let mut edge_sum = 0.0;
let mut count = 0;
for y in 1..height - 1 {
for x in 1..width - 1 {
let center = img.get_pixel(x, y)[0] as f64;
let right = img.get_pixel(x + 1, y)[0] as f64;
let bottom = img.get_pixel(x, y + 1)[0] as f64;
let edge_strength = ((center - right).abs() + (center - bottom).abs()) / 2.0;
edge_sum += edge_strength;
count += 1;
}
}
edge_sum / count as f64
}
#[test]
fn test_unsharp_mask_increases_sharpness() {
let test_img = create_test_image();
let image = Image::from_rgb(test_img.clone()).unwrap();
let sharpened = image.unsharp_mask(1.0, 1.0, 0).unwrap();
let sharpened_rgb = sharpened.into_rgb();
let original_edges = measure_edge_strength(&test_img);
let sharpened_edges = measure_edge_strength(&sharpened_rgb);
assert!(
sharpened_edges > original_edges * 1.1,
"Edge strength should increase by at least 10% (original: {}, sharpened: {})",
original_edges,
sharpened_edges
);
}
#[test]
fn test_high_pass_sharpen_effect() {
let test_img = create_test_image();
let image = Image::from_rgb(test_img.clone()).unwrap();
let sharpened = image.high_pass_sharpen(0.7).unwrap();
let sharpened_rgb = sharpened.into_rgb();
let mse = calculate_mse(&test_img, &sharpened_rgb);
assert!(
mse > 10.0,
"High-pass sharpening should significantly modify the image (MSE: {})",
mse
);
assert!(
mse < 5000.0,
"High-pass sharpening should not destroy the image (MSE: {})",
mse
);
}
#[test]
fn test_edge_enhancement_methods() {
let test_img = create_test_image();
for method in [EdgeMethod::Sobel, EdgeMethod::Prewitt] {
let image = Image::from_rgb(test_img.clone()).unwrap();
let enhanced = image.enhance_edges(1.0, method).unwrap();
let enhanced_rgb = enhanced.into_rgb();
let original_edges = measure_edge_strength(&test_img);
let enhanced_edges = measure_edge_strength(&enhanced_rgb);
assert!(
enhanced_edges > original_edges,
"Edge enhancement with {:?} should increase edge strength",
method
);
}
}
#[test]
fn test_clarity_enhancement() {
let test_img = create_test_image();
let image = Image::from_rgb(test_img.clone()).unwrap();
let enhanced = image.clarity(1.0, 3.0).unwrap();
let enhanced_rgb = enhanced.into_rgb();
let mse = calculate_mse(&test_img, &enhanced_rgb);
assert!(mse > 5.0, "Clarity should modify the image (MSE: {})", mse);
assert!(
mse < 1000.0,
"Clarity should not destroy the image (MSE: {})",
mse
);
}
#[test]
fn test_chained_operations() {
let test_img = create_test_image();
let image = Image::from_rgb(test_img.clone()).unwrap();
let result = image
.unsharp_mask(0.5, 0.5, 5)
.unwrap()
.high_pass_sharpen(0.3)
.unwrap()
.clarity(0.5, 2.0)
.unwrap();
let result_rgb = result.into_rgb();
assert_eq!(result_rgb.dimensions(), test_img.dimensions());
let edge_strength = measure_edge_strength(&result_rgb);
let original_strength = measure_edge_strength(&test_img);
assert!(
edge_strength > original_strength,
"Chained operations should enhance edges"
);
}
#[test]
fn test_parameter_bounds() {
let test_img = create_test_image();
let test_cases = vec![
("min radius", 0.5, 1.0, 0),
("max radius", 10.0, 1.0, 0),
("min amount", 1.0, 0.0, 0),
("max amount", 1.0, 5.0, 0),
("max threshold", 1.0, 1.0, 255),
];
for (name, radius, amount, threshold) in test_cases {
let image = Image::from_rgb(test_img.clone()).unwrap();
let result = image.unsharp_mask(radius, amount, threshold);
assert!(
result.is_ok(),
"Operation '{}' should succeed with valid parameters",
name
);
}
}
#[test]
fn test_image_dimensions_preserved() {
let sizes = vec![(100, 100), (256, 128), (333, 444)];
for (width, height) in sizes {
let img = RgbImage::new(width, height);
let image = Image::from_rgb(img).unwrap();
#[allow(clippy::type_complexity)]
let operations: Vec<(&str, Box<dyn Fn(Image) -> sharpy::Result<Image>>)> = vec![
(
"unsharp_mask",
Box::new(|img| img.unsharp_mask(1.0, 1.0, 0)),
),
("high_pass", Box::new(|img| img.high_pass_sharpen(0.5))),
(
"edge_enhance",
Box::new(|img| img.enhance_edges(1.0, EdgeMethod::Sobel)),
),
("clarity", Box::new(|img| img.clarity(1.0, 2.0))),
];
for (name, op) in operations {
let result = op(image.clone()).unwrap();
let result_rgb = result.into_rgb();
assert_eq!(
result_rgb.dimensions(),
(width, height),
"{} should preserve dimensions",
name
);
}
}
}
#[test]
fn test_builder_pattern_integration() {
let test_img = create_test_image();
let image = Image::from_rgb(test_img.clone()).unwrap();
let result = image
.sharpen()
.unsharp_mask(0.8, 0.8, 2)
.edge_enhance(0.3, EdgeMethod::Sobel)
.clarity(0.4, 2.5)
.apply()
.unwrap();
let result_rgb = result.into_rgb();
let edge_strength = measure_edge_strength(&result_rgb);
let original_strength = measure_edge_strength(&test_img);
assert!(
edge_strength > original_strength * 1.2,
"Builder pattern should apply all sharpening operations"
);
}
#[test]
fn test_preset_integration() {
use sharpy::SharpeningPresets;
let test_img = create_test_image();
let image = Image::from_rgb(test_img).unwrap();
let presets = vec![
("subtle", SharpeningPresets::subtle(image.clone())),
("moderate", SharpeningPresets::moderate(image.clone())),
("strong", SharpeningPresets::strong(image.clone())),
("edge_aware", SharpeningPresets::edge_aware(image.clone())),
("portrait", SharpeningPresets::portrait(image.clone())),
("landscape", SharpeningPresets::landscape(image.clone())),
];
for (name, builder) in presets {
let result = builder.apply();
assert!(
result.is_ok(),
"Preset '{}' should apply successfully",
name
);
}
}
#[test]
fn test_memory_bounds_checking() {
let huge_image = RgbImage::new(100000, 100000); let result = Image::from_rgb(huge_image);
assert!(
result.is_err(),
"Should reject images exceeding memory limits"
);
let tall_image = RgbImage::new(100, 70000); let result = Image::from_rgb(tall_image);
assert!(
result.is_err(),
"Should reject images exceeding dimension limits"
);
let normal_image = RgbImage::new(4096, 4096); let result = Image::from_rgb(normal_image);
assert!(result.is_ok(), "Should accept reasonably sized images");
}