add unit tests for lexer methods

This commit is contained in:
Josh Thomas 2024-10-16 11:14:47 -05:00
parent 8979493eac
commit 926b44f175

View file

@ -175,14 +175,7 @@ impl<'a> Lexer<'a> {
fn text(&mut self) -> Result<TokenType, LexerError> {
self.advance_while(|c| !Self::is_token_boundary(c))?;
if self.state.start == self.state.current {
Err(LexerError::EmptyToken {
line: self.state.line,
})
} else {
Ok(TokenType::Text)
}
Ok(TokenType::Text)
}
fn advance_if_matches(&mut self, expected: char) -> Result<bool, LexerError> {
@ -299,12 +292,207 @@ impl<'a> Tokenizer<'a> for Lexer<'a> {
mod tests {
use super::*;
mod lexer {
use super::*;
#[test]
fn test_lexer_new() {
let lexer = Lexer::new("");
assert_eq!(lexer.source, "");
assert_eq!(lexer.tokens.len(), 0);
assert_eq!(lexer.state.start, 0);
assert_eq!(lexer.state.current, 0);
assert_eq!(lexer.state.line, 1);
}
fn assert_token_type<F>(test_cases: Vec<(&str, TokenType)>, method: F)
where
F: Fn(&mut Lexer, Option<char>) -> Result<TokenType, LexerError>,
{
for (input, expected) in test_cases {
let mut chars = input.chars();
let first_char = chars.next().unwrap();
let second_char = chars.next();
let source = second_char.map_or(String::new(), |c| c.to_string());
let mut lexer = Lexer::new(&source);
match method(&mut lexer, Some(first_char)) {
Ok(token_type) => assert_eq!(token_type, expected, "Input: {}", input),
Err(e) => panic!(
"Expected {:?}, but got Err({:?}) for input: {}",
expected, e, input
),
}
}
}
#[test]
fn test_match_token_type() {
let test_cases = vec![
("(", TokenType::LeftParen),
(")", TokenType::RightParen),
("{", TokenType::LeftBrace),
("}", TokenType::RightBrace),
("[", TokenType::LeftBracket),
("]", TokenType::RightBracket),
("<", TokenType::LeftAngle),
(">", TokenType::RightAngle),
(",", TokenType::Comma),
(".", TokenType::Dot),
("-", TokenType::Minus),
("+", TokenType::Plus),
(":", TokenType::Colon),
(";", TokenType::Semicolon),
("/", TokenType::Slash),
("*", TokenType::Star),
("!", TokenType::Bang),
("=", TokenType::Equal),
("|", TokenType::Pipe),
("%", TokenType::Percent),
("#", TokenType::Hash),
("'", TokenType::SingleQuote),
("\"", TokenType::DoubleQuote),
("{{", TokenType::DoubleLeftBrace),
("}}", TokenType::DoubleRightBrace),
("{%", TokenType::LeftBracePercent),
("%}", TokenType::PercentRightBrace),
("{#", TokenType::LeftBraceHash),
("#}", TokenType::HashRightBrace),
("!=", TokenType::BangEqual),
("==", TokenType::DoubleEqual),
("<=", TokenType::LeftAngleEqual),
(">=", TokenType::RightAngleEqual),
(" ", TokenType::Whitespace),
("\r", TokenType::Whitespace),
("\t", TokenType::Whitespace),
("\n", TokenType::Whitespace),
(" ", TokenType::Whitespace),
(" \n", TokenType::Whitespace),
(" \r\n", TokenType::Whitespace),
("a", TokenType::Text),
("1", TokenType::Text),
("Hello", TokenType::Text),
];
assert_token_type(test_cases, |lexer, c| lexer.match_token_type(c.unwrap()));
}
#[test]
fn test_left_brace() {
let test_cases = vec![
("{", TokenType::LeftBrace),
("{{", TokenType::DoubleLeftBrace),
("{%", TokenType::LeftBracePercent),
("{#", TokenType::LeftBraceHash),
("{a", TokenType::LeftBrace),
];
assert_token_type(test_cases, |lexer, _| lexer.left_brace());
}
#[test]
fn test_right_brace() {
let test_cases = vec![
("}", TokenType::RightBrace),
("}}", TokenType::DoubleRightBrace),
];
assert_token_type(test_cases, |lexer, _| lexer.right_brace());
}
#[test]
fn test_percent() {
let test_cases = vec![
("%", TokenType::Percent),
("%}", TokenType::PercentRightBrace),
];
assert_token_type(test_cases, |lexer, _| lexer.percent());
}
#[test]
fn test_hash() {
let test_cases = vec![("#", TokenType::Hash), ("#}", TokenType::HashRightBrace)];
assert_token_type(test_cases, |lexer, _| lexer.hash());
}
#[test]
fn test_bang() {
let test_cases = vec![("!", TokenType::Bang), ("!=", TokenType::BangEqual)];
assert_token_type(test_cases, |lexer, _| lexer.bang());
}
#[test]
fn test_equal() {
let test_cases = vec![("=", TokenType::Equal), ("==", TokenType::DoubleEqual)];
assert_token_type(test_cases, |lexer, _| lexer.equal());
}
#[test]
fn test_left_angle() {
let test_cases = vec![
("<", TokenType::LeftAngle),
("<=", TokenType::LeftAngleEqual),
];
assert_token_type(test_cases, |lexer, _| lexer.left_angle());
}
#[test]
fn test_right_angle() {
let test_cases = vec![
(">", TokenType::RightAngle),
(">=", TokenType::RightAngleEqual),
];
assert_token_type(test_cases, |lexer, _| lexer.right_angle());
}
#[test]
fn test_slash() {
let test_cases = vec![("/", TokenType::Slash)];
assert_token_type(test_cases, |lexer, _| lexer.slash());
}
#[test]
fn test_whitespace() {
let test_cases = vec![
(" ", TokenType::Whitespace),
("\r", TokenType::Whitespace),
("\t", TokenType::Whitespace),
("\n", TokenType::Whitespace),
(" ", TokenType::Whitespace),
(" \n", TokenType::Whitespace),
(" \r\n", TokenType::Whitespace),
];
assert_token_type(test_cases, |lexer, c| lexer.whitespace(c.unwrap()));
}
#[test]
fn test_text() {
let test_cases = vec![
("a", TokenType::Text),
("1", TokenType::Text),
("Hello", TokenType::Text),
];
assert_token_type(test_cases, |lexer, _| lexer.text());
}
}
fn tokenize(input: &str) -> Vec<Token> {
let mut lexer = Lexer::new(input);
match lexer.tokenize() {
Ok(tokens) => {
// Debug print all tokens
for (i, token) in tokens.iter().enumerate() {
for token in tokens.iter() {
println!("{:?}", token)
}