summaryrefslogtreecommitdiff
path: root/src/syntax/test.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-02-07 22:29:16 +0100
committerLaurenz <laurmaedje@gmail.com>2020-02-07 22:29:16 +0100
commit4e8359385f73e549a563fd356b6858050464991d (patch)
treeb613f3032e623f739b22b24ebf62704f5896ae36 /src/syntax/test.rs
parent02dc29d18a7b67edf0eaa5d125be22eec6cfebb7 (diff)
Improve syntax testing framework ♻
... and finally expand a few escape sequences in strings.
Diffstat (limited to 'src/syntax/test.rs')
-rw-r--r--src/syntax/test.rs86
1 files changed, 80 insertions, 6 deletions
diff --git a/src/syntax/test.rs b/src/syntax/test.rs
index df354768..6c89b4f5 100644
--- a/src/syntax/test.rs
+++ b/src/syntax/test.rs
@@ -1,8 +1,62 @@
+use std::fmt::Debug;
+
use super::func::FuncHeader;
use super::expr::{Expr, Tuple, Object};
+use super::span::{Span, Spanned};
+use super::tokens::Token;
use super::*;
+/// Check whether the expected and found results for the given source code
+/// match by the comparison function, and print them out otherwise.
+pub fn check<T>(src: &str, exp: T, found: T, spans: bool)
+where T: Debug + PartialEq + SpanlessEq {
+ let cmp = if spans { PartialEq::eq } else { SpanlessEq::spanless_eq };
+ if !cmp(&exp, &found) {
+ println!("source: {:?}", src);
+ println!("expected: {:#?}", exp);
+ println!("found: {:#?}", found);
+ panic!("test failed");
+ }
+}
+
+/// Create a vector of optionally spanned expressions from a list description.
+///
+/// # Examples
+/// When you want to add span information to the items, the format is as
+/// follows.
+/// ```
+/// spanned![(0:0, 0:5, "hello"), (0:5, 0:3, "world")]
+/// ```
+/// The span information can simply be omitted to create a vector with items
+/// that are spanned with dummy zero spans.
+macro_rules! spanned {
+ (item ($sl:tt:$sc:tt, $el:tt:$ec:tt, $v:expr)) => ({
+ #[allow(unused_imports)]
+ use $crate::syntax::span::{Position, Span, Spanned};
+ Spanned {
+ span: Span::new(
+ Position::new($sl, $sc),
+ Position::new($el, $ec)
+ ),
+ v: $v
+ }
+ });
+
+ (vec $(($sl:tt:$sc:tt, $el:tt:$ec:tt, $v:expr)),* $(,)?) => {
+ (vec![$(spanned![item ($sl:$sc, $el:$ec, $v)]),*], true)
+ };
+
+ (vec $($v:expr),* $(,)?) => {
+ (vec![$($crate::syntax::test::zspan($v)),*], false)
+ };
+}
+
+/// Span an element with a zero span.
+pub fn zspan<T>(v: T) -> Spanned<T> {
+ Spanned { v, span: Span::ZERO }
+}
+
function! {
/// Most functions in the tests are parsed into the debug function for easy
/// inspection of arguments and body.
@@ -30,26 +84,31 @@ pub trait SpanlessEq<Rhs=Self> {
fn spanless_eq(&self, other: &Rhs) -> bool;
}
-impl SpanlessEq for Vec<Spanned<Token<'_>>> {
- fn spanless_eq(&self, other: &Vec<Spanned<Token>>) -> bool {
+impl<T: SpanlessEq> SpanlessEq for Vec<Spanned<T>> {
+ fn spanless_eq(&self, other: &Vec<Spanned<T>>) -> bool {
self.len() == other.len()
- && self.iter().zip(other).all(|(x, y)| x.v == y.v)
+ && self.iter().zip(other).all(|(x, y)| x.v.spanless_eq(&y.v))
}
}
impl SpanlessEq for SyntaxModel {
fn spanless_eq(&self, other: &SyntaxModel) -> bool {
+ self.nodes.spanless_eq(&other.nodes)
+ }
+}
+
+impl SpanlessEq for Node {
+ fn spanless_eq(&self, other: &Node) -> bool {
fn downcast<'a>(func: &'a (dyn Model + 'static)) -> &'a DebugFn {
func.downcast::<DebugFn>().expect("not a debug fn")
}
- self.nodes.len() == other.nodes.len()
- && self.nodes.iter().zip(&other.nodes).all(|(x, y)| match (&x.v, &y.v) {
+ match (self, other) {
(Node::Model(a), Node::Model(b)) => {
downcast(a.as_ref()).spanless_eq(downcast(b.as_ref()))
}
(a, b) => a == b,
- })
+ }
}
}
@@ -86,3 +145,18 @@ impl SpanlessEq for Object {
.all(|(x, y)| x.key.v == y.key.v && x.value.v.spanless_eq(&y.value.v))
}
}
+
+/// Implement `SpanlessEq` by just forwarding to `PartialEq`.
+macro_rules! forward {
+ ($type:ty) => {
+ impl SpanlessEq for $type {
+ fn spanless_eq(&self, other: &$type) -> bool {
+ self == other
+ }
+ }
+ };
+}
+
+forward!(String);
+forward!(Token<'_>);
+forward!(Decoration);