Adds integration tests that test whether a substring of a script can panic.

This commit is contained in:
Deukhoofd 2022-04-07 20:18:08 +02:00
parent b1d516b268
commit 69b5d76a9b
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
7 changed files with 124 additions and 10 deletions

View File

@ -8,6 +8,9 @@ use crate::parsing::parser::parse;
use crate::parsing::parser::parsed_statement::ParsedStatement; use crate::parsing::parser::parsed_statement::ParsedStatement;
use crate::span::Span; use crate::span::Span;
fn ignore_error(_msg: Message, _: Span) {
}
fn panic_on_error(msg: Message, _: Span) { fn panic_on_error(msg: Message, _: Span) {
std::panic::panic_any(msg.stringify()); std::panic::panic_any(msg.stringify());
} }
@ -350,4 +353,18 @@ fn integration_add_function() {
} }
}"#).unwrap(); }"#).unwrap();
assert_eq!(parsed_tree, expected_tree); assert_eq!(parsed_tree, expected_tree);
} }
// A substring of a script should never panic, even though it might be completely invalid.
#[test]
fn integration_add_function_substring() {
let mut script = "int add(int a, int b) {
return a + b;
}".to_string();
for _ in 0..script.len() {
script.pop();
let lexed_tokens = lex(script.as_str(), &mut ignore_error);
let _parsed_tree = parse(lexed_tokens, &mut ignore_error);
}
}

View File

@ -8,6 +8,14 @@ fn main() {
let mod_file_path = Path::new("src/integration_tests/mod.rs"); let mod_file_path = Path::new("src/integration_tests/mod.rs");
let mut mod_file = File::create(mod_file_path).unwrap(); let mut mod_file = File::create(mod_file_path).unwrap();
write!(
mod_file,
r#"////////////////////////////
// Automatically Generated//
////////////////////////////"#
)
.unwrap();
for path_opt in paths { for path_opt in paths {
if let Err(..) = path_opt { if let Err(..) = path_opt {
continue; continue;
@ -45,6 +53,9 @@ use crate::parsing::parser::parse;
use crate::parsing::parser::parsed_statement::ParsedStatement; use crate::parsing::parser::parsed_statement::ParsedStatement;
use crate::span::Span; use crate::span::Span;
fn ignore_error(_msg: Message, _: Span) {{
}}
fn panic_on_error(msg: Message, _: Span) {{ fn panic_on_error(msg: Message, _: Span) {{
std::panic::panic_any(msg.stringify()); std::panic::panic_any(msg.stringify());
}}"# }}"#
@ -104,5 +115,25 @@ fn integration_{name}() {{
} }
write!(testfile, "}}").unwrap(); write!(testfile, "}}").unwrap();
write!(
testfile,
r##"
// A substring of a script should never panic, even though it might be completely invalid.
#[test]
fn integration_{name}_substring() {{
let mut script = "{script}".to_string();
for _ in 0..script.len() {{
script.pop();
let lexed_tokens = lex(script.as_str(), &mut ignore_error);
let _parsed_tree = parse(lexed_tokens, &mut ignore_error);
}}
}}
"##,
name = test_name,
script = script
)
.unwrap();
} }
} }

View File

@ -8,6 +8,9 @@ use crate::parsing::parser::parse;
use crate::parsing::parser::parsed_statement::ParsedStatement; use crate::parsing::parser::parsed_statement::ParsedStatement;
use crate::span::Span; use crate::span::Span;
fn ignore_error(_msg: Message, _: Span) {
}
fn panic_on_error(msg: Message, _: Span) { fn panic_on_error(msg: Message, _: Span) {
std::panic::panic_any(msg.stringify()); std::panic::panic_any(msg.stringify());
} }
@ -90,4 +93,16 @@ fn integration_empty_class_declaration() {
} }
}"#).unwrap(); }"#).unwrap();
assert_eq!(parsed_tree, expected_tree); assert_eq!(parsed_tree, expected_tree);
} }
// A substring of a script should never panic, even though it might be completely invalid.
#[test]
fn integration_empty_class_declaration_substring() {
let mut script = "class Foo {}".to_string();
for _ in 0..script.len() {
script.pop();
let lexed_tokens = lex(script.as_str(), &mut ignore_error);
let _parsed_tree = parse(lexed_tokens, &mut ignore_error);
}
}

View File

@ -8,6 +8,9 @@ use crate::parsing::parser::parse;
use crate::parsing::parser::parsed_statement::ParsedStatement; use crate::parsing::parser::parsed_statement::ParsedStatement;
use crate::span::Span; use crate::span::Span;
fn ignore_error(_msg: Message, _: Span) {
}
fn panic_on_error(msg: Message, _: Span) { fn panic_on_error(msg: Message, _: Span) {
std::panic::panic_any(msg.stringify()); std::panic::panic_any(msg.stringify());
} }
@ -436,4 +439,22 @@ fn integration_enum_definition() {
} }
}"#).unwrap(); }"#).unwrap();
assert_eq!(parsed_tree, expected_tree); assert_eq!(parsed_tree, expected_tree);
} }
// A substring of a script should never panic, even though it might be completely invalid.
#[test]
fn integration_enum_definition_substring() {
let mut script = "enum TestEnum : uint8 {
a,
b,
c,
d = 128,
e
}".to_string();
for _ in 0..script.len() {
script.pop();
let lexed_tokens = lex(script.as_str(), &mut ignore_error);
let _parsed_tree = parse(lexed_tokens, &mut ignore_error);
}
}

