Files
k-shrink/crates/bin/tests/integration_test.rs
Gabriel Kaszewski 271d55ba57 feat: initialize K-Shrink workspace with multiple crates for image shrinking utility
- Add Cargo.toml for workspace configuration with dependencies.
- Create README.md with project description, usage, and architecture details.
- Implement `bin` crate for the main executable, including clipboard processing logic.
- Add `config` crate for handling configuration in TOML format.
- Develop `lib` crate containing core image processing logic and error handling.
- Introduce `platform` crate for platform-specific clipboard interactions, starting with Wayland.
- Implement tests for image shrinking functionality and clipboard interactions.
2026-03-17 21:50:13 +01:00

101 lines
2.8 KiB
Rust

use lib::{ClipboardError, ClipboardProvider, OutputFormat, ShrinkOptions};
use std::cell::Cell;
use std::io::Cursor;
use std::sync::{Arc, Mutex};
struct MockClipboard {
capture_bytes: Vec<u8>,
capture_mime: String,
distributed: Arc<Mutex<Vec<(Vec<u8>, String)>>>,
capture_count: Cell<usize>,
}
impl MockClipboard {
fn new(bytes: Vec<u8>, mime: &str) -> Self {
Self {
capture_bytes: bytes,
capture_mime: mime.to_string(),
distributed: Arc::new(Mutex::new(Vec::new())),
capture_count: Cell::new(0),
}
}
}
impl ClipboardProvider for MockClipboard {
fn capture(&self) -> Result<(Vec<u8>, String), ClipboardError> {
self.capture_count.set(self.capture_count.get() + 1);
Ok((self.capture_bytes.clone(), self.capture_mime.clone()))
}
fn distribute(&self, items: &[(&[u8], &str)]) -> Result<(), ClipboardError> {
let mut lock = self.distributed.lock().unwrap();
for (data, mime) in items {
lock.push((data.to_vec(), mime.to_string()));
}
Ok(())
}
}
fn make_png() -> Vec<u8> {
let img = image::DynamicImage::new_rgb8(8, 8);
let mut buf = Vec::new();
img.write_to(&mut Cursor::new(&mut buf), image::ImageFormat::Png)
.unwrap();
buf
}
fn webp_opts() -> ShrinkOptions {
ShrinkOptions {
quality: 80,
target_format: OutputFormat::Webp,
}
}
#[test]
fn image_bytes_are_shrunk_and_distributed_as_webp() {
use k_shrink::process_once;
let png = make_png();
let mock = MockClipboard::new(png, "image/png");
let mut last_hash = None;
process_once(&mock, &webp_opts(), &mut last_hash).unwrap();
let dist = mock.distributed.lock().unwrap();
assert_eq!(dist.len(), 1, "exactly one item distributed");
assert_eq!(dist[0].1, "image/webp");
}
#[test]
fn same_webp_output_not_reprocessed() {
use k_shrink::process_once;
let png = make_png();
let mock = MockClipboard::new(png, "image/png");
let mut last_hash = None;
process_once(&mock, &webp_opts(), &mut last_hash).unwrap();
// After distributing, our subprocess serves image/webp.
// Simulate next tick: clipboard returns the webp we just wrote.
let webp_data = mock.distributed.lock().unwrap()[0].0.clone();
let mock2 = MockClipboard::new(webp_data, "image/webp");
process_once(&mock2, &webp_opts(), &mut last_hash).unwrap();
// hash(webp) == last_hash → skipped
assert_eq!(mock2.distributed.lock().unwrap().len(), 0);
}
#[test]
fn non_image_mime_not_processed() {
use k_shrink::process_once;
let mock = MockClipboard::new(b"hello world".to_vec(), "text/plain");
let mut last_hash = None;
process_once(&mock, &webp_opts(), &mut last_hash).unwrap();
assert_eq!(mock.distributed.lock().unwrap().len(), 0);
}