Merge pull request #7 from elferherrera/tests

Tests for lex and lite parser
This commit is contained in:
JT
2021-08-31 12:07:46 +12:00
committed by GitHub
8 changed files with 1072 additions and 256 deletions

View File

@ -307,41 +307,4 @@ pub fn lex(
}
}
(output, error)
}
#[cfg(test)]
mod lex_tests {
use super::*;
#[test]
fn lex_basic() {
let file = b"let x = 4";
let output = lex(file, 0, &[], &[]);
assert!(output.1.is_none());
}
#[test]
fn lex_newline() {
let file = b"let x = 300\nlet y = 500;";
let output = lex(file, 0, &[], &[]);
println!("{:#?}", output.0);
assert!(output.0.contains(&Token {
contents: TokenContents::Eol,
span: Span { start: 11, end: 12 }
}));
}
#[test]
fn lex_empty() {
let file = b"";
let output = lex(file, 0, &[], &[]);
assert!(output.0.is_empty());
assert!(output.1.is_none());
}
}
}

View File

@ -80,13 +80,11 @@ impl LiteBlock {
}
pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) {
let mut curr_token = 0;
let mut block = LiteBlock::new();
let mut curr_pipeline = LiteStatement::new();
let mut curr_command = LiteCommand::new();
while let Some(token) = tokens.get(curr_token) {
for token in tokens.iter() {
match &token.contents {
TokenContents::Item => curr_command.push(token.span),
TokenContents::Pipe => {
@ -110,8 +108,8 @@ pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) {
curr_command.comments.push(token.span);
}
}
curr_token += 1;
}
if !curr_command.is_empty() {
curr_pipeline.push(curr_command);
}
@ -122,82 +120,3 @@ pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) {
(block, None)
}
#[cfg(test)]
mod tests {
use crate::{lex, lite_parse, LiteBlock, ParseError, Span};
fn lite_parse_helper(input: &[u8]) -> Result<LiteBlock, ParseError> {
let (output, err) = lex(input, 0, &[], &[]);
if let Some(err) = err {
return Err(err);
}
let (output, err) = lite_parse(&output);
if let Some(err) = err {
return Err(err);
}
Ok(output)
}
#[test]
fn comment_before() -> Result<(), ParseError> {
let input = b"# this is a comment\ndef foo bar";
let lite_block = lite_parse_helper(input)?;
assert_eq!(lite_block.block.len(), 1);
assert_eq!(lite_block.block[0].commands.len(), 1);
assert_eq!(lite_block.block[0].commands[0].comments.len(), 1);
assert_eq!(lite_block.block[0].commands[0].parts.len(), 3);
Ok(())
}
#[test]
fn comment_beside() -> Result<(), ParseError> {
let input = b"def foo bar # this is a comment";
let lite_block = lite_parse_helper(input)?;
assert_eq!(lite_block.block.len(), 1);
assert_eq!(lite_block.block[0].commands.len(), 1);
assert_eq!(lite_block.block[0].commands[0].comments.len(), 1);
assert_eq!(lite_block.block[0].commands[0].parts.len(), 3);
Ok(())
}
#[test]
fn comments_stack() -> Result<(), ParseError> {
let input = b"# this is a comment\n# another comment\ndef foo bar ";
let lite_block = lite_parse_helper(input)?;
assert_eq!(lite_block.block.len(), 1);
assert_eq!(lite_block.block[0].commands.len(), 1);
assert_eq!(lite_block.block[0].commands[0].comments.len(), 2);
assert_eq!(lite_block.block[0].commands[0].parts.len(), 3);
Ok(())
}
#[test]
fn separated_comments_dont_stack() -> Result<(), ParseError> {
let input = b"# this is a comment\n\n# another comment\ndef foo bar ";
let lite_block = lite_parse_helper(input)?;
assert_eq!(lite_block.block.len(), 1);
assert_eq!(lite_block.block[0].commands.len(), 1);
assert_eq!(lite_block.block[0].commands[0].comments.len(), 1);
assert_eq!(
lite_block.block[0].commands[0].comments[0],
Span { start: 21, end: 39 }
);
assert_eq!(lite_block.block[0].commands[0].parts.len(), 3);
Ok(())
}
}

View File

@ -1959,7 +1959,7 @@ impl<'a> ParserWorkingSet<'a> {
error = error.or(err);
// Check to see if we have parameters
let params = if matches!(
let _params = if matches!(
output.first(),
Some(Token {
contents: TokenContents::Pipe,
@ -2604,137 +2604,3 @@ impl<'a> ParserWorkingSet<'a> {
(output, error)
}
}
#[cfg(test)]
mod tests {
use crate::{ParseError, ParserState, Signature};
use super::*;
#[test]
pub fn parse_int() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let (block, err) = working_set.parse_source(b"3", true);
assert!(err.is_none());
assert!(block.len() == 1);
assert!(matches!(
block[0],
Statement::Expression(Expression {
expr: Expr::Int(3),
..
})
));
}
#[test]
pub fn parse_call() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'));
working_set.add_decl(sig.into());
let (block, err) = working_set.parse_source(b"foo", true);
assert!(err.is_none());
assert!(block.len() == 1);
match &block[0] {
Statement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
assert_eq!(call.decl_id, 0);
}
_ => panic!("not a call"),
}
}
#[test]
pub fn parse_call_missing_flag_arg() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'));
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo --jazz", true);
assert!(matches!(err, Some(ParseError::MissingFlagParam(..))));
}
#[test]
pub fn parse_call_missing_short_flag_arg() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'));
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo -j", true);
assert!(matches!(err, Some(ParseError::MissingFlagParam(..))));
}
#[test]
pub fn parse_call_too_many_shortflag_args() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo")
.named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'))
.named("--math", SyntaxShape::Int, "math!!", Some('m'));
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo -mj", true);
assert!(matches!(
err,
Some(ParseError::ShortFlagBatchCantTakeArg(..))
));
}
#[test]
pub fn parse_call_unknown_shorthand() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo").switch("--jazz", "jazz!!", Some('j'));
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo -mj", true);
assert!(matches!(err, Some(ParseError::UnknownFlag(..))));
}
#[test]
pub fn parse_call_extra_positional() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo").switch("--jazz", "jazz!!", Some('j'));
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo -j 100", true);
assert!(matches!(err, Some(ParseError::ExtraPositional(..))));
}
#[test]
pub fn parse_call_missing_req_positional() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo").required("jazz", SyntaxShape::Int, "jazz!!");
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo", true);
assert!(matches!(err, Some(ParseError::MissingPositional(..))));
}
#[test]
pub fn parse_call_missing_req_flag() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig =
Signature::build("foo").required_named("--jazz", SyntaxShape::Int, "jazz!!", None);
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo", true);
assert!(matches!(err, Some(ParseError::MissingRequiredFlag(..))));
}
}

