use djvu_rs::IffError;
use djvu_rs::djvu_document::{DjVuDocument, DocError};
use djvu_rs::djvu_render::{RenderOptions, render_coarse, render_pixmap, render_progressive};
use djvu_rs::iff::parse_form;
#[test]
fn djvu_document_parse_single_page() {
let data = std::fs::read("tests/fixtures/boy.djvu").unwrap();
let doc = DjVuDocument::parse(&data).expect("boy.djvu must parse without error");
assert_eq!(doc.page_count(), 1);
}
#[test]
fn djvu_document_parse_multipage() {
let data = std::fs::read("tests/corpus/watchmaker.djvu").unwrap();
let doc = DjVuDocument::parse(&data).expect("watchmaker.djvu must parse");
assert!(doc.page_count() > 1, "watchmaker.djvu has multiple pages");
}
#[test]
fn djvu_document_parse_empty_returns_error() {
let result = DjVuDocument::parse(&[]);
assert!(result.is_err(), "empty data must return Err");
}
#[test]
fn djvu_document_parse_garbage_no_panic() {
let _ = DjVuDocument::parse(b"this is not a djvu file at all!!");
}
#[test]
fn djvu_page_dimensions_single() {
let data = std::fs::read("tests/fixtures/boy.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).expect("page 0 must exist");
assert!(page.width() > 0 && page.height() > 0);
assert!(page.dpi() > 0);
assert_eq!(page.index(), 0);
}
#[test]
fn djvu_page_dimensions_tuple_matches() {
let data = std::fs::read("tests/fixtures/boy.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
assert_eq!(page.dimensions(), (page.width(), page.height()));
}
#[test]
fn djvu_page_out_of_bounds_returns_error() {
let data = std::fs::read("tests/fixtures/boy.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let result = doc.page(999);
assert!(result.is_err(), "out-of-bounds page access must return Err");
}
#[test]
fn djvu_page_bg44_chunks_color_page() {
let data = std::fs::read("tests/fixtures/boy.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
let chunks = page.bg44_chunks();
assert!(
!chunks.is_empty(),
"color page must have at least one BG44 chunk"
);
}
#[test]
fn djvu_page_find_chunk_existing() {
let data = std::fs::read("tests/fixtures/boy.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
assert!(
page.find_chunk(b"INFO").is_some(),
"INFO chunk must be found"
);
}
#[test]
fn djvu_page_find_chunk_missing() {
let data = std::fs::read("tests/fixtures/boy.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
assert!(page.find_chunk(b"XXXX").is_none());
}
#[test]
fn doc_error_implements_error_trait() {
fn requires_error<E: std::error::Error>() {}
requires_error::<DocError>();
}
#[test]
fn render_pixmap_default_options_boy() {
let data = std::fs::read("tests/fixtures/boy.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
let opts = RenderOptions {
width: page.width() as u32,
height: page.height() as u32,
..RenderOptions::default()
};
let pixmap = render_pixmap(page, &opts).expect("render_pixmap must succeed");
assert!(pixmap.width > 0 && pixmap.height > 0);
assert_eq!(
pixmap.data.len(),
(pixmap.width * pixmap.height * 4) as usize
);
}
#[test]
fn render_pixmap_bilevel_page() {
let data = std::fs::read("tests/fixtures/boy_jb2.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
let opts = RenderOptions {
width: page.width() as u32,
height: page.height() as u32,
..RenderOptions::default()
};
let pixmap = render_pixmap(page, &opts).expect("bilevel render must succeed");
assert!(pixmap.width > 0 && pixmap.height > 0);
}
#[test]
fn render_coarse_color_page() {
let data = std::fs::read("tests/fixtures/boy.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
let opts = RenderOptions {
width: page.width() as u32,
height: page.height() as u32,
..RenderOptions::default()
};
let result = render_coarse(page, &opts).expect("render_coarse must not error");
assert!(result.is_some(), "color page must produce coarse pixmap");
let pix = result.unwrap();
assert!(pix.width > 0 && pix.height > 0);
}
#[test]
fn render_coarse_bilevel_page_no_error() {
let data = std::fs::read("tests/fixtures/boy_jb2.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
let opts = RenderOptions {
width: page.width() as u32,
height: page.height() as u32,
..RenderOptions::default()
};
let _ = render_coarse(page, &opts).expect("render_coarse must not error on bilevel");
}
#[test]
fn render_progressive_each_chunk() {
let data = std::fs::read("tests/fixtures/boy.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
let n = page.bg44_chunks().len();
assert!(n > 0, "boy.djvu must have BG44 chunks");
let opts = RenderOptions {
width: page.width() as u32,
height: page.height() as u32,
..RenderOptions::default()
};
for i in 0..n {
let pix = render_progressive(page, &opts, i)
.unwrap_or_else(|e| panic!("render_progressive chunk {i} failed: {e}"));
assert!(pix.width > 0 && pix.height > 0);
assert_eq!(pix.data.len(), (pix.width * pix.height * 4) as usize);
}
}
#[test]
fn iff_parse_form_single_page() {
let data = std::fs::read("tests/fixtures/boy.djvu").unwrap();
let form = parse_form(&data).expect("boy.djvu must parse as IFF");
assert_eq!(&form.form_type, b"DJVU");
assert!(
!form.chunks.is_empty(),
"DJVU form must have at least one chunk"
);
}
#[test]
fn iff_parse_form_multipage_djvm() {
let data = std::fs::read("tests/corpus/watchmaker.djvu").unwrap();
let form = parse_form(&data).expect("watchmaker.djvu must parse as IFF");
assert_eq!(&form.form_type, b"DJVM");
}
#[test]
fn iff_parse_form_empty_returns_error() {
let result = parse_form(&[]);
assert!(result.is_err());
}
#[test]
fn iff_parse_form_truncated_returns_error() {
let result = parse_form(b"AT&T");
assert!(result.is_err());
}
#[test]
fn iff_parse_form_wrong_magic_returns_error() {
let bad: &[u8] = b"XXXX\x00\x00\x00\x04DJVU";
let result = parse_form(bad);
assert!(result.is_err());
}
#[test]
fn iff_error_implements_error_trait() {
fn requires_error<E: std::error::Error>() {}
requires_error::<IffError>();
}
#[test]
fn extract_mask_bilevel_page() {
let data = std::fs::read("tests/fixtures/boy_jb2.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
let mask = page.extract_mask().expect("extract_mask must not error");
assert!(mask.is_some(), "boy_jb2 must have a JB2 mask");
let bm = mask.unwrap();
assert_eq!(bm.width as u16, page.width());
assert_eq!(bm.height as u16, page.height());
}
#[test]
fn extract_mask_no_sjbz_returns_none() {
let data = std::fs::read("tests/fixtures/chicken.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
let mask = page.extract_mask().expect("must not error");
assert!(mask.is_none(), "IW44-only page should have no mask");
}
#[test]
fn extract_foreground_3layer() {
let data = std::fs::read("tests/fixtures/colorbook.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
let fg = page
.extract_foreground()
.expect("extract_foreground must not error");
assert!(
fg.is_some(),
"colorbook.djvu should have a foreground layer"
);
let pm = fg.unwrap();
assert!(pm.width > 0 && pm.height > 0);
}
#[test]
fn extract_foreground_no_fg44_returns_none() {
let data = std::fs::read("tests/fixtures/boy_jb2.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
let fg = page.extract_foreground().expect("must not error");
assert!(fg.is_none(), "bilevel page should have no foreground layer");
}
#[test]
fn extract_background_color_page() {
let data = std::fs::read("tests/fixtures/chicken.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
let bg = page
.extract_background()
.expect("extract_background must not error");
assert!(bg.is_some(), "chicken.djvu should have a background");
let pm = bg.unwrap();
assert!(pm.width > 0 && pm.height > 0);
}
#[test]
fn extract_background_no_bg44_returns_none() {
let data = std::fs::read("tests/fixtures/boy_jb2.djvu").unwrap();
let doc = DjVuDocument::parse(&data).unwrap();
let page = doc.page(0).unwrap();
let bg = page.extract_background().expect("must not error");
assert!(bg.is_none(), "bilevel page should have no background");
}
#[test]
fn iff_find_first_existing_chunk() {
let data = std::fs::read("tests/fixtures/boy.djvu").unwrap();
let form = parse_form(&data).unwrap();
let info = form.chunks.iter().find(|c| &c.id == b"INFO");
assert!(info.is_some(), "INFO chunk must exist in a DJVU form");
}