FIX: Better error reporting.

Also adds some testing functions to check build failures.

Begins to address Issue #34
This commit is contained in:
Jeremy Wall 2019-02-01 19:17:31 -06:00
parent 39f7afa8fc
commit 2068063a5b
9 changed files with 123 additions and 14 deletions

6
Cargo.lock generated
View File

@ -1,6 +1,6 @@
[[package]] [[package]]
name = "abortable_parser" name = "abortable_parser"
version = "0.2.2" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -443,7 +443,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "ucg" name = "ucg"
version = "0.5.1" version = "0.5.1"
dependencies = [ dependencies = [
"abortable_parser 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "abortable_parser 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -549,7 +549,7 @@ dependencies = [
] ]
[metadata] [metadata]
"checksum abortable_parser 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "685d99bbca3566d6b7f34b09d68039089ce4a36226f6f99f61ed8495850e3213" "checksum abortable_parser 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f1b5820556138ca74cc120d93d6724fbbdf4c8e130e640333d589a3f7ae747e4"
"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" "checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"

View File

@ -19,7 +19,7 @@ include = [
] ]
[dependencies] [dependencies]
abortable_parser = "~0.2.2" abortable_parser = "~0.2.3"
clap = "~2.26.0" clap = "~2.26.0"
serde_json = "~1.0.9" serde_json = "~1.0.9"
simple-error = "0.1" simple-error = "0.1"

View File

