use crate::tokenizer::{AssTokenizer, TokenType};
#[test]
fn position_after_each_token() {
let mut tokenizer = AssTokenizer::new("abc,def");
let mut last_pos = 0;
while let Some(token) = tokenizer.next_token().unwrap() {
assert!(tokenizer.position() >= last_pos);
last_pos = tokenizer.position();
assert!(!token.span.is_empty() || matches!(token.token_type, TokenType::Comma));
}
}
#[test]
fn context_reset_on_newline() {
let mut tokenizer = AssTokenizer::new("field: value\nnext line");
let _field = tokenizer.next_token().unwrap().unwrap();
let _colon = tokenizer.next_token().unwrap().unwrap();
let _value = tokenizer.next_token().unwrap().unwrap();
let _newline = tokenizer.next_token().unwrap().unwrap();
let next_token = tokenizer.next_token().unwrap().unwrap();
assert_eq!(next_token.token_type, TokenType::Text);
assert_eq!(next_token.span, "next line");
}
#[test]
fn bom_with_various_content() {
let contents = [
"\u{FEFF}[Section]",
"\u{FEFF}text content",
"\u{FEFF}{\\override}",
"\u{FEFF}; comment",
];
for content in &contents {
let mut tokenizer = AssTokenizer::new(content);
assert_eq!(tokenizer.position(), 3); let tokens = tokenizer.tokenize_all().unwrap();
assert!(!tokens.is_empty());
}
}
#[test]
fn tokenize_all_iteration_limit() {
let long_text = "a".repeat(100);
let mut tokenizer = AssTokenizer::new(&long_text);
let result = tokenizer.tokenize_all();
assert!(result.is_ok());
}
#[test]
fn complex_dialogue_line() {
let dialogue = "Dialogue: 0,0:00:00.00,0:00:05.00,Default,{\\an8\\fad(300,300)}Hello {\\c&H0000FF&}world{\\r}!";
let mut tokenizer = AssTokenizer::new(dialogue);
let tokens = tokenizer.tokenize_all().unwrap();
assert!(tokens.len() > 10);
let has_text = tokens.iter().any(|t| t.token_type == TokenType::Text);
let has_colon = tokens.iter().any(|t| t.token_type == TokenType::Colon);
let has_comma = tokens.iter().any(|t| t.token_type == TokenType::Comma);
let has_override = tokens
.iter()
.any(|t| t.token_type == TokenType::OverrideBlock);
assert!(has_text);
assert!(has_colon);
assert!(has_comma);
assert!(has_override);
}
#[test]
fn tokenizer_error_path_scanner_failure() {
let mut tokenizer = AssTokenizer::new("[\x00invalid");
let result = tokenizer.next_token();
assert!(result.is_ok() || result.is_err());
}
#[test]
fn tokenizer_infinite_loop_protection() {
let mut tokenizer = AssTokenizer::new("");
let mut count = 0;
while tokenizer.next_token().unwrap().is_some() {
count += 1;
assert!(count <= 1000, "Tokenizer stuck in infinite loop");
}
}
#[test]
fn tokenizer_position_advancement_check() {
let mut tokenizer = AssTokenizer::new("abc");
let mut last_pos = 0;
while let Some(_token) = tokenizer.next_token().unwrap() {
let current_pos = tokenizer.position();
assert!(current_pos > last_pos);
last_pos = current_pos;
}
}
#[test]
fn context_enter_field_value() {
let mut tokenizer = AssTokenizer::new("Key: Value here");
let _key = tokenizer.next_token().unwrap();
let colon = tokenizer.next_token().unwrap();
assert_eq!(colon.unwrap().token_type, TokenType::Colon);
let value = tokenizer.next_token().unwrap();
assert!(value.is_some());
}