#![cfg(feature = "flow")]
use harumi::{Document, FlowDocument, FlowOptions, Margins};
const NOTO: &[u8] = include_bytes!("fixtures/NotoSansJP-Regular.ttf");
#[test]
fn smoke_single_page() {
let mut doc = FlowDocument::new(NOTO, FlowOptions::default()).unwrap();
doc.push_heading("Title", 1).unwrap();
doc.push_paragraph("This is a body paragraph.").unwrap();
let bytes = doc.render().unwrap();
assert!(bytes.starts_with(b"%PDF"), "output must be a PDF");
assert!(bytes.len() > 100);
}
#[test]
fn auto_pagination() {
let mut doc = FlowDocument::new(NOTO, FlowOptions::default()).unwrap();
for i in 0..80 {
doc.push_paragraph(&format!("Paragraph {} with some content to fill the page.", i))
.unwrap();
}
let bytes = doc.render().unwrap();
let reloaded = Document::from_bytes(&bytes).unwrap();
assert!(reloaded.page_count() >= 2, "should have paginated to at least 2 pages");
}
#[test]
fn heading_levels() {
let mut doc = FlowDocument::new(NOTO, FlowOptions::default()).unwrap();
for level in 1..=6 {
doc.push_heading(&format!("Heading {}", level), level).unwrap();
doc.push_paragraph("Supporting text.").unwrap();
}
let bytes = doc.render().unwrap();
assert!(bytes.starts_with(b"%PDF"));
}
#[test]
fn key_value_table_smoke() {
let mut doc = FlowDocument::new(NOTO, FlowOptions::default()).unwrap();
doc.push_key_value_table(&[("Name", "Alice"), ("Age", "30"), ("City", "Tokyo")]).unwrap();
let bytes = doc.render().unwrap();
assert!(bytes.starts_with(b"%PDF"));
}
#[test]
fn empty_list_no_panic() {
let mut doc = FlowDocument::new(NOTO, FlowOptions::default()).unwrap();
doc.push_list(&[], false).unwrap();
doc.push_list(&[], true).unwrap();
let bytes = doc.render().unwrap();
assert!(bytes.starts_with(b"%PDF"));
}
#[test]
fn ordered_and_unordered_list() {
let mut doc = FlowDocument::new(NOTO, FlowOptions::default()).unwrap();
doc.push_list(&["Alpha", "Beta", "Gamma"], false).unwrap();
doc.push_list(&["First", "Second", "Third"], true).unwrap();
let bytes = doc.render().unwrap();
assert!(bytes.starts_with(b"%PDF"));
}
#[test]
fn explicit_page_break() {
let mut doc = FlowDocument::new(NOTO, FlowOptions::default()).unwrap();
doc.push_paragraph("Page one.").unwrap();
doc.push_page_break().unwrap();
doc.push_paragraph("Page two.").unwrap();
let bytes = doc.render().unwrap();
let reloaded = Document::from_bytes(&bytes).unwrap();
assert_eq!(reloaded.page_count(), 2);
}
#[test]
fn custom_margins() {
let opts = FlowOptions {
margins: Margins::uniform(36.0),
..FlowOptions::default()
};
let mut doc = FlowDocument::new(NOTO, opts).unwrap();
doc.push_heading("Narrow Margins", 1).unwrap();
doc.push_paragraph("Content with custom 36pt margins.").unwrap();
let bytes = doc.render().unwrap();
assert!(bytes.starts_with(b"%PDF"));
}
#[test]
fn cjk_paragraph_e2e() {
let mut doc = FlowDocument::new(NOTO, FlowOptions::default()).unwrap();
doc.push_heading("日本語の見出し", 1).unwrap();
doc.push_paragraph(
"これは日本語のサンプルテキストです。PDFに正しく出力されることを確認します。\
長いテキストが複数行に折り返されることも検証します。",
)
.unwrap();
doc.push_key_value_table(&[("名前", "田中健太郎"), ("住所", "東京都渋谷区")])
.unwrap();
let bytes = doc.render().unwrap();
assert!(bytes.starts_with(b"%PDF"));
if std::env::var("HARUMI_FLOW_OUT").is_ok() {
std::fs::write("flow_out.pdf", &bytes).unwrap();
eprintln!("Written to flow_out.pdf");
}
}
#[test]
fn max_pages_limit_returns_error() {
let opts = harumi::FlowOptions { max_pages: 2, ..harumi::FlowOptions::default() };
let mut doc = FlowDocument::new(NOTO, opts).unwrap();
let result = (0..500).try_for_each(|i| {
doc.push_paragraph(&format!("Paragraph {}", i))
});
assert!(result.is_err(), "should return error when max_pages exceeded");
}
#[test]
fn many_table_rows_paginate() {
let rows: Vec<(String, String)> = (0..50)
.map(|i| (format!("Key {}", i), format!("Value {}", i)))
.collect();
let rows_ref: Vec<(&str, &str)> = rows.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
let mut doc = FlowDocument::new(NOTO, FlowOptions::default()).unwrap();
doc.push_key_value_table(&rows_ref).unwrap();
let bytes = doc.render().unwrap();
let reloaded = Document::from_bytes(&bytes).unwrap();
assert!(reloaded.page_count() >= 2, "50 rows should span at least 2 pages");
}