@ -15,6 +15,8 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use regex::Regex;
use super::assets::MemoryCache; use super::assets::MemoryCache;
use super::FileBuilder; use super::FileBuilder;
@ -29,6 +31,39 @@ fn assert_build(input: &str) {
} }
} }
fn assert_build_failure(input: &str, expect: Vec<Regex>) {
let i_paths = Vec::new();
let cache = MemoryCache::new();
let mut b = FileBuilder::new("<Eval>", &i_paths, Rc::new(RefCell::new(cache)));
b.enable_validate_mode();
let err = b.eval_string(input);
match err {
Ok(_) => {
for r in expect.iter() {
if !b.assert_collector.success {
if let None = r.find(&b.assert_collector.failures) {
panic!(
"[{}] was not found in Assertion Failures:\n{}",
r, b.assert_collector.failures
);
}
} else {
panic!("Building input Did not panic!");
}
}
}
Err(ref err) => {
for r in expect.iter() {
let stack_trace = format!("{}", err);
// Look for each expect to match the string.
if let None = r.find(&stack_trace) {
panic!("[{}] was not found in stacktrace:\n{}", r, stack_trace);
}
}
}
}
}
#[test] #[test]
fn test_tuples() { fn test_tuples() {
assert_build(include_str!("../../integration_tests/tuple_test.ucg")); assert_build(include_str!("../../integration_tests/tuple_test.ucg"));
@ -119,3 +154,73 @@ fn test_declarative_failures_are_caused_by_msg() {
fn test_declarative_failures_can_with_format_expr() { fn test_declarative_failures_can_with_format_expr() {
assert_build("fail \"@ is a failure!\" % (1);"); assert_build("fail \"@ is a failure!\" % (1);");
} }
#[test]
fn test_assert_just_keyword_compile_failures() {
assert_build_failure(
"assert ",
vec![
Regex::new(r"line: 1, column: 1").unwrap(),
Regex::new(r"Expected Tuple \{ok=<bool>, desc=<str>\}: at <eval> line: 1, column: 8")
.unwrap(),
Regex::new(r"Expected Expression: at <eval> line: 1, column: 8").unwrap(),
],
);
}
#[test]
fn test_assert_partial_tuple_compile_failures() {
assert_build_failure(
"assert {",
vec![
Regex::new(r"line: 1, column: 1").unwrap(),
Regex::new(r"Expected Tuple \{ok=<bool>, desc=<str>\}: at <eval> line: 1, column: 8")
.unwrap(),
Regex::new(r"Expected \(\}\) Instead is \(\): at <eval> line: 1, column: 9").unwrap(),
],
);
}
#[test]
fn test_assert_partial_tuple_missing_ok_compile_failures() {
assert_build_failure(
"assert {};",
vec![
Regex::new(r"0 - NOT OK: TYPE FAIL - Expected Boolean field ok in tuple \{").unwrap(),
Regex::new(r"line: 1, column: 8").unwrap(),
],
);
}
#[test]
fn test_assert_partial_tuple_bad_ok_compile_failures() {
assert_build_failure(
"assert { ok = 1, };",
vec![
Regex::new(r"0 - NOT OK: TYPE FAIL - Expected Boolean field ok in tuple \{").unwrap(),
Regex::new(r"line: 1, column: 8").unwrap(),
],
);
}
#[test]
fn test_assert_partial_tuple_missing_desc_compile_failures() {
assert_build_failure(
"assert { ok=true, };",
vec![
Regex::new(r"0 - NOT OK: TYPE FAIL - Expected String field desc in tuple \{").unwrap(),
Regex::new(r"line: 1, column: 8").unwrap(),
],
);
}
#[test]
fn test_assert_partial_tuple_bad_desc_compile_failures() {
assert_build_failure(
"assert { ok=true, desc = 1 };",
vec![
Regex::new(r"0 - NOT OK: TYPE FAIL - Expected String field desc in tuple \{").unwrap(),
Regex::new(r"line: 1, column: 8").unwrap(),
],
);
}

View File

@ -1535,7 +1535,7 @@ impl<'a> FileBuilder<'a> {
&Val::Boolean(b) => b, &Val::Boolean(b) => b,
_ => { _ => {
let msg = format!( let msg = format!(
"TYPE FAIL - Expected Boolean field ok in tuple {}, line: {} column: {}", "TYPE FAIL - Expected Boolean field ok in tuple {}, line: {}, column: {}",
ok.as_ref(), expr.pos().line, expr.pos().column ok.as_ref(), expr.pos().line, expr.pos().column
); );
self.record_assert_result(&msg, false); self.record_assert_result(&msg, false);
@ -1544,7 +1544,7 @@ impl<'a> FileBuilder<'a> {
}, },
None => { None => {
let msg = format!( let msg = format!(
"TYPE FAIL - Expected Boolean field ok in tuple {}, line: {} column: {}", "TYPE FAIL - Expected Boolean field ok in tuple {}, line: {}, column: {}",
ok.as_ref(), expr.pos().line, expr.pos().column ok.as_ref(), expr.pos().line, expr.pos().column
); );
self.record_assert_result(&msg, false); self.record_assert_result(&msg, false);
@ -1556,7 +1556,7 @@ impl<'a> FileBuilder<'a> {
Val::Str(ref s) => s.clone(), Val::Str(ref s) => s.clone(),
_ => { _ => {
let msg = format!( let msg = format!(
"TYPE FAIL - Expected Boolean field desc in tuple {} line: {} column: {}", "TYPE FAIL - Expected String field desc in tuple {} line: {}, column: {}",
ok, expr.pos().line, expr.pos().column ok, expr.pos().line, expr.pos().column
); );
self.record_assert_result(&msg, false); self.record_assert_result(&msg, false);
@ -1565,7 +1565,7 @@ impl<'a> FileBuilder<'a> {
}, },
None => { None => {
let msg = format!( let msg = format!(
"TYPE FAIL - Expected Boolean field desc in tuple {} line: {} column: {}\n", "TYPE FAIL - Expected String field desc in tuple {} line: {}, column: {}\n",
ok, expr.pos().line, expr.pos().column ok, expr.pos().line, expr.pos().column
); );
self.record_assert_result(&msg, false); self.record_assert_result(&msg, false);

View File

@ -81,7 +81,7 @@ impl BuildError {
}; };
write!( write!(
w, w,
"{} at {} line: {} column: {}\nCaused By:\n\t{} ", "{} at {} line: {}, column: {}\nCaused By:\n\t{} ",
self.err_type, file, self.pos.line, self.pos.column, self.msg self.err_type, file, self.pos.line, self.pos.column, self.msg
)?; )?;
Ok(()) Ok(())

View File

@ -100,13 +100,17 @@ impl<'a> Positioned for OffsetStrIter<'a> {
} }
} }
impl<'a> InputIter for OffsetStrIter<'a> {} impl<'a> InputIter for OffsetStrIter<'a> {
fn curr(&self) -> Self::Item {
self.clone().peek_next().unwrap()
}
}
impl<'a> From<&'a SliceIter<'a, Token>> for Position { impl<'a> From<&'a SliceIter<'a, Token>> for Position {
fn from(source: &'a SliceIter<'a, Token>) -> Self { fn from(source: &'a SliceIter<'a, Token>) -> Self {
match source.peek_next() { match source.peek_next() {
Some(t) => t.pos.clone(), Some(t) => t.pos.clone(),
None => Position::new(0, 0, 0), None => source.curr().pos.clone(),
} }
} }
} }

View File

@ -733,7 +733,7 @@ fn expression(input: SliceIter<Token>) -> ParseResult<Expression> {
let _input = input.clone(); let _input = input.clone();
match trace_parse!(_input, op_expression) { match trace_parse!(_input, op_expression) {
Result::Incomplete(i) => Result::Incomplete(i), Result::Incomplete(i) => Result::Incomplete(i),
Result::Fail(_) => trace_parse!(input, non_op_expression), Result::Fail(_) => trace_parse!(input, wrap_err!(non_op_expression, "Expected Expression")),
Result::Abort(e) => Result::Abort(e), Result::Abort(e) => Result::Abort(e),
Result::Complete(rest, expr) => Result::Complete(rest, expr), Result::Complete(rest, expr) => Result::Complete(rest, expr),
} }
@ -782,7 +782,7 @@ make_fn!(
assert_statement<SliceIter<Token>, Statement>, assert_statement<SliceIter<Token>, Statement>,
do_each!( do_each!(
_ => word!("assert"), _ => word!("assert"),
expr => must!(expression), expr => wrap_err!(must!(expression), "Expected Tuple {ok=<bool>, desc=<str>}"),
_ => must!(punct!(";")), _ => must!(punct!(";")),
(Statement::Assert(expr)) (Statement::Assert(expr))
) )

View File

@ -630,7 +630,7 @@ macro_rules! match_token {
} else { } else {
Result::Fail(Error::new( Result::Fail(Error::new(
format!("Expected {} Instead is ({})", $msg, tok.fragment), format!("Expected {} Instead is ({})", $msg, tok.fragment),
Box::new(i_), Box::new($i.clone()),
)) ))
} }
} else { } else {