FEATURE: More ergonomic syntax for asserts.

This commit is contained in:
Jeremy Wall 2018-08-20 22:51:55 -05:00
parent b87d75c5c7
commit a7a32d56b2
11 changed files with 95 additions and 55 deletions

View File

@ -16,15 +16,15 @@ let list = [1, 2, 3];
let list2 = list;
let list3 = [1, 2];
assert "one == one";
assert "one == one";
assert "one >= one";
assert "two > one";
assert "two >= two";
assert "tpl1 == tpl2";
assert "tpl1 != tpl3";
assert "list == list2";
assert "list != list3";
assert |one == one|;
assert |one == one|;
assert |one >= one|;
assert |two > one|;
assert |two >= two|;
assert |tpl1 == tpl2|;
assert |tpl1 != tpl3|;
assert |list == list2|;
assert |list != list3|;
// Deep Comparisons
let tpl4 = {
@ -40,17 +40,17 @@ let less = {
foo = "bar"
};
assert "tpl4.inner == copy.inner";
assert "tpl4.inner.fld == copy.inner.fld";
assert "tpl4.lst == copy.lst";
assert "tpl4.foo == copy.foo";
assert "tpl4 == copy";
assert "tpl4 != extra";
assert "tpl4 != less";
assert |tpl4.inner == copy.inner|;
assert |tpl4.inner.fld == copy.inner.fld|;
assert |tpl4.lst == copy.lst|;
assert |tpl4.foo == copy.foo|;
assert |tpl4 == copy|;
assert |tpl4 != extra|;
assert |tpl4 != less|;
// Expression comparisons
assert "2 == 1+1";
assert "(1+1) == 2";
assert "(1+1) == (1+1)";
assert |2 == 1+1|;
assert |(1+1) == 2|;
assert |(1+1) == (1+1)|;
let want = "foo";
assert "select want, 1, { foo=2, } == 2";
assert |select want, 1, { foo=2, } == 2|;

View File

@ -2,4 +2,4 @@ let empty = NULL;
let tpl = {
foo = NULL,
};
assert "tpl.foo == empty";
assert |tpl.foo == empty|;

View File

@ -13,10 +13,10 @@ let cplxmacro = macro(argint, argstr, argfloat) => {
let simpleresult = simplemacro(1, 2, 3);
let cplxresult = cplxmacro(1, "We", 3.0);
assert "simpleresult.field1 == 1";
assert "simpleresult.field2 == 2";
assert "simpleresult.field3 == 3";
assert |simpleresult.field1 == 1|;
assert |simpleresult.field2 == 2|;
assert |simpleresult.field3 == 3|;
assert "cplxresult.field1 == 2";
assert "cplxresult.field2 == \"We are here\"";
assert "cplxresult.field3 == 2.0";
assert |cplxresult.field1 == 2|;
assert |cplxresult.field2 == "We are here"|;
assert |cplxresult.field3 == 2.0|;

View File

@ -1,7 +1,7 @@
assert "2 * 2 + 1 == 5";
assert "2 + 2 * 3 == 8";
assert "2 * (2 + 1) == 6";
assert "2 * 2 + 1 > 4";
assert "2 * 2 + 1 > 6";
assert "2 * 2 + 1 >= 5";
assert "2 * 2 + 1 <= 5";
assert |2 * 2 + 1 == 5|;
assert |2 + 2 * 3 == 8|;
assert |2 * (2 + 1) == 6|;
assert |2 * 2 + 1 > 4|;
assert |2 * 2 + 1 > 6|;
assert |2 * 2 + 1 >= 5|;
assert |2 * 2 + 1 <= 5|;

View File

@ -10,10 +10,10 @@ let testmacro = macro(arg) => {
output = arg,
};
assert "list.0 == 1";
assert "list.1 == 2";
assert "list.3 == 4";
assert "tuple.field1 == 1";
assert "tuple.field2 == 3";
assert "tuple.deeplist.0 == \"foo\"";
assert "tuple.deeplist.1 == \"bar\"";
assert |list.0 == 1|;
assert |list.1 == 2|;
assert |list.3 == 4|;
assert |tuple.field1 == 1|;
assert |tuple.field2 == 3|;
assert |tuple.deeplist.0 == "foo"|;
assert |tuple.deeplist.1 == "bar"|;

View File

@ -71,6 +71,7 @@ pub enum TokenType {
WS,
COMMENT,
QUOTED,
PIPEQUOTE,
DIGIT,
BAREWORD,
PUNCT,

View File

@ -409,23 +409,15 @@
//!
//! The assert statement defines an expression that must evaluate to either true or false. Assert statements are noops except
//! during a validation compile. They give you a way to assert certains properties about your data and can be used as a form
//! of unit testting for your configurations. It starts with the assert keyword followed by a quoted string that is
//! itself a valid boolean ucg expression.
//! of unit testing for your configurations. It starts with the assert keyword followed by a valid boolean ucg expression
//! delimited by `|` characters.
//!
//! ```ucg
//! assert "host == \"www.example.com\"";
//! assert "select qa, 443, {
//! assert host == "www.example.com";
//! assert |select qa, 443, {
//! qa = 80,
//! prod = 443,
//! } == 443";
//! ```
//!
//! It is a little bit awkward for strings since you have to escape their quotes. But you can work around it by
//! by storing the expectations in variables first and referencing them in the assert statement.
//!
//! ```ucg
//! let expected_host = "www.example.com";
//! assert "host == expected_host";
//! } == 443|;
//! ```
//!
//! When _test.ucg files are run in a validation run then ucg will output a log of all the assertions

View File

@ -838,7 +838,7 @@ named!(assert_statement<TokenIter, Statement, error::Error>,
error::Error::new(
"Invalid syntax for assert",
error::ErrorType::ParseError, pos)),
match_type!(STR)) >>
match_type!(PIPEQUOTE)) >>
punct!(";") >>
(Statement::Assert(tok.clone()))
)

