Skip to content

Commit

Permalink
fix PLC-lang#190: refactor parser tests into separate modules
Browse files Browse the repository at this point in the history
  • Loading branch information
ulmer-a committed Jul 16, 2021
1 parent 9cf46dd commit deba0a2
Show file tree
Hide file tree
Showing 12 changed files with 1,568 additions and 1,529 deletions.
5 changes: 4 additions & 1 deletion src/parser/tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder
mod control_parser_tests;
mod expressions_parser_tests;
mod parser_tests;
mod container_parse_tests;
mod parse_errors;
mod statement_parse_tests;
mod misc_parser_tests;

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

#[test]
fn action_container_parsed() {
let lexer = super::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 single_action_parsed() {
let lexer = super::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 = super::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");
}

#[test]
fn mixed_action_types_parsed() {
let lexer = super::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 two_action_containers_parsed() {
let lexer = super::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 actions_with_no_container_error() {
let lexer = super::lex("ACTIONS ACTION bar END_ACTION ACTION buz END_ACTION END_ACTIONS");
let err = parse(lexer).expect_err("Expecting parser failure");
assert_eq!(
err,
"expected Identifier, but found 'ACTION' [KeywordAction] at line: 1 offset: 8..14"
.to_string()
);
}

#[test]
fn a_program_needs_to_end_with_end_program() {
let lexer = super::lex("PROGRAM buz ");
let result = parse(lexer);
assert_eq!(
result,
Err(
"unexpected termination of body by '' [End], a block at line 1 was not closed"
.to_string()
)
);
}

#[test]
fn a_variable_declaration_block_needs_to_end_with_endvar() {
let lexer = super::lex("PROGRAM buz VAR END_PROGRAM ");
let result = parse(lexer);
assert_eq!(
result,
Err("expected KeywordEndVar, but found 'END_PROGRAM' [KeywordEndProgram] at line: 1 offset: 16..27".to_string())
);
}
77 changes: 77 additions & 0 deletions src/parser/tests/misc_parser_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder
use crate::ast::*;
use crate::{lexer, parser::parse};
use pretty_assertions::*;

#[test]
fn empty_returns_empty_compilation_unit() {
let (result, _) = parse(super::lex("")).unwrap();
assert_eq!(result.units.len(), 0);
}

#[test]
fn test_ast_line_locations() {
let lexer = super::lex(
"PROGRAM prg
call1();
call2();
call3();
call4();
END_PROGRAM
",
);
let (parse_result, new_lines) = parse(lexer).unwrap();
let statements = &parse_result.implementations[0].statements;

{
let statement_offset = statements.get(0).unwrap().get_location().get_start();
let line = new_lines.get_line_of(statement_offset).unwrap();
assert_eq!(2, line);
}
{
let statement_offset = statements.get(1).unwrap().get_location().get_start();
let line = new_lines.get_line_of(statement_offset).unwrap();
assert_eq!(4, line);
}
{
let statement_offset = statements.get(2).unwrap().get_location().get_start();
let line = new_lines.get_line_of(statement_offset).unwrap();
assert_eq!(5, line);
}
{
let statement_offset = statements.get(3).unwrap().get_location().get_start();
let line = new_lines.get_line_of(statement_offset).unwrap();
assert_eq!(8, line);
}
}

#[test]
fn programs_can_be_external() {
let lexer = super::lex("@EXTERNAL PROGRAM foo END_PROGRAM");
let parse_result = parse(lexer).unwrap().0;
let implementation = &parse_result.implementations[0];
assert_eq!(LinkageType::External, implementation.linkage);
}

#[test]
fn file_location_persisted() {
let lexer = lexer::lex(
"test_file.st",
"
VAR_GLOBAL
x : INT;
END_VAR
PROGRAM prg
END_PROGRAM
",
);
let (parse_result, _) = parse(lexer).unwrap();
let location = &parse_result.global_vars[0].variables[0].location;
assert_eq!("test_file.st", location.get_file_path());
let location = &parse_result.units[0].location;
assert_eq!("test_file.st", location.get_file_path());
}
6 changes: 6 additions & 0 deletions src/parser/tests/parse_errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
mod type_parse_tests;
mod variable_parse_tests;
mod program_parse_tests;
mod function_parse_tests;
mod initializer_parse_tests;
mod error_message_tests;
107 changes: 107 additions & 0 deletions src/parser/tests/parse_errors/error_message_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use crate::parser::parse;
use pretty_assertions::*;


#[test]
fn test_unexpected_token_error_message2() {
let lexer = super::super::lex(
"SOME PROGRAM prg
VAR ;
END_VAR
END_PROGRAM
",
);
let parse_result = parse(lexer);

if let Err { 0: msg } = parse_result {
assert_eq!(
"unexpected token: 'SOME' [Identifier] at line: 1 offset: 0..4",
msg
);
} else {
panic!("Expected parse error but didn't get one.");
}
}
#[test]
fn test_unexpected_type_declaration_error_message() {
let lexer = super::super::lex(
"TYPE MyType:
PROGRAM
END_PROGRAM
END_TYPE
",
);
let parse_result = parse(lexer);

if let Err { 0: msg } = parse_result {
assert_eq!("expected struct, enum, or subrange found 'PROGRAM' [KeywordProgram] at line: 2 offset: 17..24", msg);
} else {
panic!("Expected parse error but didn't get one.");
}
}

#[test]
fn test_unclosed_body_error_message() {
let lexer = super::super::lex(
"
PROGRAM My_PRG
",
);
let parse_result = parse(lexer);

if let Err { 0: msg } = parse_result {
assert_eq!(
"unexpected termination of body by '' [End], a block at line 3 was not closed",
msg
);
} else {
panic!("Expected parse error but didn't get one.");
}
}

#[test]
fn test_unexpected_token_error_message() {
let lexer = super::super::lex(
"PROGRAM prg
VAR ;
END_VAR
END_PROGRAM
",
);
let parse_result = parse(lexer);

if let Err { 0: msg } = parse_result {
assert_eq!(
"expected KeywordEndVar, but found ';' [KeywordSemicolon] at line: 2 offset: 21..22",
msg
);
} else {
panic!("Expected parse error but didn't get one.");
}
}

#[test]
fn test_case_without_condition_error_message() {
let lexer = super::super::lex(
"PROGRAM My_PRG
CASE x OF
1:
: x := 3;
END_CASE
END_PROGRAM
",
);
let parse_result = parse(lexer);

if let Err { 0: msg } = parse_result {
assert_eq!(
"unexpected ':' at line 4 - no case-condition could be found",
msg
);
} else {
panic!("Expected parse error but didn't get one.");
}
}
Loading

0 comments on commit deba0a2

Please sign in to comment.