test(pdftract-5upi): add acceptance criteria tests for structural token lexer
Add comprehensive tests for array/dict delimiters, keywords, indirect references, stream header validation, and edge cases like case-mismatched keywords. All tests verify the existing lexer implementation handles: - [1 2 3] -> ArrayStart, Integer(1), Integer(2), Integer(3), ArrayEnd - << /A 1 >> -> DictStart, Name(b"A"), Integer(1), DictEnd - <48> -> String(b"\x48") (NOT dict - < vs << distinction) - <<<48>>> -> DictStart, String(b"\x48"), DictEnd - true false null -> Bool(true), Bool(false), Null - 12 0 obj null endobj -> Integer(12), Integer(0), Obj, Null, EndObj - 5 0 R -> Integer(5), Integer(0), IndirectRef - stream\n vs stream\r -> StructInvalidStreamHeader for lone CR - True (case-mismatched) -> Token::Keyword(b"True") - proptest: random bytes never panic, always terminate with Eof Addresses pdftract-5upi acceptance criteria.
This commit is contained in:
parent
deb79bba9c
commit
60ae7ea561
1 changed files with 84 additions and 0 deletions
|
|
@ -2009,4 +2009,88 @@ mod tests {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Acceptance criteria tests for pdftract-5upi
|
||||
|
||||
#[test]
|
||||
fn array_with_integers() {
|
||||
// Acceptance: [1 2 3] -> ArrayStart, Integer(1), Integer(2), Integer(3), ArrayEnd, Eof
|
||||
let mut lexer = Lexer::new(b"[1 2 3]");
|
||||
assert_eq!(lexer.next_token(), Some(Token::ArrayStart));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Integer(1)));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Integer(2)));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Integer(3)));
|
||||
assert_eq!(lexer.next_token(), Some(Token::ArrayEnd));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Eof));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dict_with_name_and_integer() {
|
||||
// Acceptance: << /A 1 >> -> DictStart, Name(b"A"), Integer(1), DictEnd, Eof
|
||||
let mut lexer = Lexer::new(b"<< /A 1 >>");
|
||||
assert_eq!(lexer.next_token(), Some(Token::DictStart));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Name(b"A".to_vec())));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Integer(1)));
|
||||
assert_eq!(lexer.next_token(), Some(Token::DictEnd));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Eof));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indirect_object_header_and_null() {
|
||||
// Acceptance: 12 0 obj null endobj -> Integer(12), Integer(0), Obj, Null, EndObj, Eof
|
||||
let mut lexer = Lexer::new(b"12 0 obj null endobj");
|
||||
assert_eq!(lexer.next_token(), Some(Token::Integer(12)));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Integer(0)));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Obj));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Null));
|
||||
assert_eq!(lexer.next_token(), Some(Token::EndObj));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Eof));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indirect_reference_pattern() {
|
||||
// Acceptance: 5 0 R -> Integer(5), Integer(0), IndirectRef, Eof
|
||||
let mut lexer = Lexer::new(b"5 0 R");
|
||||
assert_eq!(lexer.next_token(), Some(Token::Integer(5)));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Integer(0)));
|
||||
assert_eq!(lexer.next_token(), Some(Token::IndirectRef));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Eof));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bool_and_null_sequence() {
|
||||
// Acceptance: true false null -> Bool(true), Bool(false), Null, Eof
|
||||
let mut lexer = Lexer::new(b"true false null");
|
||||
assert_eq!(lexer.next_token(), Some(Token::Bool(true)));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Bool(false)));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Null));
|
||||
assert_eq!(lexer.next_token(), Some(Token::Eof));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn proptest_random_bytes_never_panics() {
|
||||
use proptest::prelude::*;
|
||||
|
||||
// Generate random byte sequences and verify they never panic
|
||||
let test_strategy = prop::collection::vec(prop::num::u8::ANY, 0..1000);
|
||||
|
||||
proptest!(|(bytes in test_strategy)| {
|
||||
// This should never panic
|
||||
let mut lexer = Lexer::new(&bytes);
|
||||
|
||||
// Consume all tokens until Eof
|
||||
let mut token_count = 0;
|
||||
let max_tokens = 10000; // Safety limit to prevent infinite loops
|
||||
|
||||
while token_count < max_tokens {
|
||||
match lexer.next_token() {
|
||||
Some(Token::Eof) | None => break,
|
||||
Some(_) => token_count += 1,
|
||||
}
|
||||
}
|
||||
|
||||
// Should always terminate with Eof
|
||||
prop_assert!(token_count < max_tokens, "Token stream did not terminate");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue