Add tests for dust parser

This commit is contained in:
Tom Alexander 2020-04-04 22:45:56 -04:00
parent bec69557fc
commit 87a7024bf0
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE

View File

@ -2,10 +2,13 @@ use nom::branch::alt;
use nom::bytes::complete::is_a; use nom::bytes::complete::is_a;
use nom::bytes::complete::tag; use nom::bytes::complete::tag;
use nom::bytes::complete::take_until; use nom::bytes::complete::take_until;
use nom::character::complete::one_of;
use nom::combinator::map; use nom::combinator::map;
use nom::combinator::opt;
use nom::combinator::recognize; use nom::combinator::recognize;
use nom::combinator::rest; use nom::combinator::rest;
use nom::combinator::value; use nom::combinator::value;
use nom::combinator::verify;
use nom::multi::many0; use nom::multi::many0;
use nom::multi::separated_list; use nom::multi::separated_list;
use nom::sequence::delimited; use nom::sequence::delimited;
@ -20,7 +23,7 @@ enum DustTag<'a> {
DTReference(Reference<'a>), DTReference(Reference<'a>),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq)]
enum Special { enum Special {
Space, Space,
NewLine, NewLine,
@ -29,23 +32,23 @@ enum Special {
RightCurlyBrace, RightCurlyBrace,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq)]
struct Comment<'a> { struct Comment<'a> {
value: &'a str, value: &'a str,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq)]
struct Path<'a> { struct Path<'a> {
keys: Vec<&'a str>, keys: Vec<&'a str>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq)]
struct Reference<'a> { struct Reference<'a> {
path: Path<'a>, path: Path<'a>,
filters: Vec<Filter>, filters: Vec<Filter>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq)]
enum Filter { enum Filter {
HtmlEncode, HtmlEncode,
DisableHtmlEncode, DisableHtmlEncode,
@ -56,6 +59,7 @@ enum Filter {
JsonParse, JsonParse,
} }
#[derive(Clone, Debug, PartialEq)]
struct Span<'a> { struct Span<'a> {
contents: &'a str, contents: &'a str,
} }
@ -81,11 +85,11 @@ fn special(i: &str) -> IResult<&str, Special> {
delimited( delimited(
tag("{~"), tag("{~"),
alt(( alt((
value(Special::LeftCurlyBrace, tag("lb")),
value(Special::RightCurlyBrace, tag("rb")),
value(Special::Space, tag("s")), value(Special::Space, tag("s")),
value(Special::NewLine, tag("s")), value(Special::NewLine, tag("n")),
value(Special::CarriageReturn, tag("s")), value(Special::CarriageReturn, tag("r")),
value(Special::LeftCurlyBrace, tag("s")),
value(Special::RightCurlyBrace, tag("s")),
)), )),
tag("}"), tag("}"),
)(i) )(i)
@ -102,8 +106,10 @@ fn path(i: &str) -> IResult<&str, Path> {
separated_list( separated_list(
tag("."), tag("."),
recognize(tuple(( recognize(tuple((
is_a("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$"), one_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$"),
is_a("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$0123456789-"), opt(is_a(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$0123456789-",
)),
))), ))),
), ),
|body| Path { keys: body }, |body| Path { keys: body },
@ -138,7 +144,7 @@ fn filter(i: &str) -> IResult<&str, Filter> {
/// Any text that is not a Dust element /// Any text that is not a Dust element
fn span(i: &str) -> IResult<&str, Span> { fn span(i: &str) -> IResult<&str, Span> {
let (remaining, body) = alt((take_until("{"), rest))(i)?; let (remaining, body) = verify(alt((take_until("{"), rest)), |s: &str| s.len() > 0)(i)?;
Ok((remaining, Span { contents: body })) Ok((remaining, Span { contents: body }))
} }
@ -154,3 +160,106 @@ pub fn template(i: &str) -> IResult<&str, Template> {
}, },
)) ))
} }
#[cfg(test)]
mod tests {
use super::*;
use nom::bytes::complete::is_a;
use nom::error::ErrorKind;
use nom::Err::Error;
#[test]
fn test_reference() {
assert_eq!(
super::reference("{foo.bar.baz|js|s}"),
Ok((
"",
Reference {
path: Path {
keys: vec!["foo", "bar", "baz"]
},
filters: vec![Filter::JsonStringify, Filter::DisableHtmlEncode],
}
))
);
}
#[test]
fn test_path() {
assert_eq!(
is_a::<_, _, (_, ErrorKind)>("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$")(
"foo"
),
Ok(("", "foo"))
);
assert_eq!(
super::path("foo.bar.baz"),
Ok((
"",
Path {
keys: vec!["foo", "bar", "baz"]
}
))
);
}
#[test]
fn test_special() {
assert_eq!(super::special("{~s}"), Ok(("", Special::Space)));
assert_eq!(super::special("{~n}"), Ok(("", Special::NewLine)));
assert_eq!(super::special("{~r}"), Ok(("", Special::CarriageReturn)));
assert_eq!(super::special("{~lb}"), Ok(("", Special::LeftCurlyBrace)));
assert_eq!(super::special("{~rb}"), Ok(("", Special::RightCurlyBrace)));
assert_eq!(
super::special("{~zzz}"),
Err(Error(("zzz}", ErrorKind::Tag)))
);
}
#[test]
fn test_comment() {
assert_eq!(
super::comment("{! yo dawg} this is a comment !}"),
Ok((
"",
Comment {
value: " yo dawg} this is a comment "
}
))
);
assert_eq!(
super::special("{! this is a comment without a close"),
Err(Error((
"{! this is a comment without a close",
ErrorKind::Tag
)))
);
}
#[test]
fn test_span() {
assert_eq!(
super::span("this is just some text"),
Ok((
"",
Span {
contents: "this is just some text"
}
))
);
assert_eq!(
super::span("this is just some text {~lb}"),
Ok((
"{~lb}",
Span {
contents: "this is just some text "
}
))
);
assert_eq!(
super::span("{~lb}"),
Err(Error(("{~lb}", ErrorKind::Verify)))
);
}
}