View File

@ -0,0 +1,93 @@
use nu_parser::{lex, ParseError, Span, Token, TokenContents};
#[test]
fn lex_basic() {
let file = b"let x = 4";
let output = lex(file, 0, &[], &[]);
assert!(output.1.is_none());
}
#[test]
fn lex_newline() {
let file = b"let x = 300\nlet y = 500;";
let output = lex(file, 0, &[], &[]);
assert!(output.0.contains(&Token {
contents: TokenContents::Eol,
span: Span { start: 11, end: 12 }
}));
}
#[test]
fn lex_empty() {
let file = b"";
let output = lex(file, 0, &[], &[]);
assert!(output.0.is_empty());
assert!(output.1.is_none());
}
#[test]
fn lex_parenthesis() {
// The whole parenthesis is an item for the lexer
let file = b"let x = (300 + (322 * 444));";
let output = lex(file, 0, &[], &[]);
assert_eq!(
output.0.get(3).unwrap(),
&Token {
contents: TokenContents::Item,
span: Span { start: 8, end: 27 }
}
);
}
#[test]
fn lex_comment() {
let file = b"let x = 300 # a comment \n $x + 444";
let output = lex(file, 0, &[], &[]);
assert_eq!(
output.0.get(4).unwrap(),
&Token {
contents: TokenContents::Comment,
span: Span { start: 12, end: 25 }
}
);
}
#[test]
fn lex_is_incomplete() {
let file = b"let x = 300 | ;";
let output = lex(file, 0, &[], &[]);
let err = output.1.unwrap();
assert!(matches!(err, ParseError::ExtraTokens(_)));
}
#[test]
fn lex_incomplete_paren() {
let file = b"let x = (300 + ( 4 + 1)";
let output = lex(file, 0, &[], &[]);
let err = output.1.unwrap();
assert!(matches!(err, ParseError::UnexpectedEof(v, _) if v == ")"));
}
#[test]
fn lex_incomplete_quote() {
let file = b"let x = '300 + 4 + 1";
let output = lex(file, 0, &[], &[]);
let err = output.1.unwrap();
assert!(matches!(err, ParseError::UnexpectedEof(v, _) if v == "'"));
}

