Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #190: refactor parser tests into separate modules #194

Merged
merged 2 commits into from
Jul 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/parser/tests.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
use crate::ast::{SourceRange, Statement};

// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder
mod container_parser_tests;
mod control_parser_tests;
mod expressions_parser_tests;
mod function_parser_tests;
mod initializer_parser_tests;
mod misc_parser_tests;
mod parse_errors;
mod parser_tests;
mod program_parser_tests;
mod statement_parser_tests;
mod type_parser_tests;
mod variable_parser_tests;

pub fn lex(source: &str) -> crate::lexer::ParseSession {
crate::lexer::lex(source)
Expand Down
108 changes: 108 additions & 0 deletions src/parser/tests/container_parser_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use crate::{
parser::{parse, tests::lex},
Diagnostic,
};
use pretty_assertions::*;

#[test]
fn action_container_parsed() {
let lexer = lex("ACTIONS foo ACTION bar END_ACTION END_ACTIONS");
let result = parse(lexer).unwrap().0;

let prg = &result.implementations[0];
assert_eq!(prg.name, "foo.bar");
assert_eq!(prg.type_name, "foo");
}

#[test]
fn two_action_containers_parsed() {
let lexer = lex("ACTIONS foo ACTION bar END_ACTION ACTION buz END_ACTION END_ACTIONS");
let result = parse(lexer).unwrap().0;

let prg = &result.implementations[0];
assert_eq!(prg.name, "foo.bar");
assert_eq!(prg.type_name, "foo");

let prg2 = &result.implementations[1];
assert_eq!(prg2.name, "foo.buz");
assert_eq!(prg2.type_name, "foo");
}

#[test]
fn mixed_action_types_parsed() {
let lexer = lex("PROGRAM foo END_PROGRAM ACTIONS foo ACTION bar END_ACTION END_ACTIONS ACTION foo.buz END_ACTION");
let result = parse(lexer).unwrap().0;

let prg = &result.implementations[1];
assert_eq!(prg.name, "foo.bar");
assert_eq!(prg.type_name, "foo");

let prg2 = &result.implementations[2];
assert_eq!(prg2.name, "foo.buz");
assert_eq!(prg2.type_name, "foo");
}

#[test]
fn actions_with_no_container_error() {
let lexer = lex("ACTIONS ACTION bar END_ACTION ACTION buz END_ACTION END_ACTIONS");
let err = parse(lexer).expect_err("Expecting parser failure");
assert_eq!(
err,
Diagnostic::unexpected_token_found("Identifier".into(), "ACTION".into(), (8..14).into())
);
}

#[test]
fn two_programs_can_be_parsed() {
let lexer = lex("PROGRAM foo END_PROGRAM PROGRAM bar END_PROGRAM");
let result = parse(lexer).unwrap().0;

let prg = &result.units[0];
assert_eq!(prg.name, "foo");
let prg2 = &result.units[1];
assert_eq!(prg2.name, "bar");
}

#[test]
fn simple_program_with_varblock_can_be_parsed() {
let lexer = lex("PROGRAM buz VAR END_VAR END_PROGRAM");
let result = parse(lexer).unwrap().0;

let prg = &result.units[0];

assert_eq!(prg.variable_blocks.len(), 1);
}

#[test]
fn simple_program_with_two_varblocks_can_be_parsed() {
let lexer = lex("PROGRAM buz VAR END_VAR VAR END_VAR END_PROGRAM");
let result = parse(lexer).unwrap().0;

let prg = &result.units[0];

assert_eq!(prg.variable_blocks.len(), 2);
}

#[test]
fn single_action_parsed() {
let lexer = lex("ACTION foo.bar END_ACTION");
let result = parse(lexer).unwrap().0;

let prg = &result.implementations[0];
assert_eq!(prg.name, "foo.bar");
assert_eq!(prg.type_name, "foo");
}

#[test]
fn two_actions_parsed() {
let lexer = lex("ACTION foo.bar END_ACTION ACTION fuz.bar END_ACTION");
let result = parse(lexer).unwrap().0;

let prg = &result.implementations[0];
assert_eq!(prg.name, "foo.bar");
assert_eq!(prg.type_name, "foo");

let prg2 = &result.implementations[1];
assert_eq!(prg2.name, "fuz.bar");
assert_eq!(prg2.type_name, "fuz");
}
155 changes: 155 additions & 0 deletions src/parser/tests/function_parser_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
use crate::{
ast::*,
parser::{parse, tests::lex},
Diagnostic,
};
use pretty_assertions::*;

#[test]
fn simple_foo_function_can_be_parsed() {
let lexer = lex("FUNCTION foo : INT END_FUNCTION");
let result = parse(lexer).unwrap().0;

let prg = &result.units[0];
assert_eq!(prg.pou_type, PouType::Function);
assert_eq!(prg.name, "foo");
assert_eq!(
prg.return_type.as_ref().unwrap(),
&DataTypeDeclaration::DataTypeReference {
referenced_type: "INT".to_string()
}
);
}

#[test]
fn simple_foo_function_block_can_be_parsed() {
let lexer = lex("FUNCTION_BLOCK foo END_FUNCTION_BLOCK");
let result = parse(lexer).unwrap().0;

let prg = &result.units[0];
assert_eq!(prg.pou_type, PouType::FunctionBlock);
assert_eq!(prg.name, "foo");
assert!(prg.return_type.is_none());
}

#[test]
fn a_function_with_varargs_can_be_parsed() {
let lexer = lex("FUNCTION foo : INT VAR_INPUT x : INT; y : ...; END_VAR END_FUNCTION");
let result = parse(lexer).unwrap().0;

let prg = &result.units[0];
let variable_block = &prg.variable_blocks[0];
let ast_string = format!("{:#?}", variable_block);
let expected_ast = r#"VariableBlock {
variables: [
Variable {
name: "x",
data_type: DataTypeReference {
referenced_type: "INT",
},
},
Variable {
name: "y",
data_type: DataTypeDefinition {
data_type: VarArgs {
referenced_type: None,
},
},
},
],
variable_block_type: Input,
}"#;
assert_eq!(ast_string, expected_ast);
}

