use super::*;
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[test]
fn tokenizer_position_line_column_advancement() {
let source = "[Section]\nKey=Value\n! Comment";
let mut tokenizer = AssTokenizer::new(source);
let mut last_pos = 0;
let mut tokens = Vec::new();
while let Ok(Some(token)) = tokenizer.next_token() {
let current_pos = tokenizer.position();
if !tokenizer.scanner.navigator().is_at_end() {
assert!(current_pos > last_pos, "Position must advance");
}
assert!(token.line >= 1);
assert!(token.column >= 1);
tokens.push(token);
last_pos = current_pos;
if tokens.len() > 20 {
break;
}
}
assert!(!tokens.is_empty());
}
#[test]
fn tokenizer_span_creation_and_boundaries() {
let source = "[Test]\nField=Value123";
let mut tokenizer = AssTokenizer::new(source);
while let Ok(Some(token)) = tokenizer.next_token() {
assert!(
!token.span.is_empty()
|| token.token_type == crate::tokenizer::tokens::TokenType::Comment
);
assert!(token.span.len() <= source.len());
let start_pos = token.span.as_ptr() as usize - source.as_ptr() as usize;
assert!(start_pos < source.len());
}
}
#[test]
fn tokenizer_iteration_limit_comprehensive() {
let source = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,1,2,3,4,5,6,7,8,9,0,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z";
let mut tokenizer = AssTokenizer::new(source);
let result = tokenizer.tokenize_all();
if let Ok(tokens) = result {
assert!(tokens.len() <= 50, "Should respect iteration limit");
} else {
}
}
#[test]
fn tokenizer_all_error_recovery() {
let source = "Valid[Section]\n\x00InvalidChar\nKey=Value";
let mut tokenizer = AssTokenizer::new(source);
let result = tokenizer.tokenize_all();
match result {
Ok(tokens) => {
assert!(!tokens.is_empty());
}
Err(_) => {
assert!(!tokenizer.issues().is_empty());
}
}
}
#[test]
fn tokenizer_empty_source_boundaries() {
let source = "";
let mut tokenizer = AssTokenizer::new(source);
assert_eq!(tokenizer.position(), 0);
assert_eq!(tokenizer.line(), 1);
assert_eq!(tokenizer.column(), 1);
let result = tokenizer.next_token();
assert!(result.is_ok());
assert!(result.unwrap().is_none());
}
#[test]
fn tokenizer_single_character_advancement() {
let source = "a";
let mut tokenizer = AssTokenizer::new(source);
let start_pos = tokenizer.position();
if let Ok(Some(token)) = tokenizer.next_token() {
let end_pos = tokenizer.position();
assert!(end_pos > start_pos);
assert_eq!(token.span, "a");
}
}
#[test]
fn tokenizer_multi_byte_character_advancement() {
let source = "🎵音楽";
let mut tokenizer = AssTokenizer::new(source);
let mut positions = Vec::new();
positions.push(tokenizer.position());
while let Ok(Some(_)) = tokenizer.next_token() {
positions.push(tokenizer.position());
if positions.len() > 10 {
break; }
}
for window in positions.windows(2) {
if window[1] != window[0] {
assert!(window[1] > window[0]);
}
}
}
#[test]
fn tokenizer_token_push_verification() {
let source = "Key1=Value1\nKey2=Value2";
let mut tokenizer = AssTokenizer::new(source);
let tokens = tokenizer.tokenize_all().unwrap_or_default();
assert!(!tokens.is_empty());
for token in &tokens {
assert!(
!token.span.is_empty()
|| token.token_type == crate::tokenizer::tokens::TokenType::Comment
);
}
}