View File

@ -0,0 +1,125 @@
use nu_parser::{lex, lite_parse, LiteBlock, ParseError, Span};
fn lite_parse_helper(input: &[u8]) -> Result<LiteBlock, ParseError> {
let (output, err) = lex(input, 0, &[], &[]);
if let Some(err) = err {
return Err(err);
}
let (output, err) = lite_parse(&output);
if let Some(err) = err {
return Err(err);
}
Ok(output)
}
#[test]
fn comment_before() -> Result<(), ParseError> {
let input = b"# this is a comment\ndef foo bar";
let lite_block = lite_parse_helper(input)?;
assert_eq!(lite_block.block.len(), 1);
assert_eq!(lite_block.block[0].commands.len(), 1);
assert_eq!(lite_block.block[0].commands[0].comments.len(), 1);
assert_eq!(lite_block.block[0].commands[0].parts.len(), 3);
Ok(())
}
#[test]
fn comment_beside() -> Result<(), ParseError> {
let input = b"def foo bar # this is a comment";
let lite_block = lite_parse_helper(input)?;
assert_eq!(lite_block.block.len(), 1);
assert_eq!(lite_block.block[0].commands.len(), 1);
assert_eq!(lite_block.block[0].commands[0].comments.len(), 1);
assert_eq!(lite_block.block[0].commands[0].parts.len(), 3);
Ok(())
}
#[test]
fn comments_stack() -> Result<(), ParseError> {
let input = b"# this is a comment\n# another comment\ndef foo bar ";
let lite_block = lite_parse_helper(input)?;
assert_eq!(lite_block.block.len(), 1);
assert_eq!(lite_block.block[0].commands.len(), 1);
assert_eq!(lite_block.block[0].commands[0].comments.len(), 2);
assert_eq!(lite_block.block[0].commands[0].parts.len(), 3);
Ok(())
}
#[test]
fn separated_comments_dont_stack() -> Result<(), ParseError> {
let input = b"# this is a comment\n\n# another comment\ndef foo bar ";
let lite_block = lite_parse_helper(input)?;
assert_eq!(lite_block.block.len(), 1);
assert_eq!(lite_block.block[0].commands.len(), 1);
assert_eq!(lite_block.block[0].commands[0].comments.len(), 1);
assert_eq!(
lite_block.block[0].commands[0].comments[0],
Span { start: 21, end: 39 }
);
assert_eq!(lite_block.block[0].commands[0].parts.len(), 3);
Ok(())
}
#[test]
fn multiple_statements() -> Result<(), ParseError> {
// Code :
// # A comment
// let a = ( 3 + (
// 4 +
// 5 ))
// let b = 1 # comment
let input = b"# comment \n let a = ( 3 + (\n 4 + \n 5 )) \n let b = 1 # comment";
let lite_block = lite_parse_helper(input)?;
assert_eq!(lite_block.block.len(), 2);
assert_eq!(lite_block.block[0].commands.len(), 1);
assert_eq!(
lite_block.block[0].commands[0].comments[0],
Span { start: 0, end: 11 }
);
assert_eq!(lite_block.block[1].commands.len(), 1);
assert_eq!(
lite_block.block[1].commands[0].comments[0],
Span { start: 52, end: 61 }
);
Ok(())
}
#[test]
fn multiple_commands() -> Result<(), ParseError> {
// Pipes add commands to the lite parser
// Code :
// let a = ls | where name == 1
// let b = 1 # comment
let input = b"let a = ls | where name == 1 \n let b = 1 # comment";
let lite_block = lite_parse_helper(input)?;
assert_eq!(lite_block.block.len(), 2);
assert_eq!(lite_block.block[0].commands.len(), 2);
assert_eq!(lite_block.block[1].commands.len(), 1);
assert_eq!(
lite_block.block[1].commands[0].comments[0],
Span { start: 41, end: 50 }
);
Ok(())
}