View File

@ -1,4 +1,6 @@
mod enum_definition; ////////////////////////////
// Automatically Generated//
////////////////////////////mod enum_definition;
mod multiple_inheritance_class; mod multiple_inheritance_class;
mod empty_class_declaration; mod empty_class_declaration;
mod add_function; mod add_function;

View File

@ -8,6 +8,9 @@ use crate::parsing::parser::parse;
use crate::parsing::parser::parsed_statement::ParsedStatement; use crate::parsing::parser::parsed_statement::ParsedStatement;
use crate::span::Span; use crate::span::Span;
fn ignore_error(_msg: Message, _: Span) {
}
fn panic_on_error(msg: Message, _: Span) { fn panic_on_error(msg: Message, _: Span) {
std::panic::panic_any(msg.stringify()); std::panic::panic_any(msg.stringify());
} }
@ -170,4 +173,16 @@ fn integration_multiple_inheritance_class() {
} }
}"#).unwrap(); }"#).unwrap();
assert_eq!(parsed_tree, expected_tree); assert_eq!(parsed_tree, expected_tree);
} }
// A substring of a script should never panic, even though it might be completely invalid.
#[test]
fn integration_multiple_inheritance_class_substring() {
let mut script = "class Foo : Zom, Aar, Bar {}".to_string();
for _ in 0..script.len() {
script.pop();
let lexed_tokens = lex(script.as_str(), &mut ignore_error);
let _parsed_tree = parse(lexed_tokens, &mut ignore_error);
}
}

View File

@ -619,6 +619,10 @@ fn parse_class(
} }
reader.consume(TokenType::CloseCurlyBracket, log); reader.consume(TokenType::CloseCurlyBracket, log);
if name.is_none() {
return Some(Box::new(ParsedStatement::Invalid));
}
Some(Box::new(ParsedStatement::ClassDeclaration { Some(Box::new(ParsedStatement::ClassDeclaration {
modifiers, modifiers,
name: name.unwrap(), name: name.unwrap(),
@ -670,6 +674,10 @@ fn parse_funcdef(
outer_reader.set_from_inner(&reader); outer_reader.set_from_inner(&reader);
if identifier.is_none() || param_list.is_none() {
Some(Box::new(ParsedStatement::Invalid));
}
Some(Box::new(ParsedStatement::FuncDefDeclaration { Some(Box::new(ParsedStatement::FuncDefDeclaration {
modifiers, modifiers,
returns_reference, returns_reference,
@ -894,7 +902,10 @@ fn parse_paramlist(
break; break;
} }
let param_type = parse_type(reader, log); let param_type = parse_type(reader, log);
// FIXME: Deal with empty param_type if param_type.is_none() {
// FIXME: Add logging
break;
}
let type_mod = parse_typemod(reader, log); let type_mod = parse_typemod(reader, log);
let identifier = parse_identifier(reader, log, true); let identifier = parse_identifier(reader, log, true);
let mut default = None; let mut default = None;
@ -1329,9 +1340,8 @@ fn parse_expr(
if let Some(..) = binary_operand { if let Some(..) = binary_operand {
let expr_term2 = parse_exprterm(reader, log); let expr_term2 = parse_exprterm(reader, log);
if expr_term2.is_none() { if expr_term2.is_none() {
unimplemented!() return Some(Box::new(ParsedStatement::Invalid));
} }
// FIXME: deal with empty expr_term2
return Some(Box::new(ParsedStatement::BinaryExpr { return Some(Box::new(ParsedStatement::BinaryExpr {
left: expr_term.unwrap(), left: expr_term.unwrap(),
operator: binary_operand.unwrap(), operator: binary_operand.unwrap(),
@ -1556,10 +1566,13 @@ fn parse_exprvalue(
} }
fn parse_lambda( fn parse_lambda(
_outer_reader: &mut ParseReader, reader: &mut ParseReader,
_log: &mut dyn FnMut(Message, Span), log: &mut dyn FnMut(Message, Span),
) -> Option<Box<ParsedStatement>> { ) -> Option<Box<ParsedStatement>> {
// lambda ::= 'function' '(' [[type typemod] identifier {',' [type typemod] identifier}] ')' statblock; // lambda ::= 'function' '(' [[type typemod] identifier {',' [type typemod] identifier}] ')' statblock;
if reader.peek().token_type != TokenType::FunctionKeyword {
return None;
}
unimplemented!(); unimplemented!();
} }