From 1befc8674e77a973c6c7a8a8dfe65202d85bfd83 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sun, 8 Jan 2017 19:01:48 -0800 Subject: [PATCH] Test all errors and error messages (#145) --- src/integration.rs | 258 ++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 25 +++-- 2 files changed, 269 insertions(+), 14 deletions(-) diff --git a/src/integration.rs b/src/integration.rs index e8e37d5..dee834d 100644 --- a/src/integration.rs +++ b/src/integration.rs @@ -344,7 +344,7 @@ recipe: } #[test] -fn error() { +fn unknown_dependency() { integration_test( &[], "bar:\nhello:\nfoo: bar baaaaaaaz hello", @@ -740,6 +740,31 @@ wut: ); } +#[test] +fn outer_shebang() { + integration_test( + &[], + r#"#!/lol/wut +export foo = "a" +baz = "c" +export bar = "b" +export abc = foo + bar + baz + +wut: + #!/bin/sh + echo $foo $bar $abc +"#, + 255, + "", + "error: `#!` is reserved syntax outside of recipes + | +1 | #!/lol/wut + | ^ +", + ); +} + + #[test] fn export_shebang() { integration_test( @@ -1100,6 +1125,53 @@ recipe a b +d: ); } +#[test] +fn mixed_whitespace() { + integration_test( + &[], + "bar:\n\t echo hello", + 255, + "", + "error: Found a mix of tabs and spaces in leading whitespace: `␉␠` +Leading whitespace may consist of tabs or spaces, but not both + | +2 | echo hello + | ^ +", + ); +} + +#[test] +fn extra_leading_whitespace() { + integration_test( + &[], + "bar:\n\t\techo hello\n\t\t\techo goodbye", + 255, + "", + "error: Recipe line has extra leading whitespace + | +3 | echo goodbye + | ^^^^^^^^^^^^^^^^ +", + ); +} + +#[test] +fn inconsistent_leading_whitespace() { + integration_test( + &[], + "bar:\n\t\techo hello\n\t echo goodbye", + 255, + "", + "error: Recipe line has inconsistent leading whitespace. Recipe started with `␉␉` but found line with `␉␠` + | +3 | echo goodbye + | ^ +", + ); +} + + #[test] fn required_after_default() { integration_test( @@ -1115,6 +1187,21 @@ fn required_after_default() { ); } +#[test] +fn required_after_variadic() { + integration_test( + &[], + "bar:\nhello baz +arg bar:", + 255, + "", + "error: Parameter `bar` follows variadic parameter + | +2 | hello baz +arg bar: + | ^^^ +", + ); +} + #[test] fn use_string_default() { integration_test( @@ -1374,6 +1461,128 @@ c: b a ); } +#[test] +fn parameter_shadows_variable() { + integration_test( + &["a"], + "FOO = 'hello'\na FOO:", + 255, + "", + "error: Parameter `FOO` shadows variable of the same name + | +2 | a FOO: + | ^^^ +", + ); +} + + +#[test] +fn dependency_takes_arguments() { + integration_test( + &["b"], + "b: a\na FOO:", + 255, + "", + "error: Recipe `b` depends on `a` which requires arguments. Dependencies may not require arguments + | +1 | b: a + | ^ +", + ); +} + +#[test] +fn duplicate_parameter() { + integration_test( + &["a"], + "a foo foo:", + 255, + "", + "error: Recipe `a` has duplicate parameter `foo` + | +1 | a foo foo: + | ^^^ +", + ); +} + +#[test] +fn duplicate_dependency() { + integration_test( + &["a"], + "b:\na: b b", + 255, + "", + "error: Recipe `a` has duplicate dependency `b` + | +2 | a: b b + | ^ +", + ); +} + +#[test] +fn duplicate_recipe() { + integration_test( + &["b"], + "b:\nb:", + 255, + "", + "error: Recipe `b` first defined on line 1 is redefined on line 2 + | +2 | b: + | ^ +", + ); +} + +#[test] +fn duplicate_variable() { + integration_test( + &["foo"], + "a = 'hello'\na = 'hello'\nfoo:", + 255, + "", + "error: Variable `a` has multiple definitions + | +2 | a = 'hello' + | ^ +", + ); +} + +#[test] +fn unexpected_token() { + integration_test( + &["foo"], + "foo: 'bar'", + 255, + "", + "error: Expected name, end of line, or end of file, but found raw string + | +1 | foo: 'bar' + | ^^^^^ +", + ); +} + + +#[test] +fn self_dependency() { + integration_test( + &["a"], + "a: a", + 255, + "", + "error: Recipe `a` depends on itself + | +1 | a: a + | ^ +", + ); +} + #[test] fn long_circular_recipe_dependency() { integration_test( @@ -1389,6 +1598,53 @@ fn long_circular_recipe_dependency() { ); } +#[test] +fn variable_self_dependency() { + integration_test( + &["a"], + "z = z\na:", + 255, + "", + "error: Variable `z` is defined in terms of itself + | +1 | z = z + | ^ +", + ); +} + +#[test] +fn variable_circular_dependency() { + integration_test( + &["a"], + "x = y\ny = z\nz = x\na:", + 255, + "", + "error: Variable `x` depends on its own value: `x -> y -> z -> x` + | +1 | x = y + | ^ +", + ); +} + +#[test] +fn invalid_escape_sequence() { + integration_test( + &["a"], + r#"x = "\q" +a:"#, + 255, + "", + "error: `\\q` is not a valid escape sequence + | +1 | x = \"\\q\" + | ^^^^ +", + ); +} + + #[test] fn multiline_raw_string() { integration_test( diff --git a/src/lib.rs b/src/lib.rs index 184b82d..2a50448 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -828,7 +828,7 @@ fn internal_error(message: String) -> CompileError<'static> { } fn show_whitespace(text: &str) -> String { - text.chars().map(|c| match c { '\t' => 't', ' ' => 's', _ => c }).collect() + text.chars().map(|c| match c { '\t' => '␉', ' ' => '␠', _ => c }).collect() } fn mixed_whitespace(text: &str) -> bool { @@ -1052,7 +1052,7 @@ impl<'a> Display for CompileError<'a> { match self.kind { CircularRecipeDependency{recipe, ref circle} => { if circle.len() == 2 { - write!(f, "Recipe `{}` depends on itself", recipe)?; + writeln!(f, "Recipe `{}` depends on itself", recipe)?; } else { writeln!(f, "Recipe `{}` has circular dependency `{}`", recipe, circle.join(" -> "))?; @@ -1060,8 +1060,7 @@ impl<'a> Display for CompileError<'a> { } CircularVariableDependency{variable, ref circle} => { if circle.len() == 2 { - writeln!(f, "Variable `{}` depends on its own value: `{}`", - variable, circle.join(" -> "))?; + writeln!(f, "Variable `{}` is defined in terms of itself", variable)?; } else { writeln!(f, "Variable `{}` depends on its own value: `{}`", variable, circle.join(" -> "))?; @@ -1075,21 +1074,21 @@ impl<'a> Display for CompileError<'a> { writeln!(f, "Recipe `{}` has duplicate parameter `{}`", recipe, parameter)?; } DuplicateVariable{variable} => { - writeln!(f, "Variable `{}` is has multiple definitions", variable)?; + writeln!(f, "Variable `{}` has multiple definitions", variable)?; } UnexpectedToken{ref expected, found} => { - writeln!(f, "Expected {} but found {}", Or(expected), found)?; + writeln!(f, "Expected {}, but found {}", Or(expected), found)?; } DuplicateDependency{recipe, dependency} => { writeln!(f, "Recipe `{}` has duplicate dependency `{}`", recipe, dependency)?; } DuplicateRecipe{recipe, first} => { writeln!(f, "Recipe `{}` first defined on line {} is redefined on line {}", - recipe, first, self.line)?; + recipe, first + 1, self.line + 1)?; } DependencyHasParameters{recipe, dependency} => { writeln!(f, "Recipe `{}` depends on `{}` which requires arguments. \ - dependencies may not require arguments", recipe, dependency)?; + Dependencies may not require arguments", recipe, dependency)?; } ParameterShadowsVariable{parameter} => { writeln!(f, "Parameter `{}` shadows variable of the same name", parameter)?; @@ -1098,12 +1097,12 @@ impl<'a> Display for CompileError<'a> { writeln!(f, "Non-default parameter `{}` follows default parameter", parameter)?; } ParameterFollowsVariadicParameter{parameter} => { - writeln!(f, "Parameter `{}` follows a varidic parameter", parameter)?; + writeln!(f, "Parameter `{}` follows variadic parameter", parameter)?; } MixedLeadingWhitespace{whitespace} => { writeln!(f, "Found a mix of tabs and spaces in leading whitespace: `{}`\n\ - leading whitespace may consist of tabs or spaces, but not both", + Leading whitespace may consist of tabs or spaces, but not both", show_whitespace(whitespace) )?; } @@ -1112,12 +1111,12 @@ impl<'a> Display for CompileError<'a> { } InconsistentLeadingWhitespace{expected, found} => { writeln!(f, - "Inconsistant leading whitespace: recipe started with `{}` but found line with `{}`:", + "Recipe line has inconsistent leading whitespace. Recipe started with `{}` but found line with `{}`", show_whitespace(expected), show_whitespace(found) )?; } OuterShebang => { - writeln!(f, "Shebang `#!` is reserved syntax outside of recipes")?; + writeln!(f, "`#!` is reserved syntax outside of recipes")?; } UnknownDependency{recipe, unknown} => { writeln!(f, "Recipe `{}` has unknown dependency `{}`", recipe, unknown)?; @@ -1405,7 +1404,7 @@ impl<'a> Display for RunError<'a> { error_token = Some(token); } BacktickUnknownFailure{ref token} => { - write!(f, "Backtick failed for an uknown reason")?; + write!(f, "Backtick failed for an unknown reason")?; error_token = Some(token); } BacktickIoError{ref token, ref io_error} => {