View File

@ -309,6 +309,20 @@ fn test_out_statement_parse() {
);
}
#[test]
fn test_assert_statement_parse() {
assert_error!(out_statement("assert"));
assert_error!(out_statement("assert |"));
assert_error!(out_statement("assert |foo"));
assert_parse!(
assert_statement("assert |foo|;"),
Statement::Assert(Token {
pos: Position { line: 1, column: 8 },
fragment: "foo".to_string(),
typ: TokenType::PIPEQUOTE
})
);
}
#[test]
fn test_expression_statement_parse() {
assert_error!(expression_statement("foo"));

View File

@ -73,6 +73,20 @@ named!(strtok( Span ) -> Token,
)
);
named!(pipequotetok( Span ) -> Token,
do_parse!(
span: position!() >>
tag!("|") >>
frag: take_until!("|") >>
tag!("|") >>
(Token{
typ: TokenType::PIPEQUOTE,
pos: Position::from(span),
fragment: frag.fragment.to_string(),
})
)
);
named!(barewordtok( Span ) -> Token,
do_parse!(
span: position!() >>
@ -336,6 +350,7 @@ named!(whitespace( Span ) -> Token,
named!(token( Span ) -> Token,
alt!(
strtok |
pipequotetok |
emptytok | // This must come before the barewordtok
digittok |
commatok |
@ -475,6 +490,14 @@ macro_rules! match_type {
match_type!($i, STR => token_clone)
};
($i:expr,PIPEQUOTE => $h:expr) => {
match_type!($i, TokenType::PIPEQUOTE, "Not a Pipe Quoted String", $h)
};
($i:expr,PIPEQUOTE) => {
match_type!($i, PIPEQUOTE => token_clone)
};
($i:expr,DIGIT => $h:expr) => {
match_type!($i, TokenType::DIGIT, "Not a DIGIT", $h)
};

View File

@ -42,6 +42,16 @@ fn test_escape_quoted() {
}
}
#[test]
fn test_pipe_quoted() {
let result = pipequotetok(LocatedSpan::new("|foo|"));
assert!(result.is_done(), format!("result {:?} is not ok", result));
if let nom::IResult::Done(_, tok) = result {
assert_eq!(tok.fragment, "foo".to_string());
assert_eq!(tok.typ, TokenType::PIPEQUOTE);
}
}
#[test]
fn test_string_with_escaping() {
let result = strtok(LocatedSpan::new("\"foo \\\\ \\\"bar\""));