diff options
Diffstat (limited to 'src/luax/tests')
| -rw-r--r-- | src/luax/tests/lexer.rs | 197 | ||||
| -rw-r--r-- | src/luax/tests/mod.rs | 2 | ||||
| -rw-r--r-- | src/luax/tests/preprocessor.rs | 198 |
3 files changed, 397 insertions, 0 deletions
diff --git a/src/luax/tests/lexer.rs b/src/luax/tests/lexer.rs new file mode 100644 index 0000000..997dc2c --- /dev/null +++ b/src/luax/tests/lexer.rs @@ -0,0 +1,197 @@ +use crate::luax::lexer::*; +use crate::luax::tokens::*; +use color_eyre::Result; + +fn compare_tokens<'a>(lua: &'a str, expected: Vec<Token<'a>>) -> Result<()> { + let mut lexer = Lexer::new(lua); + let mut tokens = Vec::new(); + loop { + let token = lexer.next_token()?; + if token.is_none() { + break; + } + tokens.push(token.unwrap()); + } + + assert_eq!(tokens, expected); + + Ok(()) +} + +#[test] +fn empty() -> Result<()> { + compare_tokens("", vec![Token::Eof]) +} + +#[test] +fn number() -> Result<()> { + compare_tokens("123", vec![Token::Number("123"), Token::Eof]) +} + +#[test] +fn string() -> Result<()> { + compare_tokens( + "\"hello world\"", + vec![Token::String("hello world", StringType::Double), Token::Eof], + ) +} + +#[test] +fn empty_string() -> Result<()> { + compare_tokens( + "\"\"", + vec![Token::String("", StringType::Double), Token::Eof], + ) +} + +#[test] +fn all_string_types() -> Result<()> { + compare_tokens( + "\"hello world\"'hello world'[[hello world]]", + vec![ + Token::String("hello world", StringType::Double), + Token::String("hello world", StringType::Single), + Token::String("hello world", StringType::DoubleBracket), + Token::Eof, + ], + ) +} + +#[test] +fn table() -> Result<()> { + compare_tokens( + "{1, 2, 3}", + vec![ + Token::OpenBrace, + Token::Number("1"), + Token::Comma, + Token::Number("2"), + Token::Comma, + Token::Number("3"), + Token::CloseBrace, + Token::Eof, + ], + ) +} + +#[test] +fn table_with_string_keys() -> Result<()> { + compare_tokens( + "{[\"a\"]=1, [\"b\"]=2, [\"c\"]=3}", + vec![ + Token::OpenBrace, + Token::OpenBracket, + Token::String("a", StringType::Double), + Token::CloseBracket, + Token::Eq, + Token::Number("1"), + Token::Comma, + Token::OpenBracket, + Token::String("b", StringType::Double), + Token::CloseBracket, + Token::Eq, + Token::Number("2"), + Token::Comma, + Token::OpenBracket, + Token::String("c", StringType::Double), + Token::CloseBracket, + Token::Eq, + Token::Number("3"), + Token::CloseBrace, + Token::Eof, + ], + ) +} + +#[test] +fn operators() -> Result<()> { + compare_tokens( + "+ - * / // ^ % & ~ | << >> .. < <= > >= == ~= and or # not", + vec![ + Token::Plus, + Token::Minus, + Token::Star, + Token::Slash, + Token::SlashSlash, + Token::Hat, + Token::Percent, + Token::Amp, + Token::Tilde, + Token::Pipe, + Token::LtLt, + Token::GtGt, + Token::DotDot, + Token::Lt, + Token::Le, + Token::Gt, + Token::Ge, + Token::EqEq, + Token::TildeEq, + Token::And, + Token::Or, + Token::Hash, + Token::Not, + Token::Eof, + ], + ) +} + +#[test] +fn keywords() -> Result<()> { + compare_tokens( + "and break do else elseif end false for function goto if in local nil not or repeat return then true until while", + vec![ + Token::And, + Token::Break, + Token::Do, + Token::Else, + Token::ElseIf, + Token::End, + Token::False, + Token::For, + Token::Function, + Token::Goto, + Token::If, + Token::In, + Token::Local, + Token::Nil, + Token::Not, + Token::Or, + Token::Repeat, + Token::Return, + Token::Then, + Token::True, + Token::Until, + Token::While, + Token::Eof, + ], + ) +} + +#[test] +fn html() -> Result<()> { + compare_tokens( + "<div class=\"hello\">hello world</div><img src=\"hello.png\"/>", + vec![ + Token::Lt, + Token::Identifier("div"), + Token::Identifier("class"), + Token::Eq, + Token::String("hello", StringType::Double), + Token::Gt, + Token::Identifier("hello"), + Token::Identifier("world"), + Token::OpenClosingTag, + Token::Identifier("div"), + Token::Gt, + Token::Lt, + Token::Identifier("img"), + Token::Identifier("src"), + Token::Eq, + Token::String("hello.png", StringType::Double), + Token::Slash, + Token::Gt, + Token::Eof, + ], + ) +} diff --git a/src/luax/tests/mod.rs b/src/luax/tests/mod.rs new file mode 100644 index 0000000..f2fed46 --- /dev/null +++ b/src/luax/tests/mod.rs @@ -0,0 +1,2 @@ +mod lexer; +mod preprocessor; diff --git a/src/luax/tests/preprocessor.rs b/src/luax/tests/preprocessor.rs new file mode 100644 index 0000000..d5c2f42 --- /dev/null +++ b/src/luax/tests/preprocessor.rs @@ -0,0 +1,198 @@ +use crate::luax::{lexer::Lexer, tokens::Token, *}; +use color_eyre::Result; + +fn tokenize(input: &str) -> Result<Vec<Token>> { + let mut lexer = Lexer::new(input); + let mut tokens = Vec::new(); + + while let Some(token) = lexer.next_token()? { + tokens.push(token); + } + + Ok(tokens) +} + +fn compare_output(input: &str, expected: &str) -> Result<()> { + let output = preprocess(input)?; + + // collect the tokens from each string + let expected_tokens = tokenize(expected)?; + let output_tokens = tokenize(&output)?; + + if !expected_tokens + .iter() + .zip(output_tokens.iter()) + .all(|(a, b)| a == b) + { + println!("expected: {:?}", expected_tokens); + println!("output: {:?}", output_tokens); + let first_mismatch = expected_tokens + .iter() + .zip(output_tokens.iter()) + .enumerate() + .find(|(_, (a, b))| a != b) + .unwrap(); + println!( + "first mismatch: index {}: {:?} != {:?}", + first_mismatch.0, first_mismatch.1.0, first_mismatch.1.1 + ); + println!("expected: {}", expected); + println!("output: {}", output); + panic!("output did not match expected"); + } + + Ok(()) +} + +#[test] +fn empty() -> Result<()> { + compare_output("", "") +} + +#[test] +fn no_preprocessor() -> Result<()> { + compare_output("hello", "hello") +} + +#[test] +fn lua_function() -> Result<()> { + compare_output("function hello() end", "function hello ( ) end") +} + +#[test] +fn lua_function_with_args() -> Result<()> { + compare_output( + "function hello(a, b, c) end", + "function hello ( a , b , c ) end", + ) +} + +#[test] +fn variable() -> Result<()> { + compare_output( + "local hello = 123 hello = 456", + "local hello = 123 hello = 456", + ) +} + +#[test] +fn call() -> Result<()> { + compare_output("hello()", "hello ( )") +} + +#[test] +fn call_with_args() -> Result<()> { + compare_output("hello(1, 2, 3)", "hello ( 1 , 2 , 3 )") +} + +#[test] +fn call_with_args_and_assign() -> Result<()> { + compare_output("local a = hello(1, 2, 3)", "local a = hello ( 1 , 2 , 3 )") +} + +#[test] +fn call_with_string_arg() -> Result<()> { + compare_output("hello \"world\"", "hello \"world\"") +} + +#[test] +fn call_with_table_arg() -> Result<()> { + compare_output("hello {1, 2, 3}", "hello { 1 , 2 , 3 }") +} + +#[test] +fn long_call_and_access() -> Result<()> { + compare_output("a.b.c()[1].d()().e", "a . b . c ( ) [ 1 ] . d ( ) ( ) . e") +} + +#[test] +fn simple_html() -> Result<()> { + compare_output( + "return <div></div>", + "return { tag=\"div\", attrs={}, children={} }", + ) +} + +#[test] +fn html_with_text() -> Result<()> { + compare_output( + "return <div>hello</div>", + "return { tag=\"div\", attrs={}, children={ \"hello\",} }", + ) +} + +#[test] +fn html_with_weird_text() -> Result<()> { + compare_output( + "return <div>hello #world!</div>", + "return { tag=\"div\", attrs={}, children={ \"hello #world!\",} }", + ) +} + +#[test] +fn html_with_attrs() -> Result<()> { + compare_output( + "return <div class=\"hello\" id=\"world\"></div>", + "return { tag=\"div\", attrs={class=\"hello\", id=\"world\", }, children={} }", + ) +} + +#[test] +fn nested_html() -> Result<()> { + compare_output( + "return <div><span></span></div>", + "return { tag=\"div\", attrs={}, children={ { tag=\"span\", attrs={}, children={} },} }", + ) +} + +#[test] +fn nested_html_with_text() -> Result<()> { + compare_output( + "return <div><span>hello</span></div>", + "return { tag=\"div\", attrs={}, children={ { tag=\"span\", attrs={}, children={ \"hello\",} },} }", + ) +} + +#[test] +fn nested_html_with_attrs() -> Result<()> { + compare_output( + "return <div><span class=\"hello\" id=\"world\"></span></div>", + "return { tag=\"div\", attrs={}, children={ { tag=\"span\", attrs={class=\"hello\", id=\"world\", }, children={} },} }", + ) +} + +#[test] +fn self_closing_tag() -> Result<()> { + compare_output( + "return <div><span /><span /></div>", + "return { tag=\"div\", attrs={}, children={ { tag=\"span\", attrs={}, children={} }, { tag=\"span\", attrs={}, children={} },} }", + ) +} + +#[test] +fn site() -> Result<()> { + compare_output( + r#" + return <html> + <head> + <title>My Site</title> + </head> + <body> + <h1>My Site</h1> + <p>My site is the best site.</p> + </body> + </html> + "#, + r#" + return { tag="html", attrs={}, children={ + { tag="head", attrs={}, children={ + { tag="title", attrs={}, children={ "My Site",} }, + } }, + { tag="body", attrs={}, children={ + { tag="h1", attrs={}, children={ "My Site",} }, + { tag="p", attrs={}, children={ "My site is the best site.",} }, + } }, + } } + "#, + ) +} |
