Ensure no errors in parse tests

This commit is contained in:
Shuhei Takahashi 2025-02-04 23:41:26 +09:00
parent 876bca27e8
commit 41e47fcd5a
3 changed files with 110 additions and 74 deletions

View file

@ -16,6 +16,7 @@ use either::Either;
use pest::Span;
mod parser;
mod tests;
pub trait Node<'i> {
fn as_node(&self) -> &dyn Node<'i>;
@ -34,6 +35,10 @@ pub trait Node<'i> {
None
}
fn as_error(&self) -> Option<&ErrorStatement<'i>> {
None
}
fn identifiers<'n>(&'n self) -> FilterWalk<'i, 'n, Identifier<'i>> {
FilterWalk::new(self.as_node(), |node| node.as_identifier())
}
@ -41,6 +46,10 @@ pub trait Node<'i> {
fn strings<'n>(&'n self) -> FilterWalk<'i, 'n, StringLiteral<'i>> {
FilterWalk::new(self.as_node(), |node| node.as_string())
}
fn errors<'n>(&'n self) -> FilterWalk<'i, 'n, ErrorStatement<'i>> {
FilterWalk::new(self.as_node(), |node| node.as_error())
}
}
pub struct Walk<'i, 'n> {
@ -594,6 +603,10 @@ impl<'i> Node<'i> for ErrorStatement<'i> {
self
}
fn as_error(&self) -> Option<&ErrorStatement<'i>> {
Some(self)
}
fn children(&self) -> Vec<&dyn Node<'i>> {
match self {
ErrorStatement::UnknownStatement(unknown) => vec![unknown.as_node()],

View file

@ -352,77 +352,3 @@ pub fn parse(input: &str) -> Block {
.unwrap();
convert_file(file_pair)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn smoke() {
// Empty
parse("");
parse(" \r\n\t");
// Assignment
parse("a = 1");
parse("a += 1");
parse("a -= 1");
parse("a[1] = 1");
parse("a.b = 1");
// Conditional
parse("if (true) {}");
parse("if (true) { a = 1 }");
parse("if (true) {} else {}");
parse("if (true) { a = 1 } else { a = 2 }");
parse("if (true) {} else if (true) {}");
parse("if (true) { a = 1 } else if (true) { a = 2 }");
parse("if (true) {} else if (true) {} else {}");
parse("if (true) { a = 1 } else if (true) { a = 2 } else { a = 3 }");
// Call
parse("assert(true)");
parse("declare_args() {}");
parse("declare_args() { a = 1 }");
parse("template(\"foo\") {}");
parse("template(\"foo\") { bar(target_name) }");
// Expressions
parse("a = 1");
parse("a = b[1]");
parse("a = b.c");
parse("a = 1 + 2 * 3");
parse("a = 1 == 2");
parse("a = 1 <= 2");
parse("a = true && false || !false");
parse(r#"a = "foo\"bar\\baz""#);
parse("a = b(c)");
parse("a = b.c");
parse("a = {}");
parse("a = { b = 1 }");
parse("a = (((1)))");
parse("a = []");
parse("a = [1]");
parse("a = [1, ]");
parse("a = [1, 2]");
parse("a = [1, 2, ]");
// TODO: Add more tests.
}
#[test]
fn comments() {
parse("# comment");
parse("# comment\n # comment\n");
parse("a = 1 # comment");
}
#[test]
fn error_recovery() {
parse("a = 1 2 3");
parse("a = \"foo\nb = 1");
parse("declare_args() {}}");
// TODO: Add more tests.
}
}

97
src/ast/tests.rs Normal file
View file

@ -0,0 +1,97 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![cfg(test)]
use super::{parse, Node};
fn parse_no_errors(input: &str) {
let block = parse(input);
let errors: Vec<_> = block.errors().collect();
assert!(
errors.is_empty(),
"parse failed!\n\tinput = {:?}\n\terrors = {:?}",
input,
errors
);
}
#[test]
fn smoke() {
// Empty
parse_no_errors("");
parse_no_errors(" \r\n\t");
// Assignment
parse_no_errors("a = 1");
parse_no_errors("a += 1");
parse_no_errors("a -= 1");
parse_no_errors("a[1] = 1");
parse_no_errors("a.b = 1");
// Conditional
parse_no_errors("if (true) {}");
parse_no_errors("if (true) { a = 1 }");
parse_no_errors("if (true) {} else {}");
parse_no_errors("if (true) { a = 1 } else { a = 2 }");
parse_no_errors("if (true) {} else if (true) {}");
parse_no_errors("if (true) { a = 1 } else if (true) { a = 2 }");
parse_no_errors("if (true) {} else if (true) {} else {}");
parse_no_errors("if (true) { a = 1 } else if (true) { a = 2 } else { a = 3 }");
// Call
parse_no_errors("assert(true)");
parse_no_errors("declare_args() {}");
parse_no_errors("declare_args() { a = 1 }");
parse_no_errors("template(\"foo\") {}");
parse_no_errors("template(\"foo\") { bar(target_name) }");
// Expressions
parse_no_errors("a = 1");
parse_no_errors("a = b[1]");
parse_no_errors("a = b.c");
parse_no_errors("a = 1 + 2 - 3");
parse_no_errors("a = 1 == 2");
parse_no_errors("a = 1 <= 2");
parse_no_errors("a = true && false || !false");
parse_no_errors(r#"a = "foo\"bar\\baz""#);
parse_no_errors("a = b(c)");
parse_no_errors("a = b.c");
parse_no_errors("a = {}");
parse_no_errors("a = { b = 1 }");
parse_no_errors("a = (((1)))");
parse_no_errors("a = []");
parse_no_errors("a = [1]");
parse_no_errors("a = [1, ]");
parse_no_errors("a = [1, 2]");
parse_no_errors("a = [1, 2, ]");
// TODO: Add more tests.
}
#[test]
fn comments() {
parse_no_errors("# comment");
parse_no_errors("# comment\n # comment\n");
parse_no_errors("a = 1 # comment");
}
#[test]
fn error_recovery() {
parse("a = 1 2 3");
parse("a = \"foo\nb = 1");
parse("declare_args() {}}");
// TODO: Add more tests.
}