use oxidize_pdf::parser::{
content::{ContentOperation, ContentParser},
objects::{PdfArray, PdfDictionary, PdfName, PdfObject, PdfStream, PdfString},
ParseError, ParseResult,
};
use std::collections::HashMap;
#[cfg(test)]
mod content_parser_tests {
use super::*;
#[test]
fn test_parse_inline_image() {
let content = b"BI /W 10 /H 10 /CS /RGB ID \x00\x01\x02\x03 EI";
let result = ContentParser::parse(content);
match result {
Ok(ops) => {
let _has_inline_image = ops
.iter()
.any(|op| matches!(op, ContentOperation::BeginInlineImage));
}
Err(_) => {
}
}
}
#[test]
fn test_parse_marked_content() {
let content = b"BMC q 100 200 m 150 250 l S Q EMC";
let result = ContentParser::parse(content);
match result {
Ok(ops) => {
assert!(!ops.is_empty());
}
Err(_) => {
}
}
}
#[test]
fn test_parse_text_positioning() {
let content = b"BT /F1 12 Tf 100 700 Td (Hello) Tj 0 -20 TD (World) Tj ET";
let ops = ContentParser::parse(content).unwrap();
assert!(ops
.iter()
.any(|op| matches!(op, ContentOperation::BeginText)));
assert!(ops.iter().any(|op| matches!(op, ContentOperation::EndText)));
}
#[test]
fn test_parse_color_operations() {
let content = b"1 0 0 rg 0.5 0.5 0.5 RG 0 0 0 1 k 0.2 0.3 0.4 0.5 K";
let ops = ContentParser::parse(content).unwrap();
assert!(ops.len() >= 4);
}
#[test]
fn test_parse_path_construction() {
let content = b"100 200 m 150 250 l 200 200 300 300 400 200 c h S";
let ops = ContentParser::parse(content).unwrap();
assert!(ops.len() >= 5);
}
#[test]
fn test_parse_transformation_matrix() {
let content = b"q 2 0 0 2 100 100 cm 50 50 m 100 100 l S Q";
let ops = ContentParser::parse(content).unwrap();
assert!(ops
.iter()
.any(|op| matches!(op, ContentOperation::SaveGraphicsState)));
assert!(ops
.iter()
.any(|op| matches!(op, ContentOperation::RestoreGraphicsState)));
}
#[test]
fn test_parse_shading_patterns() {
let content = b"/Pattern cs /P1 scn 100 200 300 400 re f";
let result = ContentParser::parse(content);
assert!(result.is_ok() || result.is_err());
}
#[test]
fn test_parse_xobject_invocation() {
let content = b"q 100 0 0 100 50 50 cm /Im1 Do Q";
let ops = ContentParser::parse(content).unwrap();
assert!(ops.iter().any(|op| match op {
ContentOperation::PaintXObject(_) => true,
_ => false,
}));
}
#[test]
fn test_tokenizer_edge_cases() {
let result = ContentParser::parse(b"");
assert!(result.is_ok());
assert!(result.unwrap().is_empty());
let result = ContentParser::parse(b" \n\r\t ");
assert!(result.is_ok());
}
#[test]
fn test_parse_invalid_operators() {
let content = b"INVALID_OP 100 200 m ANOTHER_BAD_OP";
let result = ContentParser::parse(content);
assert!(result.is_ok() || result.is_err());
}
}
#[cfg(test)]
mod objects_parser_tests {
use super::*;
#[test]
fn test_pdf_reference_handling() {
let mut dict = PdfDictionary(HashMap::new());
dict.0.insert(
PdfName::new("Parent".to_string()),
PdfObject::Reference(1, 0),
);
assert!(dict.0.contains_key(&PdfName::new("Parent".to_string())));
}
#[test]
fn test_pdf_dictionary_nested() {
let mut inner_dict = PdfDictionary(HashMap::new());
inner_dict.0.insert(
PdfName::new("InnerKey".to_string()),
PdfObject::String(PdfString(b"InnerValue".to_vec())),
);
let mut outer_dict = PdfDictionary(HashMap::new());
outer_dict.0.insert(
PdfName::new("OuterKey".to_string()),
PdfObject::Dictionary(inner_dict),
);
if let Some(PdfObject::Dictionary(inner)) =
outer_dict.0.get(&PdfName::new("OuterKey".to_string()))
{
assert!(inner.0.contains_key(&PdfName::new("InnerKey".to_string())));
} else {
panic!("Nested dictionary not found");
}
}
#[test]
fn test_pdf_array_operations() {
let mut array = PdfArray(vec![
PdfObject::Integer(1),
PdfObject::Integer(2),
PdfObject::Integer(3),
]);
assert_eq!(array.0.len(), 3);
array.0.push(PdfObject::Integer(4));
assert_eq!(array.0.len(), 4);
if let PdfObject::Integer(val) = &array.0[0] {
assert_eq!(*val, 1);
}
}
#[test]
fn test_pdf_stream_with_filters() {
let mut dict = PdfDictionary(HashMap::new());
dict.0.insert(
PdfName::new("Filter".to_string()),
PdfObject::Name(PdfName::new("FlateDecode".to_string())),
);
dict.0
.insert(PdfName::new("Length".to_string()), PdfObject::Integer(100));
let stream = PdfStream {
dict: dict.clone(),
data: vec![0u8; 100],
};
assert!(dict.0.contains_key(&PdfName::new("Filter".to_string())));
assert_eq!(stream.data.len(), 100);
}
#[test]
fn test_pdf_object_conversion() {
let int_obj = PdfObject::Integer(42);
let real_obj = PdfObject::Real(3.14);
let bool_obj = PdfObject::Boolean(true);
let null_obj = PdfObject::Null;
match int_obj {
PdfObject::Integer(val) => assert_eq!(val, 42),
_ => panic!("Wrong type"),
}
match real_obj {
PdfObject::Real(val) => assert!((val - 3.14).abs() < 0.001),
_ => panic!("Wrong type"),
}
match bool_obj {
PdfObject::Boolean(val) => assert!(val),
_ => panic!("Wrong type"),
}
match null_obj {
PdfObject::Null => {} _ => panic!("Wrong type"),
}
}
#[test]
fn test_pdf_hexstring() {
let hex_string = PdfObject::String(PdfString(vec![0xFF, 0xAB, 0xCD, 0xEF]));
match hex_string {
PdfObject::String(data) => {
assert_eq!(data.0.len(), 4);
assert_eq!(data.0[0], 0xFF);
}
_ => panic!("Wrong type"),
}
}
#[test]
fn test_pdf_name_escaping() {
let name1 = PdfName::new("Simple".to_string());
let name2 = PdfName::new("With#20Space".to_string());
let name3 = PdfName::new("With/Slash".to_string());
assert_eq!(name1.0, "Simple");
assert_eq!(name2.0, "With#20Space");
assert_eq!(name3.0, "With/Slash");
}
#[test]
fn test_circular_reference_detection() {
let mut dict1 = PdfDictionary(HashMap::new());
dict1
.0
.insert(PdfName::new("Next".to_string()), PdfObject::Reference(2, 0));
assert!(dict1.0.contains_key(&PdfName::new("Next".to_string())));
}
}
#[cfg(test)]
mod parser_error_tests {
use super::*;
#[test]
fn test_parse_error_creation() {
let err = ParseError::SyntaxError {
position: 0,
message: "Test error".to_string(),
};
match err {
ParseError::SyntaxError { message, .. } => {
assert_eq!(message, "Test error");
}
_ => panic!("Wrong error type"),
}
}
#[test]
fn test_parse_error_propagation() {
fn parse_something() -> ParseResult<i32> {
Err(ParseError::UnexpectedToken {
expected: "value".to_string(),
found: "EOF".to_string(),
})
}
let result = parse_something();
assert!(result.is_err());
match result.unwrap_err() {
ParseError::UnexpectedToken { .. } => {} _ => panic!("Wrong error type"),
}
}
#[test]
fn test_parse_error_conversion() {
use std::io;
let io_err = io::Error::new(io::ErrorKind::NotFound, "File not found");
let parse_err = ParseError::from(io_err);
match parse_err {
ParseError::Io(_) => {} _ => panic!("Wrong error type"),
}
}
}