#[test]
fn a_function_with_typed_varargs_can_be_parsed() {
let lexer = lex("FUNCTION foo : INT VAR_INPUT x : INT; y : INT...; END_VAR END_FUNCTION");
let result = parse(lexer).unwrap().0;

let prg = &result.units[0];
let variable_block = &prg.variable_blocks[0];
let ast_string = format!("{:#?}", variable_block);
let expected_ast = r#"VariableBlock {
variables: [
Variable {
name: "x",
data_type: DataTypeReference {
referenced_type: "INT",
},
},
Variable {
name: "y",
data_type: DataTypeDefinition {
data_type: VarArgs {
referenced_type: Some(
DataTypeReference {
referenced_type: "INT",
},
),
},
},
},
],
variable_block_type: Input,
}"#;
assert_eq!(ast_string, expected_ast);
}

#[test]
fn varargs_parameters_can_be_parsed() {
let lexer = lex("
FUNCTION foo : DINT
VAR_INPUT
args1 : ...;
args2 : INT...;
END_VAR
END_FUNCTION
");
let (parse_result, diagnostics) = parse(lexer).unwrap();

assert_eq!(
format!("{:#?}", diagnostics),
format!("{:#?}", Vec::<Diagnostic>::new()).as_str()
);

let x = &parse_result.units[0];
let expected = Pou {
name: "foo".into(),
pou_type: PouType::Function,
return_type: Some(DataTypeDeclaration::DataTypeReference {
referenced_type: "DINT".into(),
}),
variable_blocks: vec![VariableBlock {
variable_block_type: VariableBlockType::Input,
variables: vec![
Variable {
name: "args1".into(),
data_type: DataTypeDeclaration::DataTypeDefinition {
data_type: DataType::VarArgs {
referenced_type: None,
},
},
initializer: None,
location: SourceRange::undefined(),
},
Variable {
name: "args2".into(),
data_type: DataTypeDeclaration::DataTypeDefinition {
data_type: DataType::VarArgs {
referenced_type: Some(Box::new(
DataTypeDeclaration::DataTypeReference {
referenced_type: "INT".into(),
},
)),
},
},
initializer: None,
location: SourceRange::undefined(),
},
],
}],
location: SourceRange::undefined(),
};
assert_eq!(format!("{:#?}", expected), format!("{:#?}", x).as_str());
}
Loading