View File

@ -0,0 +1,128 @@
use nu_parser::*;
use nu_parser::{ParseError, ParserState, Signature};
#[test]
pub fn parse_int() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let (block, err) = working_set.parse_source(b"3", true);
assert!(err.is_none());
assert!(block.len() == 1);
assert!(matches!(
block[0],
Statement::Expression(Expression {
expr: Expr::Int(3),
..
})
));
}
#[test]
pub fn parse_call() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'));
working_set.add_decl(sig.into());
let (block, err) = working_set.parse_source(b"foo", true);
assert!(err.is_none());
assert!(block.len() == 1);
match &block[0] {
Statement::Expression(Expression {
expr: Expr::Call(call),
..
}) => {
assert_eq!(call.decl_id, 0);
}
_ => panic!("not a call"),
}
}
#[test]
pub fn parse_call_missing_flag_arg() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'));
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo --jazz", true);
assert!(matches!(err, Some(ParseError::MissingFlagParam(..))));
}
#[test]
pub fn parse_call_missing_short_flag_arg() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'));
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo -j", true);
assert!(matches!(err, Some(ParseError::MissingFlagParam(..))));
}
#[test]
pub fn parse_call_too_many_shortflag_args() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo")
.named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'))
.named("--math", SyntaxShape::Int, "math!!", Some('m'));
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo -mj", true);
assert!(matches!(
err,
Some(ParseError::ShortFlagBatchCantTakeArg(..))
));
}
#[test]
pub fn parse_call_unknown_shorthand() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo").switch("--jazz", "jazz!!", Some('j'));
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo -mj", true);
assert!(matches!(err, Some(ParseError::UnknownFlag(..))));
}
#[test]
pub fn parse_call_extra_positional() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo").switch("--jazz", "jazz!!", Some('j'));
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo -j 100", true);
assert!(matches!(err, Some(ParseError::ExtraPositional(..))));
}
#[test]
pub fn parse_call_missing_req_positional() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo").required("jazz", SyntaxShape::Int, "jazz!!");
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo", true);
assert!(matches!(err, Some(ParseError::MissingPositional(..))));
}
#[test]
pub fn parse_call_missing_req_flag() {
let parser_state = ParserState::new();
let mut working_set = ParserWorkingSet::new(&parser_state);
let sig = Signature::build("foo").required_named("--jazz", SyntaxShape::Int, "jazz!!", None);
working_set.add_decl(sig.into());
let (_, err) = working_set.parse_source(b"foo", true);
assert!(matches!(err, Some(ParseError::MissingRequiredFlag(..))));
}