chore: refactor ahead of supporting more conversion types
All checks were successful
Checking Renovate configuration / validate (pull_request) Successful in 1m5s
Build and test / Clippy (pull_request) Successful in 3m25s
Checking yaml / Run yamllint (pull_request) Successful in 11s
Build and test / Tests (pull_request) Successful in 4m12s
Build and test / Build AMD64 (pull_request) Successful in 4m12s
Build and test / Generate Documentation (pull_request) Successful in 3m52s
All checks were successful
Checking Renovate configuration / validate (pull_request) Successful in 1m5s
Build and test / Clippy (pull_request) Successful in 3m25s
Checking yaml / Run yamllint (pull_request) Successful in 11s
Build and test / Tests (pull_request) Successful in 4m12s
Build and test / Build AMD64 (pull_request) Successful in 4m12s
Build and test / Generate Documentation (pull_request) Successful in 3m52s
This commit is contained in:
parent
48b560d85e
commit
034f0b142c
12 changed files with 468 additions and 150 deletions
57
tests/cbz_reader_tests.rs
Normal file
57
tests/cbz_reader_tests.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
use cbz2pdf::formats::cbz::CbzReader;
|
||||
use cbz2pdf::formats::FormatReader;
|
||||
|
||||
#[test]
|
||||
fn cbz_reader_reads_jpgs_and_sorts_by_name() {
|
||||
// Build a temporary CBZ with 3 jpgs (including in a subdir) and one non-jpg
|
||||
let temp_dir = tempfile::tempdir().expect("create temp dir");
|
||||
let cbz_path = temp_dir.path().join("book.cbz");
|
||||
|
||||
{
|
||||
let file = File::create(&cbz_path).expect("create cbz");
|
||||
let mut zip = zip::ZipWriter::new(file);
|
||||
let options = zip::write::SimpleFileOptions::default();
|
||||
|
||||
// out of order names
|
||||
zip.start_file("002.jpg", options).unwrap();
|
||||
// Create a tiny JPEG using the JPEG encoder
|
||||
let img = image::DynamicImage::new_rgb8(1, 1).to_rgb8();
|
||||
let mut buf = Vec::new();
|
||||
{
|
||||
let mut cursor = std::io::Cursor::new(&mut buf);
|
||||
let mut enc = image::codecs::jpeg::JpegEncoder::new_with_quality(&mut cursor, 80);
|
||||
enc.encode(&img, 1, 1, image::ColorType::Rgb8.into())
|
||||
.unwrap();
|
||||
}
|
||||
zip.write_all(&buf).unwrap();
|
||||
|
||||
zip.start_file("001.jpg", options).unwrap();
|
||||
zip.write_all(&buf).unwrap();
|
||||
|
||||
// nested path should be accepted
|
||||
zip.start_file("subdir/003.jpg", options).unwrap();
|
||||
zip.write_all(&buf).unwrap();
|
||||
|
||||
// non-jpg should be ignored
|
||||
zip.start_file("notes.txt", options).unwrap();
|
||||
zip.write_all(b"hello").unwrap();
|
||||
|
||||
zip.finish().unwrap();
|
||||
}
|
||||
|
||||
let reader = CbzReader;
|
||||
let doc = reader.read(&cbz_path).expect("read cbz");
|
||||
|
||||
assert_eq!(doc.pages.len(), 3, "should include only jpg files");
|
||||
let names: Vec<String> = doc.pages.iter().map(|p| p.name.clone()).collect();
|
||||
assert_eq!(
|
||||
names,
|
||||
vec!["001.jpg", "002.jpg", "003.jpg"],
|
||||
"pages sorted by name"
|
||||
);
|
||||
|
||||
// temp_dir goes out of scope and cleans up automatically
|
||||
}
|
||||
40
tests/job_and_format_tests.rs
Normal file
40
tests/job_and_format_tests.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use cbz2pdf::formats::FormatId;
|
||||
use cbz2pdf::job::Job;
|
||||
|
||||
#[test]
|
||||
fn detect_from_path_recognizes_extensions() {
|
||||
let cbz = PathBuf::from("/tmp/book.cbz");
|
||||
let pdf = PathBuf::from("/tmp/book.pdf");
|
||||
assert_eq!(FormatId::detect_from_path(&cbz), Some(FormatId::Cbz));
|
||||
assert_eq!(FormatId::detect_from_path(&pdf), Some(FormatId::Pdf));
|
||||
assert_eq!(
|
||||
FormatId::detect_from_path(&PathBuf::from("/tmp/book.txt")),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn job_new_sets_output_extension() {
|
||||
let input = PathBuf::from("/tmp/book.cbz");
|
||||
let outdir = PathBuf::from("/tmp");
|
||||
let job = Job::new(input.clone(), outdir.clone(), FormatId::Cbz, FormatId::Pdf);
|
||||
assert!(job.output_path.ends_with("book.pdf"));
|
||||
|
||||
let job2 = Job::new(
|
||||
PathBuf::from("/tmp/book.pdf"),
|
||||
outdir,
|
||||
FormatId::Pdf,
|
||||
FormatId::Cbz,
|
||||
);
|
||||
assert!(job2.output_path.ends_with("book.cbz"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_capabilities_consistent() {
|
||||
assert!(FormatId::Cbz.can_read());
|
||||
assert!(!FormatId::Cbz.can_write());
|
||||
assert!(FormatId::Pdf.can_write());
|
||||
assert!(!FormatId::Pdf.can_read());
|
||||
}
|
||||
38
tests/pdf_writer_smoke.rs
Normal file
38
tests/pdf_writer_smoke.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
use std::fs;
|
||||
use std::io::Read;
|
||||
|
||||
use cbz2pdf::formats::pdf::PdfWriter;
|
||||
use cbz2pdf::formats::FormatWriter;
|
||||
use cbz2pdf::model::{Document, ImagePage};
|
||||
|
||||
#[test]
|
||||
fn pdf_writer_writes_valid_pdf_header() {
|
||||
// Build a simple 2x2 red image page
|
||||
let mut img = image::DynamicImage::new_rgb8(2, 2).to_rgb8();
|
||||
for p in img.pixels_mut() {
|
||||
*p = image::Rgb([255, 0, 0]);
|
||||
}
|
||||
let page = ImagePage {
|
||||
name: "page1.jpg".to_string(),
|
||||
image: image::DynamicImage::ImageRgb8(img),
|
||||
jpeg_dct: None,
|
||||
};
|
||||
let doc = Document::new(vec![page]);
|
||||
|
||||
let temp_dir = tempfile::tempdir().expect("create temp dir");
|
||||
let output = temp_dir.path().join("out.pdf");
|
||||
|
||||
let writer = PdfWriter;
|
||||
writer.write(&doc, &output).expect("failed to write PDF");
|
||||
|
||||
// Assert file exists and has PDF header
|
||||
let mut f = fs::File::open(&output).expect("pdf not created");
|
||||
let mut header = [0u8; 5];
|
||||
f.read_exact(&mut header).expect("cannot read header");
|
||||
assert_eq!(&header, b"%PDF-", "missing PDF header");
|
||||
|
||||
let meta = fs::metadata(&output).unwrap();
|
||||
assert!(meta.len() > 0, "empty pdf");
|
||||
|
||||
// temp_dir cleans up automatically on drop
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue