diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f9629d17e5..751e2d3eb3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -49,7 +49,7 @@ jobs: - uses: actions-rust-lang/setup-rust-toolchain@v1 with: - toolchain: 1.82.0 + toolchain: 1.85.0 - uses: Swatinem/rust-cache@v2 diff --git a/Cargo.lock b/Cargo.lock index 40179f8c0c..df7b2e25f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,6 +79,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "ariadne" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8454c8a44ce2cb9cc7e7fae67fc6128465b343b92c6631e94beca3c8d1524ea5" +dependencies = [ + "unicode-width", + "yansi", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -549,6 +559,7 @@ name = "just" version = "1.46.0" dependencies = [ "ansi_term", + "ariadne", "blake3", "camino", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 545011120d..a812c4b0d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,13 +12,14 @@ keywords = ["command-line", "task", "runner", "development", "utility"] license = "CC0-1.0" readme = "crates-io-readme.md" repository = "https://github.com/casey/just" -rust-version = "1.82.0" +rust-version = "1.85.0" [workspace] members = [".", "crates/*"] [dependencies] ansi_term = "0.12.0" +ariadne = "0.6.0" blake3 = { version = "1.5.0", features = ["rayon", "mmap"] } camino = "1.0.4" chrono = "0.4.38" diff --git a/src/compile_error.rs b/src/compile_error.rs index 469e73fd84..900d130e72 100644 --- a/src/compile_error.rs +++ b/src/compile_error.rs @@ -26,6 +26,65 @@ impl<'src> CompileError<'src> { } } +pub(crate) fn render_compile_error(error: &CompileError, color: Color) { + use ariadne::{Config, Label, Report, ReportKind, Source}; + + let source = Source::from(error.token.src); + + let start = error.token.offset; + let end = start + error.token.length; + let path = error.token.path.display().to_string(); + let label = Label::new((&path, start..end)); + + let config = Config::default().with_color(color.stderr().active()); + let report = Report::build(ReportKind::Error, (&path, start..end)).with_config(config); + + let report = match &*error.kind { + CompileErrorKind::AttributeArgumentCountMismatch { + attribute, + found, + min, + max, + } => { + let label_msg = format!("Found {found} {}", Count("argument", *found)); + + let note = if min == max { + format!("`{attribute}` takes {min} {}", Count("argument", *min)) + } else if *max == usize::MAX { + format!( + "`{attribute}` takes at least {min} {}", + Count("argument", *min) + ) + } else { + format!("`{attribute}` takes between {min} and {max} arguments") + }; + + report + .with_message("Attribute argument count mismatch") + .with_label(label.with_message(label_msg)) + .with_note(note) + .finish() + } + CompileErrorKind::DuplicateAttribute { attribute, first } => { + let original_label = source + .line(*first) + .map(|line| Label::new((&path, line.span())).with_message("original")); + + let mut report = report.with_message(format!("Duplicate attribute `{attribute}`")); + if let Some(original) = original_label { + report = report.with_label(original); + } + report.with_label(label.with_message("duplicate")).finish() + } + _ => { + let message = format!("{error}"); + report.with_message(message).with_label(label).finish() + } + }; + + report.eprint((&path, source)).unwrap(); +} + fn capitalize(s: &str) -> String { let mut chars = s.chars(); match chars.next() { diff --git a/src/error.rs b/src/error.rs index 81a6ef5f9e..3d582ffe1a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -822,6 +822,13 @@ impl ColorDisplay for Error<'_> { } } +pub(crate) fn render_error(error: &Error, color: Color) { + match error { + Error::Compile { compile_error } => compile_error::render_compile_error(compile_error, color), + _ => eprintln!("{}", error.color_display(color.stderr())), + } +} + fn format_cmd(binary: &OsString, arguments: &Vec) -> String { iter::once(binary) .chain(arguments) diff --git a/src/run.rs b/src/run.rs index 056c9fa72d..ceec82cd63 100644 --- a/src/run.rs +++ b/src/run.rs @@ -29,7 +29,7 @@ pub fn run(args: impl Iterator + Clone>) -> Result<() }) .map_err(|error| { if !verbosity.quiet() && error.print_message() { - eprintln!("{}", error.color_display(color.stderr())); + crate::error::render_error(&error, color); } error.code().unwrap_or(EXIT_FAILURE) }) diff --git a/tests/alias.rs b/tests/alias.rs index f69f08c3b9..05b1ae429c 100644 --- a/tests/alias.rs +++ b/tests/alias.rs @@ -33,12 +33,11 @@ fn unknown_nested_alias() { ) .arg("b") .stderr( - "\ - error: Alias `b` has an unknown target `foo::bar::baz` - ——▶ justfile:3:7 - │ -3 │ alias b := foo::bar::baz - │ ^ + r"Error: Alias `b` has an unknown target `foo::bar::baz` + ╭─[ justfile:3:7 ] + │ + 3 │ alias b := foo::bar::baz +───╯ ", ) .failure(); diff --git a/tests/allow_missing.rs b/tests/allow_missing.rs index 237b013fcf..1bd151b688 100644 --- a/tests/allow_missing.rs +++ b/tests/allow_missing.rs @@ -26,13 +26,12 @@ fn allow_missing_does_not_apply_to_compilation_errors() { .justfile("bar: foo") .args(["--allow-missing", "foo"]) .stderr( - " - error: Recipe `bar` has unknown dependency `foo` - ——▶ justfile:1:6 - │ - 1 │ bar: foo - │ ^^^ - ", + r"Error: Recipe `bar` has unknown dependency `foo` + ╭─[ justfile:1:6 ] + │ + 1 │ bar: foo +───╯ +", ) .failure(); } diff --git a/tests/arg_attribute.rs b/tests/arg_attribute.rs index 59d8333a77..f024c1b095 100644 --- a/tests/arg_attribute.rs +++ b/tests/arg_attribute.rs @@ -77,17 +77,12 @@ fn pattern_invalid_regex_error() { ", ) .stderr( - " - error: Failed to parse argument pattern - ——▶ justfile:1:21 - │ - 1 │ [arg('bar', pattern='{')] - │ ^^^ - caused by: regex parse error: - { - ^ - error: repetition operator missing expression - ", + r"Error: Failed to parse argument pattern + ╭─[ justfile:1:21 ] + │ + 1 │ [arg('bar', pattern='{')] +───╯ +", ) .failure(); } @@ -123,13 +118,12 @@ fn duplicate_attribute_error() { ) .args(["foo", "BAR"]) .stderr( - " - error: Recipe attribute for argument `bar` first used on line 1 is duplicated on line 2 - ——▶ justfile:2:2 - │ - 2 │ [arg('bar', pattern='BAR')] - │ ^^^ - ", + r"Error: Recipe attribute for argument `bar` first used on line 1 is duplicated on line 2 + ╭─[ justfile:2:2 ] + │ + 2 │ [arg('bar', pattern='BAR')] +───╯ +", ) .failure(); } @@ -145,13 +139,12 @@ fn extra_keyword_error() { ) .args(["foo", "BAR"]) .stderr( - " - error: Unknown keyword `foo` for `arg` attribute - ——▶ justfile:1:28 - │ - 1 │ [arg('bar', pattern='BAR', foo='foo')] - │ ^^^ - ", + r"Error: Unknown keyword `foo` for `arg` attribute + ╭─[ justfile:1:28 ] + │ + 1 │ [arg('bar', pattern='BAR', foo='foo')] +───╯ +", ) .failure(); } @@ -167,13 +160,12 @@ fn unknown_argument_error() { ) .arg("foo") .stderr( - " - error: Argument attribute for undefined argument `bar` - ——▶ justfile:1:6 - │ - 1 │ [arg('bar', pattern='BAR')] - │ ^^^^^ - ", + r"Error: Argument attribute for undefined argument `bar` + ╭─[ justfile:1:6 ] + │ + 1 │ [arg('bar', pattern='BAR')] +───╯ +", ) .failure(); } @@ -221,13 +213,12 @@ fn positional_arguments_cannot_follow_keyword_arguments() { ) .args(["foo", "BAR"]) .stderr( - " - error: Positional attribute arguments cannot follow keyword attribute arguments - ——▶ justfile:1:21 - │ - 1 │ [arg(pattern='BAR', 'bar')] - │ ^^^^^ - ", + r"Error: Positional attribute arguments cannot follow keyword attribute arguments + ╭─[ justfile:1:21 ] + │ + 1 │ [arg(pattern='BAR', 'bar')] +───╯ +", ) .failure(); } @@ -352,13 +343,12 @@ fn pattern_requires_value() { ", ) .stderr( - " - error: Attribute key `pattern` requires value - ——▶ justfile:1:13 - │ - 1 │ [arg('bar', pattern)] - │ ^^^^^^^ - ", + r"Error: Attribute key `pattern` requires value + ╭─[ justfile:1:13 ] + │ + 1 │ [arg('bar', pattern)] +───╯ +", ) .failure(); } @@ -373,13 +363,12 @@ fn short_requires_value() { ", ) .stderr( - " - error: Attribute key `short` requires value - ——▶ justfile:1:13 - │ - 1 │ [arg('bar', short)] - │ ^^^^^ - ", + r"Error: Attribute key `short` requires value + ╭─[ justfile:1:13 ] + │ + 1 │ [arg('bar', short)] +───╯ +", ) .failure(); } @@ -394,13 +383,12 @@ fn value_requires_value() { ", ) .stderr( - " - error: Attribute key `value` requires value - ——▶ justfile:1:19 - │ - 1 │ [arg('bar', long, value)] - │ ^^^^^ - ", + r"Error: Attribute key `value` requires value + ╭─[ justfile:1:19 ] + │ + 1 │ [arg('bar', long, value)] +───╯ +", ) .failure(); } diff --git a/tests/assignment.rs b/tests/assignment.rs index 4269bb1cf1..2c3bec9215 100644 --- a/tests/assignment.rs +++ b/tests/assignment.rs @@ -9,13 +9,12 @@ fn set_export_parse_error() { ", ) .stderr( - " - error: Expected keyword `true` or `false` but found identifier `fals` - ——▶ justfile:1:15 - │ - 1 │ set export := fals - │ ^^^^ - ", + r"Error: Expected keyword `true` or `false` but found identifier `fals` + ╭─[ justfile:1:15 ] + │ + 1 │ set export := fals +───╯ +", ) .failure(); } @@ -29,13 +28,12 @@ fn set_export_parse_error_eol() { ", ) .stderr( - " - error: Expected identifier, but found end of line - ——▶ justfile:1:14 - │ - 1 │ set export := - │ ^ - ", + r"Error: Expected identifier, but found end of line + ╭─[ justfile:1:14 ] + │ + 1 │ set export := +───╯ +", ) .failure(); } @@ -51,13 +49,12 @@ fn invalid_attributes_are_an_error() { ) .args(["--evaluate", "x"]) .stderr( - " - error: Assignment `x` has invalid attribute `group` - ——▶ justfile:2:1 - │ - 2 │ x := 'foo' - │ ^ - ", + r"Error: Assignment `x` has invalid attribute `group` + ╭─[ justfile:2:1 ] + │ + 2 │ x := 'foo' +───╯ +", ) .failure(); } diff --git a/tests/attributes.rs b/tests/attributes.rs index 408381282a..0fe62fbec9 100644 --- a/tests/attributes.rs +++ b/tests/attributes.rs @@ -31,13 +31,17 @@ fn duplicate_attributes_are_disallowed() { ", ) .stderr( - " - error: Recipe attribute `no-exit-message` first used on line 1 is duplicated on line 2 - ——▶ justfile:2:2 - │ - 2 │ [no-exit-message] - │ ^^^^^^^^^^^^^^^ - ", + r"Error: Duplicate attribute `no-exit-message` + ╭─[ justfile:2:2 ] + │ + 1 │ [no-exit-message] + │ ─────────┬──────── + │ ╰────────── original + 2 │ [no-exit-message] + │ ───────┬─────── + │ ╰───────── duplicate +───╯ +", ) .failure(); } @@ -69,13 +73,12 @@ fn multiple_attributes_one_line_error_message() { ", ) .stderr( - " - error: Expected ']', ':', ',', or '(', but found identifier - ——▶ justfile:1:16 - │ - 1 │ [macos,windows linux,openbsd] - │ ^^^^^ - ", + r"Error: Expected ']', ':', ',', or '(', but found identifier + ╭─[ justfile:1:16 ] + │ + 1 │ [macos,windows linux,openbsd] +───╯ +", ) .failure(); } @@ -92,13 +95,17 @@ fn multiple_attributes_one_line_duplicate_check() { ", ) .stderr( - " - error: Recipe attribute `linux` first used on line 1 is duplicated on line 2 - ——▶ justfile:2:2 - │ - 2 │ [linux] - │ ^^^^^ - ", + r"Error: Duplicate attribute `linux` + ╭─[ justfile:2:2 ] + │ + 1 │ [macos, windows, linux, openbsd] + │ ────────────────┬──────────────── + │ ╰────────────────── original + 2 │ [linux] + │ ──┬── + │ ╰──── duplicate +───╯ +", ) .failure(); } @@ -114,13 +121,16 @@ fn unexpected_attribute_argument() { ", ) .stderr( - " - error: Attribute `private` got 1 argument but takes 0 arguments - ——▶ justfile:1:2 - │ - 1 │ [private('foo')] - │ ^^^^^^^ - ", + r"Error: Attribute argument count mismatch + ╭─[ justfile:1:2 ] + │ + 1 │ [private('foo')] + │ ───┬─── + │ ╰───── Found 1 argument + │ + │ Note: `private` takes 0 arguments +───╯ +", ) .failure(); } @@ -168,13 +178,16 @@ fn expected_metadata_attribute_argument() { ", ) .stderr( - " - error: Attribute `metadata` got 0 arguments but takes at least 1 argument - ——▶ justfile:1:2 - │ - 1 │ [metadata] - │ ^^^^^^^^ - ", + r"Error: Attribute argument count mismatch + ╭─[ justfile:1:2 ] + │ + 1 │ [metadata] + │ ────┬─── + │ ╰───── Found 0 arguments + │ + │ Note: `metadata` takes at least 1 argument +───╯ +", ) .failure(); } @@ -268,12 +281,11 @@ fn extension_on_linewise_error() { ", ) .stderr( - " - error: Recipe `baz` has invalid attribute `extension` - ——▶ justfile:2:1 - │ - 2 │ baz: - │ ^^^ + r"Error: Recipe `baz` has invalid attribute `extension` + ╭─[ justfile:2:1 ] + │ + 2 │ baz: +───╯ ", ) .failure(); @@ -290,12 +302,16 @@ fn duplicate_non_repeatable_attributes_are_forbidden() { ", ) .stderr( - " - error: Recipe attribute `confirm` first used on line 1 is duplicated on line 2 - ——▶ justfile:2:2 - │ - 2 │ [confirm: 'no'] - │ ^^^^^^^ + r"Error: Duplicate attribute `confirm` + ╭─[ justfile:2:2 ] + │ + 1 │ [confirm: 'yes'] + │ ────────┬──────── + │ ╰────────── original + 2 │ [confirm: 'no'] + │ ───┬─── + │ ╰───── duplicate +───╯ ", ) .failure(); @@ -392,12 +408,15 @@ fn env_attribute_too_few_arguments() { ", ) .stderr( - " - error: Attribute `env` got 1 argument but takes 2 arguments - ——▶ justfile:1:2 - │ - 1 │ [env('MY_VAR')] - │ ^^^ + r"Error: Attribute argument count mismatch + ╭─[ justfile:1:2 ] + │ + 1 │ [env('MY_VAR')] + │ ─┬─ + │ ╰─── Found 1 argument + │ + │ Note: `env` takes 2 arguments +───╯ ", ) .failure(); @@ -414,12 +433,15 @@ fn env_attribute_too_many_arguments() { ", ) .stderr( - " - error: Attribute `env` got 3 arguments but takes 2 arguments - ——▶ justfile:1:2 - │ - 1 │ [env('A', 'B', 'C')] - │ ^^^ + r"Error: Attribute argument count mismatch + ╭─[ justfile:1:2 ] + │ + 1 │ [env('A', 'B', 'C')] + │ ─┬─ + │ ╰─── Found 3 arguments + │ + │ Note: `env` takes 2 arguments +───╯ ", ) .failure(); @@ -437,12 +459,11 @@ fn env_attribute_duplicate_error() { ", ) .stderr( - " - error: Environment variable `VAR1` first set on line 1 is set again on line 2 - ——▶ justfile:2:2 - │ - 2 │ [env('VAR1', 'value 2')] - │ ^^^ + r"Error: Environment variable `VAR1` first set on line 1 is set again on line 2 + ╭─[ justfile:2:2 ] + │ + 2 │ [env('VAR1', 'value 2')] +───╯ ", ) .failure(); diff --git a/tests/byte_order_mark.rs b/tests/byte_order_mark.rs index 39269e89dc..1077ffdaaa 100644 --- a/tests/byte_order_mark.rs +++ b/tests/byte_order_mark.rs @@ -24,14 +24,12 @@ fn non_leading_byte_order_mark_produces_error() { \u{feff} ", ) - .stderr( - " - error: Expected \'@\', \'[\', comment, end of file, end of line, or identifier, but found byte order mark - ——▶ justfile:3:1 - │ - 3 │ \u{feff} - │ ^ - ") + .stderr(r"Error: Expected '@', '[', comment, end of file, end of line, or identifier, but found byte order mark + ╭─[ justfile:3:1 ] + │ + │ +───╯ +") .failure(); } @@ -40,13 +38,12 @@ fn dont_mention_byte_order_mark_in_errors() { Test::new() .justfile("{") .stderr( - " - error: Expected '@', '[', comment, end of file, end of line, or identifier, but found '{' - ——▶ justfile:1:1 - │ - 1 │ { - │ ^ - ", + r"Error: Expected '@', '[', comment, end of file, end of line, or identifier, but found '{' + ╭─[ justfile:1:1 ] + │ + 1 │ { +───╯ +", ) .failure(); } diff --git a/tests/conditional.rs b/tests/conditional.rs index 6cee81468f..ff2a833df4 100644 --- a/tests/conditional.rs +++ b/tests/conditional.rs @@ -82,13 +82,12 @@ fn undefined_lhs() { ", ) .stderr( - " - error: Variable `b` not defined - ——▶ justfile:1:9 - │ - 1 │ a := if b == '' { '' } else { '' } - │ ^ - ", + r"Error: Variable `b` not defined + ╭─[ justfile:1:9 ] + │ + 1 │ a := if b == '' { '' } else { '' } +───╯ +", ) .failure(); } @@ -105,13 +104,12 @@ fn undefined_rhs() { ", ) .stderr( - " - error: Variable `b` not defined - ——▶ justfile:1:15 - │ - 1 │ a := if '' == b { '' } else { '' } - │ ^ - ", + r"Error: Variable `b` not defined + ╭─[ justfile:1:15 ] + │ + 1 │ a := if '' == b { '' } else { '' } +───╯ +", ) .failure(); } @@ -128,13 +126,12 @@ fn undefined_then() { ", ) .stderr( - " - error: Variable `b` not defined - ——▶ justfile:1:20 - │ - 1 │ a := if '' == '' { b } else { '' } - │ ^ - ", + r"Error: Variable `b` not defined + ╭─[ justfile:1:20 ] + │ + 1 │ a := if '' == '' { b } else { '' } +───╯ +", ) .failure(); } @@ -151,13 +148,12 @@ fn undefined_otherwise() { ", ) .stderr( - " - error: Variable `b` not defined - ——▶ justfile:1:32 - │ - 1 │ a := if '' == '' { '' } else { b } - │ ^ - ", + r"Error: Variable `b` not defined + ╭─[ justfile:1:32 ] + │ + 1 │ a := if '' == '' { '' } else { b } +───╯ +", ) .failure(); } @@ -174,13 +170,12 @@ fn unexpected_op() { ", ) .stderr( - " - error: Expected '&&', '!=', '!~', '||', '==', '=~', '+', or '/', but found identifier - ——▶ justfile:1:12 - │ - 1 │ a := if '' a '' { '' } else { b } - │ ^ - ", + r"Error: Expected '&&', '!=', '!~', '||', '==', '=~', '+', or '/', but found identifier + ╭─[ justfile:1:12 ] + │ + 1 │ a := if '' a '' { '' } else { b } +───╯ +", ) .failure(); } @@ -233,13 +228,12 @@ fn missing_else() { ", ) .stderr( - " - error: Expected keyword `else` but found `end of line` - ——▶ justfile:1:54 - │ - 1 │ TEST := if path_exists('/bin/bash') == 'true' {'yes'} - │ ^ - ", + r"Error: Expected keyword `else` but found `end of line` + ╭─[ justfile:1:54 ] + │ + 1 │ TEST := if path_exists('/bin/bash') == 'true' {'yes'} +───╯ +", ) .failure(); } @@ -253,13 +247,12 @@ fn incorrect_else_identifier() { ", ) .stderr( - " - error: Expected keyword `else` but found identifier `els` - ——▶ justfile:1:55 - │ - 1 │ TEST := if path_exists('/bin/bash') == 'true' {'yes'} els {'no'} - │ ^^^ - ", + r"Error: Expected keyword `else` but found identifier `els` + ╭─[ justfile:1:55 ] + │ + 1 │ TEST := if path_exists('/bin/bash') == 'true' {'yes'} els {'no'} +───╯ +", ) .failure(); } diff --git a/tests/confirm.rs b/tests/confirm.rs index db7332be31..e914eb1b2e 100644 --- a/tests/confirm.rs +++ b/tests/confirm.rs @@ -128,13 +128,16 @@ fn confirm_recipe_with_prompt_too_many_args() { "#, ) .stderr( - r#" - error: Attribute `confirm` got 2 arguments but takes at most 1 argument - ——▶ justfile:1:2 - │ - 1 │ [confirm("PROMPT","EXTRA")] - │ ^^^^^^^ - "#, + r#"Error: Attribute argument count mismatch + ╭─[ justfile:1:2 ] + │ + 1 │ [confirm("PROMPT","EXTRA")] + │ ───┬─── + │ ╰───── Found 2 arguments + │ + │ Note: `confirm` takes between 0 and 1 arguments +───╯ +"#, ) .failure(); } diff --git a/tests/default.rs b/tests/default.rs index 7322d33e7e..dfcab5f16c 100644 --- a/tests/default.rs +++ b/tests/default.rs @@ -29,14 +29,11 @@ fn default_attribute_may_only_appear_once_per_justfile() { bar: ", ) - .stderr( - " - error: Recipe `foo` has duplicate `[default]` attribute, which may only appear once per module - ——▶ justfile:2:1 - │ - 2 │ foo: - │ ^^^ - " - ) + .stderr(r"Error: Recipe `foo` has duplicate `[default]` attribute, which may only appear once per module + ╭─[ justfile:2:1 ] + │ + 2 │ foo: +───╯ +") .failure(); } diff --git a/tests/delimiters.rs b/tests/delimiters.rs index 1a3686e53f..384f4bd633 100644 --- a/tests/delimiters.rs +++ b/tests/delimiters.rs @@ -5,13 +5,12 @@ fn mismatched_delimiter() { Test::new() .justfile("(]") .stderr( - " - error: Mismatched closing delimiter `]`. (Did you mean to close the `(` on line 1?) - ——▶ justfile:1:2 - │ - 1 │ (] - │ ^ - ", + r"Error: Mismatched closing delimiter `]`. (Did you mean to close the `(` on line 1?) + ╭─[ justfile:1:2 ] + │ + 1 │ (] +───╯ +", ) .failure(); } @@ -21,13 +20,12 @@ fn unexpected_delimiter() { Test::new() .justfile("]") .stderr( - " - error: Unexpected closing delimiter `]` - ——▶ justfile:1:1 - │ - 1 │ ] - │ ^ - ", + r"Error: Unexpected closing delimiter `]` + ╭─[ justfile:1:1 ] + │ + 1 │ ] +───╯ +", ) .failure(); } diff --git a/tests/dependencies.rs b/tests/dependencies.rs index 251664c320..e70476cda8 100644 --- a/tests/dependencies.rs +++ b/tests/dependencies.rs @@ -45,11 +45,11 @@ fn dependency_not_in_submodule() { ) .arg("baz") .stderr( - "error: Recipe `baz` has unknown dependency `foo::baz` - ——▶ justfile:2:11 - │ -2 │ baz: foo::baz - │ ^^^ + r"Error: Recipe `baz` has unknown dependency `foo::baz` + ╭─[ justfile:2:11 ] + │ + 2 │ baz: foo::baz +───╯ ", ) .failure(); @@ -69,11 +69,11 @@ fn dependency_submodule_missing() { ) .arg("baz") .stderr( - "error: Recipe `baz` has unknown dependency `foo::bar` - ——▶ justfile:5:11 - │ -5 │ baz: foo::bar - │ ^^^ + r"Error: Recipe `baz` has unknown dependency `foo::bar` + ╭─[ justfile:5:11 ] + │ + 5 │ baz: foo::bar +───╯ ", ) .failure(); @@ -92,11 +92,11 @@ fn recipe_dependency_on_module_fails() { ) .arg("baz") .stderr( - "error: Recipe `baz` has unknown dependency `foo::bar` - ——▶ justfile:2:11 - │ -2 │ baz: foo::bar - │ ^^^ + r"Error: Recipe `baz` has unknown dependency `foo::bar` + ╭─[ justfile:2:11 ] + │ + 2 │ baz: foo::bar +───╯ ", ) .failure(); diff --git a/tests/error_messages.rs b/tests/error_messages.rs index e8cf59a6f0..b760c90342 100644 --- a/tests/error_messages.rs +++ b/tests/error_messages.rs @@ -5,13 +5,12 @@ fn invalid_alias_attribute() { Test::new() .justfile("[private]\n[linux]\nalias t := test\n\ntest:\n") .stderr( - " - error: Alias `t` has invalid attribute `linux` - ——▶ justfile:3:7 - │ - 3 │ alias t := test - │ ^ - ", + r"Error: Alias `t` has invalid attribute `linux` + ╭─[ justfile:3:7 ] + │ + 3 │ alias t := test +───╯ +", ) .failure(); } @@ -21,13 +20,12 @@ fn expected_keyword() { Test::new() .justfile("foo := if '' == '' { '' } arlo { '' }") .stderr( - " - error: Expected keyword `else` but found identifier `arlo` - ——▶ justfile:1:27 - │ - 1 │ foo := if '' == '' { '' } arlo { '' } - │ ^^^^ - ", + r"Error: Expected keyword `else` but found identifier `arlo` + ╭─[ justfile:1:27 ] + │ + 1 │ foo := if '' == '' { '' } arlo { '' } +───╯ +", ) .failure(); } @@ -37,13 +35,12 @@ fn unexpected_character() { Test::new() .justfile("&~") .stderr( - " - error: Expected character `&` - ——▶ justfile:1:2 - │ - 1 │ &~ - │ ^ - ", + r"Error: Expected character `&` + ╭─[ justfile:1:2 ] + │ + 1 │ &~ +───╯ +", ) .failure(); } @@ -68,12 +65,11 @@ fn file_path_is_indented_if_justfile_is_long() { Test::new() .justfile("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nfoo") .stderr( - " -error: Expected '*', ':', '$', identifier, or '+', but found end of file - ——▶ justfile:20:4 - │ -20 │ foo - │ ^ + r"Error: Expected '*', ':', '$', identifier, or '+', but found end of file + ╭─[ justfile:20:4 ] + │ + 20 │ foo +────╯ ", ) .failure(); @@ -85,12 +81,11 @@ fn file_paths_are_relative() { .justfile("import 'foo/bar.just'") .write("foo/bar.just", "baz") .stderr(format!( - " -error: Expected '*', ':', '$', identifier, or '+', but found end of file - ——▶ foo{MAIN_SEPARATOR}bar.just:1:4 - │ -1 │ baz - │ ^ + "Error: Expected '*', ':', '$', identifier, or '+', but found end of file + ╭─[ foo{MAIN_SEPARATOR}bar.just:1:4 ] + │ + 1 │ baz +───╯ ", )) .failure(); @@ -107,11 +102,11 @@ fn file_paths_not_in_subdir_are_absolute() { .no_justfile() .args(["--justfile", "foo/justfile"]) .stderr_regex( - r"error: Expected '\*', ':', '\$', identifier, or '\+', but found end of file - ——▶ /.*/bar.just:1:4 - │ -1 │ baz - │ \^ + r"Error: Expected '\*', ':', '\$', identifier, or '\+', but found end of file + ╭─\[ .+bar\.just:1:4 \] + │ + 1 │ baz +───╯ ", ) .failure(); @@ -123,12 +118,11 @@ fn redefinition_errors_properly_swap_types() { .write("foo.just", "foo:") .justfile("foo:\n echo foo\n\nmod foo 'foo.just'") .stderr( - " -error: Recipe `foo` defined on line 1 is redefined as a module on line 4 - ——▶ justfile:4:5 - │ -4 │ mod foo 'foo.just' - │ ^^^ + r"Error: Recipe `foo` defined on line 1 is redefined as a module on line 4 + ╭─[ justfile:4:5 ] + │ + 4 │ mod foo 'foo.just' +───╯ ", ) .failure(); diff --git a/tests/fallback.rs b/tests/fallback.rs index 7b721ae5e7..519a47ae26 100644 --- a/tests/fallback.rs +++ b/tests/fallback.rs @@ -144,13 +144,12 @@ fn print_error_from_parent_if_recipe_not_found_in_current() { .args(["foo"]) .current_dir("bar") .stderr( - " - error: Variable `bar` not defined - ——▶ justfile:2:9 - │ - 2 │ echo {{bar}} - │ ^^^ - ", + r"Error: Variable `bar` not defined + ╭─[ justfile:2:9 ] + │ + 2 │ echo {{bar}} +───╯ +", ) .failure(); } diff --git a/tests/format_string.rs b/tests/format_string.rs index 8c44c6b8cd..973bf2a339 100644 --- a/tests/format_string.rs +++ b/tests/format_string.rs @@ -148,13 +148,12 @@ fn unclosed() { Test::new() .justfile("foo := f'FOO{{") .stderr( - " - error: Expected backtick, identifier, '(', '/', or string, but found end of file - ——▶ justfile:1:15 - │ - 1 │ foo := f'FOO{{ - │ ^ - ", + r"Error: Expected backtick, identifier, '(', '/', or string, but found end of file + ╭─[ justfile:1:15 ] + │ + 1 │ foo := f'FOO{{ +───╯ +", ) .failure(); } @@ -237,13 +236,12 @@ fn escaped_delimiter_in_double_quoted_format_string() { ) .args(["--evaluate", "foo"]) .stderr( - r#" - error: `\{` is not a valid escape sequence - ——▶ justfile:1:9 - │ - 1 │ foo := f"\{{{{" - │ ^^^^^^^ - "#, + r#"Error: `\{` is not a valid escape sequence + ╭─[ justfile:1:9 ] + │ + 1 │ foo := f"\{{{{" +───╯ +"#, ) .failure(); } @@ -341,13 +339,12 @@ fn undefined_variable_error() { ", ) .stderr( - " - error: Variable `bar` not defined - ——▶ justfile:1:12 - │ - 1 │ foo := f'{{bar}}' - │ ^^^ - ", + r"Error: Variable `bar` not defined + ╭─[ justfile:1:12 ] + │ + 1 │ foo := f'{{bar}}' +───╯ +", ) .failure(); } diff --git a/tests/functions.rs b/tests/functions.rs index c7d0bf751c..2553d7e84a 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -771,13 +771,12 @@ fn join_argument_count_error() { .justfile("x := join('a')") .args(["--evaluate"]) .stderr( - " - error: Function `join` called with 1 argument but takes 2 or more - ——▶ justfile:1:6 - │ - 1 │ x := join(\'a\') - │ ^^^^ - ", + r"Error: Function `join` called with 1 argument but takes 2 or more + ╭─[ justfile:1:6 ] + │ + 1 │ x := join('a') +───╯ +", ) .failure(); } @@ -993,13 +992,12 @@ fn shell_no_argument() { .justfile("var := shell()") .args(["--evaluate"]) .stderr( - " - error: Function `shell` called with 0 arguments but takes 1 or more - ——▶ justfile:1:8 - │ - 1 │ var := shell() - │ ^^^^^ - ", + r"Error: Function `shell` called with 0 arguments but takes 1 or more + ╭─[ justfile:1:8 ] + │ + 1 │ var := shell() +───╯ +", ) .failure(); } @@ -1278,13 +1276,12 @@ fn unary_argument_count_mismamatch_error_message() { .justfile("x := datetime()") .args(["--evaluate"]) .stderr( - " - error: Function `datetime` called with 0 arguments but takes 1 - ——▶ justfile:1:6 - │ - 1 │ x := datetime() - │ ^^^^^^^^ - ", + r"Error: Function `datetime` called with 0 arguments but takes 1 + ╭─[ justfile:1:6 ] + │ + 1 │ x := datetime() +───╯ +", ) .failure(); } diff --git a/tests/ignore_comments.rs b/tests/ignore_comments.rs index e598bc3ac4..8a81907c90 100644 --- a/tests/ignore_comments.rs +++ b/tests/ignore_comments.rs @@ -123,13 +123,12 @@ fn comments_still_must_be_parsable_when_ignored() { ", ) .stderr( - " - error: Expected '&&', '||', '}}', '(', '+', or '/', but found identifier - ——▶ justfile:4:12 - │ - 4 │ # {{ foo bar }} - │ ^^^ - ", + r"Error: Expected '&&', '||', '}}', '(', '+', or '/', but found identifier + ╭─[ justfile:4:12 ] + │ + 4 │ # {{ foo bar }} +───╯ +", ) .failure(); } diff --git a/tests/imports.rs b/tests/imports.rs index fd1fbb6aeb..dcaed69aff 100644 --- a/tests/imports.rs +++ b/tests/imports.rs @@ -149,13 +149,12 @@ fn include_error() { Test::new() .justfile("!include foo") .stderr( - " - error: The `!include` directive has been stabilized as `import` - ——▶ justfile:1:1 - │ - 1 │ !include foo - │ ^ - ", + r"Error: The `!include` directive has been stabilized as `import` + ╭─[ justfile:1:1 ] + │ + 1 │ !include foo +───╯ +", ) .failure(); } diff --git a/tests/interpolation.rs b/tests/interpolation.rs index 81b7a55c33..246c6e5d6a 100644 --- a/tests/interpolation.rs +++ b/tests/interpolation.rs @@ -58,13 +58,12 @@ fn comment_in_interopolation() { ", ) .stderr( - " - error: Expected backtick, identifier, '(', '/', or string, but found comment - ——▶ justfile:2:11 - │ - 2 │ echo {{ # hello - │ ^^^^^^^ - ", + r"Error: Expected backtick, identifier, '(', '/', or string, but found comment + ╭─[ justfile:2:11 ] + │ + 2 │ echo {{ # hello +───╯ +", ) .failure(); } diff --git a/tests/misc.rs b/tests/misc.rs index 0080f8e806..ffb3f3859c 100644 --- a/tests/misc.rs +++ b/tests/misc.rs @@ -115,13 +115,12 @@ fn bad_setting() { ", ) .stderr( - " - error: Unknown setting `foo` - ——▶ justfile:1:5 - │ - 1 │ set foo - │ ^^^ - ", + r"Error: Unknown setting `foo` + ╭─[ justfile:1:5 ] + │ + 1 │ set foo +───╯ +", ) .failure(); } @@ -135,13 +134,12 @@ fn bad_setting_with_keyword_name() { ", ) .stderr( - " - error: Unknown setting `if` - ——▶ justfile:1:5 - │ - 1 │ set if := 'foo' - │ ^^ - ", + r"Error: Unknown setting `if` + ╭─[ justfile:1:5 ] + │ + 1 │ set if := 'foo' +───╯ +", ) .failure(); } @@ -161,13 +159,12 @@ fn duplicate_alias() { Test::new() .justfile("alias foo := bar\nalias foo := baz\n") .stderr( - " - error: Alias `foo` first defined on line 1 is redefined on line 2 - ——▶ justfile:2:7 - │ - 2 │ alias foo := baz - │ ^^^ - ", + r"Error: Alias `foo` first defined on line 1 is redefined on line 2 + ╭─[ justfile:2:7 ] + │ + 2 │ alias foo := baz +───╯ +", ) .failure(); } @@ -177,13 +174,12 @@ fn unknown_alias_target() { Test::new() .justfile("alias foo := bar\n") .stderr( - " - error: Alias `foo` has an unknown target `bar` - ——▶ justfile:1:7 - │ - 1 │ alias foo := bar - │ ^^^ - ", + r"Error: Alias `foo` has an unknown target `bar` + ╭─[ justfile:1:7 ] + │ + 1 │ alias foo := bar +───╯ +", ) .failure(); } @@ -193,13 +189,12 @@ fn alias_shadows_recipe() { Test::new() .justfile("bar:\n echo bar\nalias foo := bar\nfoo:\n echo foo") .stderr( - " - error: Alias `foo` defined on line 3 is redefined as a recipe on line 4 - ——▶ justfile:4:1 - │ - 4 │ foo: - │ ^^^ - ", + r"Error: Alias `foo` defined on line 3 is redefined as a recipe on line 4 + ╭─[ justfile:4:1 ] + │ + 4 │ foo: +───╯ +", ) .failure(); } @@ -302,13 +297,12 @@ fn unknown_dependency() { Test::new() .justfile("bar:\nhello:\nfoo: bar baaaaaaaz hello") .stderr( - " - error: Recipe `foo` has unknown dependency `baaaaaaaz` - ——▶ justfile:3:10 - │ - 3 │ foo: bar baaaaaaaz hello - │ ^^^^^^^^^ - ", + r"Error: Recipe `foo` has unknown dependency `baaaaaaaz` + ╭─[ justfile:3:10 ] + │ + 3 │ foo: bar baaaaaaaz hello +───╯ +", ) .failure(); } @@ -736,11 +730,11 @@ fn line_error_spacing() { ", ) .stderr( - "error: Unknown start of token '^' - ——▶ justfile:10:1 - │ -10 │ ^^^ - │ ^ + r"Error: Unknown start of token '^' + ╭─[ justfile:10:1 ] + │ + 10 │ ^^^ +────╯ ", ) .failure(); @@ -952,12 +946,12 @@ fn mixed_whitespace() { Test::new() .justfile("bar:\n\t echo hello") .stderr( - "error: Found a mix of tabs and spaces in leading whitespace: `␉␠` + r"Error: Found a mix of tabs and spaces in leading whitespace: `␉␠` Leading whitespace may consist of tabs or spaces, but not both - ——▶ justfile:2:1 - │ -2 │ echo hello - │ ^^^^^ + ╭─[ justfile:2:1 ] + │ + 2 │ echo hello +───╯ ", ) .failure(); @@ -968,11 +962,11 @@ fn extra_leading_whitespace() { Test::new() .justfile("bar:\n\t\techo hello\n\t\t\techo goodbye") .stderr( - "error: Recipe line has extra leading whitespace - ——▶ justfile:3:3 - │ -3 │ echo goodbye - │ ^^^^^^^^^^^^^^^^ + r"Error: Recipe line has extra leading whitespace + ╭─[ justfile:3:3 ] + │ + 3 │ echo goodbye +───╯ ", ) .failure(); @@ -982,15 +976,12 @@ fn extra_leading_whitespace() { fn inconsistent_leading_whitespace() { Test::new() .justfile("bar:\n\t\techo hello\n\t echo goodbye") - .stderr( - "error: Recipe line has inconsistent leading whitespace. \ - Recipe started with `␉␉` but found line with `␉␠` - ——▶ justfile:3:1 - │ -3 │ echo goodbye - │ ^^^^^ -", - ) + .stderr(r"Error: Recipe line has inconsistent leading whitespace. Recipe started with `␉␉` but found line with `␉␠` + ╭─[ justfile:3:1 ] + │ + 3 │ echo goodbye +───╯ +") .failure(); } @@ -999,11 +990,11 @@ fn required_after_default() { Test::new() .justfile("bar:\nhello baz arg='foo' bar:") .stderr( - "error: Non-default parameter `bar` follows default parameter - ——▶ justfile:2:21 - │ -2 │ hello baz arg='foo' bar: - │ ^^^ + r"Error: Non-default parameter `bar` follows default parameter + ╭─[ justfile:2:21 ] + │ + 2 │ hello baz arg='foo' bar: +───╯ ", ) .failure(); @@ -1014,11 +1005,11 @@ fn required_after_plus_variadic() { Test::new() .justfile("bar:\nhello baz +arg bar:") .stderr( - "error: Parameter `bar` follows variadic parameter - ——▶ justfile:2:16 - │ -2 │ hello baz +arg bar: - │ ^^^ + r"Error: Parameter `bar` follows variadic parameter + ╭─[ justfile:2:16 ] + │ + 2 │ hello baz +arg bar: +───╯ ", ) .failure(); @@ -1029,11 +1020,11 @@ fn required_after_star_variadic() { Test::new() .justfile("bar:\nhello baz *arg bar:") .stderr( - "error: Parameter `bar` follows variadic parameter - ——▶ justfile:2:16 - │ -2 │ hello baz *arg bar: - │ ^^^ + r"Error: Parameter `bar` follows variadic parameter + ╭─[ justfile:2:16 ] + │ + 2 │ hello baz *arg bar: +───╯ ", ) .failure(); @@ -1498,11 +1489,11 @@ fn unknown_function_in_assignment() { bar:"#, ) .stderr( - r#"error: Call to unknown function `foo` - ——▶ justfile:1:8 - │ -1 │ foo := foo() + "hello" - │ ^^^ + r#"Error: Call to unknown function `foo` + ╭─[ justfile:1:8 ] + │ + 1 │ foo := foo() + "hello" +───╯ "#, ) .failure(); @@ -1519,11 +1510,11 @@ fn dependency_takes_arguments_exact() { ", ) .stderr( - "error: Dependency `a` got 0 arguments but takes 1 argument - ——▶ justfile:2:4 - │ -2 │ b: a - │ ^ + r"Error: Dependency `a` got 0 arguments but takes 1 argument + ╭─[ justfile:2:4 ] + │ + 2 │ b: a +───╯ ", ) .failure(); @@ -1540,11 +1531,11 @@ fn dependency_takes_arguments_at_least() { ", ) .stderr( - "error: Dependency `a` got 0 arguments but takes at least 1 argument - ——▶ justfile:2:4 - │ -2 │ b: a - │ ^ + r"Error: Dependency `a` got 0 arguments but takes at least 1 argument + ╭─[ justfile:2:4 ] + │ + 2 │ b: a +───╯ ", ) .failure(); @@ -1561,11 +1552,11 @@ fn dependency_takes_arguments_at_most() { ", ) .stderr( - "error: Dependency `a` got 3 arguments but takes at most 2 arguments - ——▶ justfile:2:5 - │ -2 │ b: (a '0' '1' '2') - │ ^ + r"Error: Dependency `a` got 3 arguments but takes at most 2 arguments + ╭─[ justfile:2:5 ] + │ + 2 │ b: (a '0' '1' '2') +───╯ ", ) .failure(); @@ -1577,11 +1568,11 @@ fn duplicate_parameter() { .arg("a") .justfile("a foo foo:") .stderr( - "error: Recipe `a` has duplicate parameter `foo` - ——▶ justfile:1:7 - │ -1 │ a foo foo: - │ ^^^ + r"Error: Recipe `a` has duplicate parameter `foo` + ╭─[ justfile:1:7 ] + │ + 1 │ a foo foo: +───╯ ", ) .failure(); @@ -1593,11 +1584,11 @@ fn duplicate_recipe() { .arg("b") .justfile("b:\nb:") .stderr( - "error: Recipe `b` first defined on line 1 is redefined on line 2 - ——▶ justfile:2:1 - │ -2 │ b: - │ ^ + r"Error: Recipe `b` first defined on line 1 is redefined on line 2 + ╭─[ justfile:2:1 ] + │ + 2 │ b: +───╯ ", ) .failure(); @@ -1609,11 +1600,11 @@ fn duplicate_variable() { .arg("foo") .justfile("a := 'hello'\na := 'hello'\nfoo:") .stderr( - "error: Variable `a` has multiple definitions - ——▶ justfile:2:1 - │ -2 │ a := 'hello' - │ ^ + r"Error: Variable `a` has multiple definitions + ╭─[ justfile:2:1 ] + │ + 2 │ a := 'hello' +───╯ ", ) .failure(); @@ -1624,15 +1615,12 @@ fn unexpected_token_in_dependency_position() { Test::new() .arg("foo") .justfile("foo: 'bar'") - .stderr( - "error: Expected '&&', comment, end of file, end of line, \ - identifier, or '(', but found string - ——▶ justfile:1:6 - │ -1 │ foo: 'bar' - │ ^^^^^ -", - ) + .stderr(r"Error: Expected '&&', comment, end of file, end of line, identifier, or '(', but found string + ╭─[ justfile:1:6 ] + │ + 1 │ foo: 'bar' +───╯ +") .failure(); } @@ -1642,11 +1630,11 @@ fn unexpected_token_after_name() { .arg("foo") .justfile("foo 'bar'") .stderr( - "error: Expected '*', ':', '$', identifier, or '+', but found string - ——▶ justfile:1:5 - │ -1 │ foo 'bar' - │ ^^^^^ + r"Error: Expected '*', ':', '$', identifier, or '+', but found string + ╭─[ justfile:1:5 ] + │ + 1 │ foo 'bar' +───╯ ", ) .failure(); @@ -1658,11 +1646,11 @@ fn self_dependency() { .arg("a") .justfile("a: a") .stderr( - "error: Recipe `a` depends on itself - ——▶ justfile:1:4 - │ -1 │ a: a - │ ^ + r"Error: Recipe `a` depends on itself + ╭─[ justfile:1:4 ] + │ + 1 │ a: a +───╯ ", ) .failure(); @@ -1674,11 +1662,11 @@ fn long_circular_recipe_dependency() { .arg("a") .justfile("a: b\nb: c\nc: d\nd: a") .stderr( - "error: Recipe `d` has circular dependency `a -> b -> c -> d -> a` - ——▶ justfile:4:4 - │ -4 │ d: a - │ ^ + r"Error: Recipe `d` has circular dependency `a -> b -> c -> d -> a` + ╭─[ justfile:4:4 ] + │ + 4 │ d: a +───╯ ", ) .failure(); @@ -1690,11 +1678,11 @@ fn variable_self_dependency() { .arg("a") .justfile("z := z\na:") .stderr( - "error: Variable `z` is defined in terms of itself - ——▶ justfile:1:1 - │ -1 │ z := z - │ ^ + r"Error: Variable `z` is defined in terms of itself + ╭─[ justfile:1:1 ] + │ + 1 │ z := z +───╯ ", ) .failure(); @@ -1706,11 +1694,11 @@ fn variable_circular_dependency() { .arg("a") .justfile("x := y\ny := z\nz := x\na:") .stderr( - "error: Variable `x` depends on its own value: `x -> y -> z -> x` - ——▶ justfile:1:1 - │ -1 │ x := y - │ ^ + r"Error: Variable `x` depends on its own value: `x -> y -> z -> x` + ╭─[ justfile:1:1 ] + │ + 1 │ x := y +───╯ ", ) .failure(); @@ -1730,11 +1718,11 @@ fn variable_circular_dependency_with_additional_variable() { ", ) .stderr( - "error: Variable `x` depends on its own value: `x -> y -> x` - ——▶ justfile:2:1 - │ -2 │ x := y - │ ^ + r"Error: Variable `x` depends on its own value: `x -> y -> x` + ╭─[ justfile:2:1 ] + │ + 2 │ x := y +───╯ ", ) .failure(); @@ -1903,11 +1891,11 @@ foo *a +b: ", ) .stderr( - "error: Expected \':\' or \'=\', but found \'+\' - ——▶ justfile:1:8 - │ -1 │ foo *a +b: - │ ^ + r"Error: Expected ':' or '=', but found '+' + ╭─[ justfile:1:8 ] + │ + 1 │ foo *a +b: +───╯ ", ) .failure(); @@ -1923,11 +1911,11 @@ foo +a *b: ", ) .stderr( - "error: Expected \':\' or \'=\', but found \'*\' - ——▶ justfile:1:8 - │ -1 │ foo +a *b: - │ ^ + r"Error: Expected ':' or '=', but found '*' + ╭─[ justfile:1:8 ] + │ + 1 │ foo +a *b: +───╯ ", ) .failure(); @@ -1973,11 +1961,11 @@ a: x y ", ) .stderr( - "error: Recipe `a` has unknown dependency `y` - ——▶ justfile:3:6 - │ -3 │ a: x y - │ ^ + r"Error: Recipe `a` has unknown dependency `y` + ╭─[ justfile:3:6 ] + │ + 3 │ a: x y +───╯ ", ) .failure(); @@ -2091,11 +2079,11 @@ X := "\'" "#, ) .stderr( - r#"error: `\'` is not a valid escape sequence - ——▶ justfile:1:6 - │ -1 │ X := "\'" - │ ^^^^ + r#"Error: `\'` is not a valid escape sequence + ╭─[ justfile:1:6 ] + │ + 1 │ X := "\'" +───╯ "#, ) .failure(); @@ -2110,11 +2098,11 @@ fn unknown_variable_in_default() { ", ) .stderr( - r"error: Variable `bar` not defined - ——▶ justfile:1:7 - │ -1 │ foo x=bar: - │ ^^^ + r"Error: Variable `bar` not defined + ╭─[ justfile:1:7 ] + │ + 1 │ foo x=bar: +───╯ ", ) .failure(); @@ -2129,11 +2117,11 @@ foo x=bar(): ", ) .stderr( - r"error: Call to unknown function `bar` - ——▶ justfile:1:7 - │ -1 │ foo x=bar(): - │ ^^^ + r"Error: Call to unknown function `bar` + ╭─[ justfile:1:7 ] + │ + 1 │ foo x=bar(): +───╯ ", ) .failure(); @@ -2206,13 +2194,12 @@ fn unterminated_interpolation_eol() { ", ) .stderr( - r" - error: Unterminated interpolation - ——▶ justfile:2:8 - │ - 2 │ echo {{ - │ ^^ - ", + r"Error: Unterminated interpolation + ╭─[ justfile:2:8 ] + │ + 2 │ echo {{ +───╯ +", ) .failure(); } @@ -2227,13 +2214,12 @@ fn unterminated_interpolation_eof() { ", ) .stderr( - r" - error: Unterminated interpolation - ——▶ justfile:2:8 - │ - 2 │ echo {{ - │ ^^ - ", + r"Error: Unterminated interpolation + ╭─[ justfile:2:8 ] + │ + 2 │ echo {{ +───╯ +", ) .failure(); } @@ -2247,13 +2233,12 @@ assembly_source_files = %(wildcard src/arch/$(arch)/*.s) ", ) .stderr( - r" - error: Unknown start of token '%' - ——▶ justfile:1:25 - │ - 1 │ assembly_source_files = %(wildcard src/arch/$(arch)/*.s) - │ ^ - ", + r"Error: Unknown start of token '%' + ╭─[ justfile:1:25 ] + │ + 1 │ assembly_source_files = %(wildcard src/arch/$(arch)/*.s) +───╯ +", ) .failure(); } @@ -2267,12 +2252,11 @@ fn unknown_start_of_token_invisible_unicode() { ", ) .stderr( - " -error: Unknown start of token '\u{200b}' (U+200B) - ——▶ justfile:1:1 - │ -1 │ \u{200b}foo := 'bar' - │ ^ + "Error: Unknown start of token '\u{200b}' (U+200B) + ╭─[ justfile:1:1 ] + │ + 1 │ \u{200b}foo := 'bar' +───╯ ", ) .failure(); @@ -2283,16 +2267,15 @@ fn unknown_start_of_token_ascii_control_char() { Test::new() .justfile( " -\0foo := 'bar' +\u{0000}foo := 'bar' ", ) .stderr( - " -error: Unknown start of token '\0' (U+0000) - ——▶ justfile:1:1 - │ -1 │ \0foo := 'bar' - │ ^ + "Error: Unknown start of token '\0' (U+0000) + ╭─[ justfile:1:1 ] + │ + 1 │ \0foo := 'bar' +───╯ ", ) .failure(); @@ -2419,13 +2402,12 @@ fn old_equals_assignment_syntax_produces_error() { ", ) .stderr( - " - error: Expected '*', ':', '$', identifier, or '+', but found '=' - ——▶ justfile:1:5 - │ - 1 │ foo = 'bar' - │ ^ - ", + r"Error: Expected '*', ':', '$', identifier, or '+', but found '=' + ╭─[ justfile:1:5 ] + │ + 1 │ foo = 'bar' +───╯ +", ) .failure(); } diff --git a/tests/modules.rs b/tests/modules.rs index d692c6d65a..c50bf59855 100644 --- a/tests/modules.rs +++ b/tests/modules.rs @@ -204,13 +204,12 @@ foo: .arg("foo") .arg("foo") .stderr( - " - error: Recipe `foo` first defined on line 1 is redefined on line 2 - ——▶ foo.just:2:1 - │ - 2 │ foo: - │ ^^^ - ", + r"Error: Recipe `foo` first defined on line 1 is redefined on line 2 + ╭─[ foo.just:2:1 ] + │ + 2 │ foo: +───╯ +", ) .failure(); } @@ -226,13 +225,12 @@ fn modules_conflict_with_recipes() { ", ) .stderr( - " - error: Module `foo` defined on line 1 is redefined as a recipe on line 2 - ——▶ justfile:2:1 - │ - 2 │ foo: - │ ^^^ - ", + r"Error: Module `foo` defined on line 1 is redefined as a recipe on line 2 + ╭─[ justfile:2:1 ] + │ + 2 │ foo: +───╯ +", ) .failure(); } @@ -249,13 +247,12 @@ fn modules_conflict_with_aliases() { ", ) .stderr( - " - error: Module `foo` defined on line 1 is redefined as an alias on line 3 - ——▶ justfile:3:7 - │ - 3 │ alias foo := bar - │ ^^^ - ", + r"Error: Module `foo` defined on line 1 is redefined as an alias on line 3 + ╭─[ justfile:3:7 ] + │ + 3 │ alias foo := bar +───╯ +", ) .failure(); } @@ -273,13 +270,12 @@ fn modules_conflict_with_other_modules() { ", ) .stderr( - " - error: Module `foo` first defined on line 1 is redefined on line 2 - ——▶ justfile:2:5 - │ - 2 │ mod foo - │ ^^^ - ", + r"Error: Module `foo` first defined on line 1 is redefined on line 2 + ╭─[ justfile:2:5 ] + │ + 2 │ mod foo +───╯ +", ) .failure(); } @@ -1019,7 +1015,14 @@ fn bad_module_attribute_fails() { ) .test_round_trip(false) .arg("--list") - .stderr("error: Module `foo` has invalid attribute `no-cd`\n ——▶ justfile:2:5\n │\n2 │ mod foo\n │ ^^^\n") + .stderr( + r"Error: Module `foo` has invalid attribute `no-cd` + ╭─[ justfile:2:5 ] + │ + 2 │ mod foo +───╯ +", + ) .failure(); } diff --git a/tests/newline_escape.rs b/tests/newline_escape.rs index 29f51612e5..07c746de22 100644 --- a/tests/newline_escape.rs +++ b/tests/newline_escape.rs @@ -69,13 +69,12 @@ fn newline_escape_deps_invalid_esc() { ", ) .stderr( - " - error: `\\ ` is not a valid escape sequence - ——▶ justfile:1:11 - │ - 1 │ default: a\\ b - │ ^ - ", + r"Error: `\ ` is not a valid escape sequence + ╭─[ justfile:1:11 ] + │ + 1 │ default: a\ b +───╯ +", ) .failure(); } @@ -88,13 +87,12 @@ fn newline_escape_unpaired_linefeed() { default:\\\ra", ) .stderr( - " - error: Unpaired carriage return - ——▶ justfile:1:9 - │ - 1 │ default:\\\ra - │ ^ - ", + r"Error: Unpaired carriage return + ╭─[ justfile:1:9 ] + │ + 1 │ default:\ +───╯ +", ) .failure(); } diff --git a/tests/no_exit_message.rs b/tests/no_exit_message.rs index ff79d9a405..a1b8062d91 100644 --- a/tests/no_exit_message.rs +++ b/tests/no_exit_message.rs @@ -65,13 +65,12 @@ fn unknown_attribute() { ", ) .stderr( - " - error: Unknown attribute `unknown-attribute` - ——▶ justfile:2:2 - │ - 2 │ [unknown-attribute] - │ ^^^^^^^^^^^^^^^^^ - ", + r"Error: Unknown attribute `unknown-attribute` + ╭─[ justfile:2:2 ] + │ + 2 │ [unknown-attribute] +───╯ +", ) .failure(); } @@ -88,13 +87,12 @@ fn empty_attribute() { ", ) .stderr( - " - error: Expected identifier, but found ']' - ——▶ justfile:2:2 - │ - 2 │ [] - │ ^ - ", + r"Error: Expected identifier, but found ']' + ╭─[ justfile:2:2 ] + │ + 2 │ [] +───╯ +", ) .failure(); } @@ -111,13 +109,12 @@ fn extraneous_attribute_before_comment() { ", ) .stderr( - " - error: Extraneous attribute - ——▶ justfile:1:1 - │ - 1 │ [no-exit-message] - │ ^ - ", + r"Error: Extraneous attribute + ╭─[ justfile:1:1 ] + │ + 1 │ [no-exit-message] +───╯ +", ) .failure(); } @@ -134,13 +131,12 @@ fn extraneous_attribute_before_empty_line() { ", ) .stderr( - " - error: Extraneous attribute - ——▶ justfile:1:1 - │ - 1 │ [no-exit-message] - │ ^ - ", + r"Error: Extraneous attribute + ╭─[ justfile:1:1 ] + │ + 1 │ [no-exit-message] +───╯ +", ) .failure(); } @@ -252,13 +248,12 @@ fn exit_message_and_no_exit_message_compile_forbidden() { ", ) .stderr( - " - error: Recipe `bar` has both `[exit-message]` and `[no-exit-message]` attributes - ——▶ justfile:2:1 - │ - 2 │ bar: - │ ^^^ - ", + r"Error: Recipe `bar` has both `[exit-message]` and `[no-exit-message]` attributes + ╭─[ justfile:2:1 ] + │ + 2 │ bar: +───╯ +", ) .failure(); } diff --git a/tests/options.rs b/tests/options.rs index e9527ce9a1..294a242ad5 100644 --- a/tests/options.rs +++ b/tests/options.rs @@ -11,13 +11,12 @@ fn long_options_may_not_be_empty() { ", ) .stderr( - " - error: Option name for parameter `bar` is empty - ——▶ justfile:1:18 - │ - 1 │ [arg('bar', long='')] - │ ^^ - ", + r"Error: Option name for parameter `bar` is empty + ╭─[ justfile:1:18 ] + │ + 1 │ [arg('bar', long='')] +───╯ +", ) .failure(); } @@ -33,13 +32,12 @@ fn short_options_may_not_be_empty() { ", ) .stderr( - " - error: Option name for parameter `bar` is empty - ——▶ justfile:1:19 - │ - 1 │ [arg('bar', short='')] - │ ^^ - ", + r"Error: Option name for parameter `bar` is empty + ╭─[ justfile:1:19 ] + │ + 1 │ [arg('bar', short='')] +───╯ +", ) .failure(); } @@ -55,13 +53,12 @@ fn short_options_may_not_have_multiple_characters() { ", ) .stderr( - " - error: Short option name for parameter `bar` contains multiple characters - ——▶ justfile:1:19 - │ - 1 │ [arg('bar', short='abc')] - │ ^^^^^ - ", + r"Error: Short option name for parameter `bar` contains multiple characters + ╭─[ justfile:1:19 ] + │ + 1 │ [arg('bar', short='abc')] +───╯ +", ) .failure(); } @@ -170,13 +167,12 @@ fn duplicate_long_option_attributes_are_forbidden() { ", ) .stderr( - " - error: Recipe `foo` defines option `--bar` multiple times - ——▶ justfile:2:18 - │ - 2 │ [arg('baz', long='bar')] - │ ^^^^^ - ", + r"Error: Recipe `foo` defines option `--bar` multiple times + ╭─[ justfile:2:18 ] + │ + 2 │ [arg('baz', long='bar')] +───╯ +", ) .failure(); } @@ -195,13 +191,12 @@ fn defaulted_duplicate_long_option() { ", ) .stderr( - " - error: Recipe `foo` defines option `--bar` multiple times - ——▶ justfile:5:19 - │ - 5 │ [arg( 'bar', long)] - │ ^^^^ - ", + r"Error: Recipe `foo` defines option `--bar` multiple times + ╭─[ justfile:5:19 ] + │ + 5 │ [arg( 'bar', long)] +───╯ +", ) .failure(); } @@ -217,13 +212,12 @@ fn duplicate_short_option_attributes_are_forbidden() { ", ) .stderr( - " - error: Recipe `foo` defines option `-b` multiple times - ——▶ justfile:2:19 - │ - 2 │ [arg('baz', short='b')] - │ ^^^ - ", + r"Error: Recipe `foo` defines option `-b` multiple times + ╭─[ justfile:2:19 ] + │ + 2 │ [arg('baz', short='b')] +───╯ +", ) .failure(); } @@ -238,13 +232,12 @@ fn variadics_with_long_options_are_forbidden() { ", ) .stderr( - " - error: Variadic parameters may not be options - ——▶ justfile:2:6 - │ - 2 │ foo +bar: - │ ^^^ - ", + r"Error: Variadic parameters may not be options + ╭─[ justfile:2:6 ] + │ + 2 │ foo +bar: +───╯ +", ) .failure(); } @@ -259,13 +252,12 @@ fn variadics_with_short_options_are_forbidden() { ", ) .stderr( - " - error: Variadic parameters may not be options - ——▶ justfile:2:6 - │ - 2 │ foo +bar: - │ ^^^ - ", + r"Error: Variadic parameters may not be options + ╭─[ justfile:2:6 ] + │ + 2 │ foo +bar: +───╯ +", ) .failure(); } @@ -280,13 +272,12 @@ fn long_option_names_may_not_contain_equal_sign() { ", ) .stderr( - " - error: Option name for parameter `bar` contains equal sign - ——▶ justfile:1:18 - │ - 1 │ [arg('bar', long='bar=baz')] - │ ^^^^^^^^^ - ", + r"Error: Option name for parameter `bar` contains equal sign + ╭─[ justfile:1:18 ] + │ + 1 │ [arg('bar', long='bar=baz')] +───╯ +", ) .failure(); } @@ -301,13 +292,12 @@ fn short_option_names_may_not_contain_equal_sign() { ", ) .stderr( - " - error: Option name for parameter `bar` contains equal sign - ——▶ justfile:1:19 - │ - 1 │ [arg('bar', short='=')] - │ ^^^ - ", + r"Error: Option name for parameter `bar` contains equal sign + ╭─[ justfile:1:19 ] + │ + 1 │ [arg('bar', short='=')] +───╯ +", ) .failure(); } @@ -670,13 +660,12 @@ fn value_requires_long_or_short() { ) .args(["foo", "-b=hello"]) .stderr( - " - error: Argument attribute `value` only valid with `long` or `short` - ——▶ justfile:1:13 - │ - 1 │ [arg('bar', value='baz')] - │ ^^^^^ - ", + r"Error: Argument attribute `value` only valid with `long` or `short` + ╭─[ justfile:1:13 ] + │ + 1 │ [arg('bar', value='baz')] +───╯ +", ) .failure(); } diff --git a/tests/parameters.rs b/tests/parameters.rs index 519aeb9bf4..fc518f1a94 100644 --- a/tests/parameters.rs +++ b/tests/parameters.rs @@ -25,13 +25,12 @@ fn parameter_default_values_may_not_use_later_parameters() { ) .args(["foo", "bar"]) .stderr( - " - error: Variable `c` not defined - ——▶ justfile:1:10 - │ - 1 │ @foo a b=c c='': - │ ^ - ", + r"Error: Variable `c` not defined + ╭─[ justfile:1:10 ] + │ + 1 │ @foo a b=c c='': +───╯ +", ) .failure(); } diff --git a/tests/parser.rs b/tests/parser.rs index 85ff23178a..230464bd28 100644 --- a/tests/parser.rs +++ b/tests/parser.rs @@ -21,12 +21,11 @@ fn invalid_bang_operator() { ", ) .stderr( - r" -error: Expected character `=` or `~` - ——▶ justfile:1:13 - │ -1 │ x := if '' !! '' { '' } else { '' } - │ ^ + r"Error: Expected character `=` or `~` + ╭─[ justfile:1:13 ] + │ + 1 │ x := if '' !! '' { '' } else { '' } +───╯ ", ) .failure(); @@ -37,12 +36,11 @@ fn truncated_bang_operator() { Test::new() .justfile("x := if '' !") .stderr( - r" -error: Expected character `=` or `~` but found end-of-file - ——▶ justfile:1:13 - │ -1 │ x := if '' ! - │ ^ + r"Error: Expected character `=` or `~` but found end-of-file + ╭─[ justfile:1:13 ] + │ + 1 │ x := if '' ! +───╯ ", ) .failure(); diff --git a/tests/recursion_limit.rs b/tests/recursion_limit.rs index 042b38ed76..7f691dca2b 100644 --- a/tests/recursion_limit.rs +++ b/tests/recursion_limit.rs @@ -13,19 +13,17 @@ fn bugfix() { } #[cfg(not(windows))] -const RECURSION_LIMIT_REACHED: &str = " -error: Parsing recursion depth exceeded - ——▶ justfile:1:265 - │ -1 │ foo: (x (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( - │ ^ +const RECURSION_LIMIT_REACHED: &str = r"Error: Parsing recursion depth exceeded + ╭─[ justfile:1:265 ] + │ + 1 │ foo: (x (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +───╯ "; #[cfg(windows)] -const RECURSION_LIMIT_REACHED: &str = " -error: Parsing recursion depth exceeded - ——▶ justfile:1:57 - │ -1 │ foo: (x (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( - │ ^ +const RECURSION_LIMIT_REACHED: &str = r"Error: Parsing recursion depth exceeded + ╭─[ justfile:1:57 ] + │ + 1 │ foo: (x (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +───╯ "; diff --git a/tests/settings.rs b/tests/settings.rs index 73642b19b4..1353e76805 100644 --- a/tests/settings.rs +++ b/tests/settings.rs @@ -35,13 +35,12 @@ fn undefined_variable_in_working_directory() { ", ) .stderr( - " - error: Variable `foo` not defined - ——▶ justfile:1:26 - │ - 1 │ set working-directory := foo - │ ^^^ - ", + r"Error: Variable `foo` not defined + ╭─[ justfile:1:26 ] + │ + 1 │ set working-directory := foo +───╯ +", ) .failure(); } @@ -55,13 +54,12 @@ fn undefined_variable_in_dotenv_filename() { ", ) .stderr( - " - error: Variable `foo` not defined - ——▶ justfile:1:24 - │ - 1 │ set dotenv-filename := foo - │ ^^^ - ", + r"Error: Variable `foo` not defined + ╭─[ justfile:1:24 ] + │ + 1 │ set dotenv-filename := foo +───╯ +", ) .failure(); } @@ -75,13 +73,12 @@ fn undefined_variable_in_dotenv_path() { ", ) .stderr( - " - error: Variable `foo` not defined - ——▶ justfile:1:20 - │ - 1 │ set dotenv-path := foo - │ ^^^ - ", + r"Error: Variable `foo` not defined + ╭─[ justfile:1:20 ] + │ + 1 │ set dotenv-path := foo +───╯ +", ) .failure(); } @@ -95,13 +92,12 @@ fn undefined_variable_in_tempdir() { ", ) .stderr( - " - error: Variable `foo` not defined - ——▶ justfile:1:16 - │ - 1 │ set tempdir := foo - │ ^^^ - ", + r"Error: Variable `foo` not defined + ╭─[ justfile:1:16 ] + │ + 1 │ set tempdir := foo +───╯ +", ) .failure(); } @@ -115,13 +111,12 @@ fn undefined_variable_in_script_interpreter_command() { ", ) .stderr( - " - error: Variable `foo` not defined - ——▶ justfile:1:28 - │ - 1 │ set script-interpreter := [foo] - │ ^^^ - ", + r"Error: Variable `foo` not defined + ╭─[ justfile:1:28 ] + │ + 1 │ set script-interpreter := [foo] +───╯ +", ) .failure(); } @@ -135,13 +130,12 @@ fn undefined_variable_in_script_interpreter_argument() { ", ) .stderr( - " - error: Variable `bar` not defined - ——▶ justfile:1:35 - │ - 1 │ set script-interpreter := ['foo', bar] - │ ^^^ - ", + r"Error: Variable `bar` not defined + ╭─[ justfile:1:35 ] + │ + 1 │ set script-interpreter := ['foo', bar] +───╯ +", ) .failure(); } @@ -155,13 +149,12 @@ fn undefined_variable_in_shell_command() { ", ) .stderr( - " - error: Variable `foo` not defined - ——▶ justfile:1:15 - │ - 1 │ set shell := [foo] - │ ^^^ - ", + r"Error: Variable `foo` not defined + ╭─[ justfile:1:15 ] + │ + 1 │ set shell := [foo] +───╯ +", ) .failure(); } @@ -175,13 +168,12 @@ fn undefined_variable_in_shell_argument() { ", ) .stderr( - " - error: Variable `bar` not defined - ——▶ justfile:1:22 - │ - 1 │ set shell := ['foo', bar] - │ ^^^ - ", + r"Error: Variable `bar` not defined + ╭─[ justfile:1:22 ] + │ + 1 │ set shell := ['foo', bar] +───╯ +", ) .failure(); } @@ -195,13 +187,12 @@ fn undefined_variable_in_windows_shell_command() { ", ) .stderr( - " - error: Variable `foo` not defined - ——▶ justfile:1:23 - │ - 1 │ set windows-shell := [foo] - │ ^^^ - ", + r"Error: Variable `foo` not defined + ╭─[ justfile:1:23 ] + │ + 1 │ set windows-shell := [foo] +───╯ +", ) .failure(); } @@ -215,13 +206,12 @@ fn undefined_variable_in_windows_shell_argument() { ", ) .stderr( - " - error: Variable `bar` not defined - ——▶ justfile:1:30 - │ - 1 │ set windows-shell := ['foo', bar] - │ ^^^ - ", + r"Error: Variable `bar` not defined + ╭─[ justfile:1:30 ] + │ + 1 │ set windows-shell := ['foo', bar] +───╯ +", ) .failure(); } diff --git a/tests/shell_expansion.rs b/tests/shell_expansion.rs index 120708cf8e..9498dd5eff 100644 --- a/tests/shell_expansion.rs +++ b/tests/shell_expansion.rs @@ -22,15 +22,12 @@ fn shell_expanded_strings_must_not_have_whitespace() { x := x '$JUST_TEST_VARIABLE' ", ) - .stderr( - " - error: Expected '&&', '||', comment, end of file, end of line, '(', '+', or '/', but found string - ——▶ justfile:1:8 - │ - 1 │ x := x '$JUST_TEST_VARIABLE' - │ ^^^^^^^^^^^^^^^^^^^^^ - ", - ) + .stderr(r"Error: Expected '&&', '||', comment, end of file, end of line, '(', '+', or '/', but found string + ╭─[ justfile:1:8 ] + │ + 1 │ x := x '$JUST_TEST_VARIABLE' +───╯ +") .failure(); } @@ -44,14 +41,12 @@ fn shell_expanded_error_messages_highlight_string_token() { ) .env("JUST_TEST_VARIABLE", "FOO") .args(["--evaluate", "x"]) - .stderr( - " - error: Shell expansion failed: error looking key 'FOOOOOOOOOOOOOOOOOOOOOOOOOOOOO' up: environment variable not found - ——▶ justfile:1:7 - │ - 1 │ x := x'$FOOOOOOOOOOOOOOOOOOOOOOOOOOOOO' - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ") + .stderr(r"Error: Shell expansion failed: error looking key 'FOOOOOOOOOOOOOOOOOOOOOOOOOOOOO' up: environment variable not found + ╭─[ justfile:1:7 ] + │ + 1 │ x := x'$FOOOOOOOOOOOOOOOOOOOOOOOOOOOOO' +───╯ +") .failure(); } diff --git a/tests/show.rs b/tests/show.rs index b6d2bdf597..a10981938a 100644 --- a/tests/show.rs +++ b/tests/show.rs @@ -43,13 +43,12 @@ fn alias_show_missing_target() { .arg("f") .justfile("alias f := foo") .stderr( - " - error: Alias `f` has an unknown target `foo` - ——▶ justfile:1:7 - │ - 1 │ alias f := foo - │ ^ - ", + r"Error: Alias `f` has an unknown target `foo` + ╭─[ justfile:1:7 ] + │ + 1 │ alias f := foo +───╯ +", ) .failure(); } diff --git a/tests/slash_operator.rs b/tests/slash_operator.rs index 01593f1e20..408b7db732 100644 --- a/tests/slash_operator.rs +++ b/tests/slash_operator.rs @@ -46,13 +46,12 @@ fn no_rhs_once() { Test::new() .justfile("x := 'a' /") .stderr( - " - error: Expected backtick, identifier, '(', '/', or string, but found end of file - ——▶ justfile:1:11 - │ - 1 │ x := 'a' / - │ ^ - ", + r"Error: Expected backtick, identifier, '(', '/', or string, but found end of file + ╭─[ justfile:1:11 ] + │ + 1 │ x := 'a' / +───╯ +", ) .failure(); } @@ -67,13 +66,12 @@ fn default_un_parenthesized() { ", ) .stderr( - " - error: Expected '*', ':', '$', identifier, or '+', but found '/' - ——▶ justfile:1:11 - │ - 1 │ foo x='a' / 'b': - │ ^ - ", + r"Error: Expected '*', ':', '$', identifier, or '+', but found '/' + ╭─[ justfile:1:11 ] + │ + 1 │ foo x='a' / 'b': +───╯ +", ) .failure(); } @@ -88,13 +86,12 @@ fn no_lhs_un_parenthesized() { ", ) .stderr( - " - error: Expected backtick, identifier, '(', or string, but found '/' - ——▶ justfile:1:7 - │ - 1 │ foo x=/ 'a' / 'b': - │ ^ - ", + r"Error: Expected backtick, identifier, '(', or string, but found '/' + ╭─[ justfile:1:7 ] + │ + 1 │ foo x=/ 'a' / 'b': +───╯ +", ) .failure(); } diff --git a/tests/string.rs b/tests/string.rs index 2aaa243ae1..249d9fd55b 100644 --- a/tests/string.rs +++ b/tests/string.rs @@ -122,12 +122,12 @@ fn invalid_escape_sequence() { a:"#, ) .stderr( - "error: `\\q` is not a valid escape sequence - ——▶ justfile:1:6 - │ -1 │ x := \"\\q\" - │ ^^^^ -", + r#"Error: `\q` is not a valid escape sequence + ╭─[ justfile:1:6 ] + │ + 1 │ x := "\q" +───╯ +"#, ) .failure(); } @@ -147,11 +147,11 @@ a: ", ) .stderr( - "error: Variable `foo` not defined - ——▶ justfile:6:11 - │ -6 │ echo '{{foo}}' - │ ^^^ + r"Error: Variable `foo` not defined + ╭─[ justfile:6:11 ] + │ + 6 │ echo '{{foo}}' +───╯ ", ) .failure(); @@ -172,11 +172,11 @@ a: ", ) .stderr( - "error: Variable `bar` not defined - ——▶ justfile:3:13 - │ -3 │ whatever' + bar - │ ^^^ + r"Error: Variable `bar` not defined + ╭─[ justfile:3:13 ] + │ + 3 │ whatever' + bar +───╯ ", ) .failure(); @@ -222,11 +222,11 @@ a: "#, ) .stderr( - "error: Variable `b` not defined - ——▶ justfile:5:10 - │ -5 │ echo {{b}} - │ ^ + r"Error: Variable `b` not defined + ╭─[ justfile:5:10 ] + │ + 5 │ echo {{b}} +───╯ ", ) .failure(); @@ -242,13 +242,12 @@ fn unterminated_raw_string() { ", ) .stderr( - " - error: Unterminated string - ——▶ justfile:1:6 - │ - 1 │ a b= ': - │ ^ - ", + r"Error: Unterminated string + ╭─[ justfile:1:6 ] + │ + 1 │ a b= ': +───╯ +", ) .failure(); } @@ -263,13 +262,12 @@ fn unterminated_string() { "#, ) .stderr( - r#" - error: Unterminated string - ——▶ justfile:1:6 - │ - 1 │ a b= ": - │ ^ - "#, + r#"Error: Unterminated string + ╭─[ justfile:1:6 ] + │ + 1 │ a b= ": +───╯ +"#, ) .failure(); } @@ -284,13 +282,12 @@ fn unterminated_backtick() { ", ) .stderr( - r" - error: Unterminated backtick - ——▶ justfile:1:8 - │ - 1 │ foo a= `echo blaaaaaah: - │ ^ - ", + r"Error: Unterminated backtick + ╭─[ justfile:1:8 ] + │ + 1 │ foo a= `echo blaaaaaah: +───╯ +", ) .failure(); } @@ -305,13 +302,12 @@ fn unterminated_indented_raw_string() { ", ) .stderr( - " - error: Unterminated string - ——▶ justfile:1:6 - │ - 1 │ a b= ''': - │ ^^^ - ", + r"Error: Unterminated string + ╭─[ justfile:1:6 ] + │ + 1 │ a b= ''': +───╯ +", ) .failure(); } @@ -326,13 +322,12 @@ fn unterminated_indented_string() { "#, ) .stderr( - r#" - error: Unterminated string - ——▶ justfile:1:6 - │ - 1 │ a b= """: - │ ^^^ - "#, + r#"Error: Unterminated string + ╭─[ justfile:1:6 ] + │ + 1 │ a b= """: +───╯ +"#, ) .failure(); } @@ -347,13 +342,12 @@ fn unterminated_indented_backtick() { ", ) .stderr( - r" - error: Unterminated backtick - ——▶ justfile:1:8 - │ - 1 │ foo a= ```echo blaaaaaah: - │ ^^^ - ", + r"Error: Unterminated backtick + ╭─[ justfile:1:8 ] + │ + 1 │ foo a= ```echo blaaaaaah: +───╯ +", ) .failure(); } @@ -500,13 +494,12 @@ fn shebang_backtick() { ", ) .stderr( - " - error: Backticks may not start with `#!` - ——▶ justfile:1:6 - │ - 1 │ x := `#!/usr/bin/env sh` - │ ^^^^^^^^^^^^^^^^^^^ - ", + r"Error: Backticks may not start with `#!` + ╭─[ justfile:1:6 ] + │ + 1 │ x := `#!/usr/bin/env sh` +───╯ +", ) .failure(); } @@ -544,12 +537,11 @@ fn unicode_escape_no_braces() { .justfile("x := \"\\u1234\"") .args(["--evaluate", "x"]) .stderr( - r#" -error: expected unicode escape sequence delimiter `{` but found `1` - ——▶ justfile:1:6 - │ -1 │ x := "\u1234" - │ ^^^^^^^^ + r#"Error: expected unicode escape sequence delimiter `{` but found `1` + ╭─[ justfile:1:6 ] + │ + 1 │ x := "\u1234" +───╯ "#, ) .failure(); @@ -561,12 +553,11 @@ fn unicode_escape_empty() { .justfile("x := \"\\u{}\"") .args(["--evaluate", "x"]) .stderr( - r#" -error: unicode escape sequences must not be empty - ——▶ justfile:1:6 - │ -1 │ x := "\u{}" - │ ^^^^^^ + r#"Error: unicode escape sequences must not be empty + ╭─[ justfile:1:6 ] + │ + 1 │ x := "\u{}" +───╯ "#, ) .failure(); @@ -578,12 +569,11 @@ fn unicode_escape_requires_immediate_opening_brace() { .justfile("x := \"\\u {1f916}\"") .args(["--evaluate", "x"]) .stderr( - r#" -error: expected unicode escape sequence delimiter `{` but found ` ` - ——▶ justfile:1:6 - │ -1 │ x := "\u {1f916}" - │ ^^^^^^^^^^^^ + r#"Error: expected unicode escape sequence delimiter `{` but found ` ` + ╭─[ justfile:1:6 ] + │ + 1 │ x := "\u {1f916}" +───╯ "#, ) .failure(); @@ -596,11 +586,11 @@ fn unicode_escape_non_hex() { .args(["--evaluate", "x"]) .stderr( r#" -error: expected hex digit [0-9A-Fa-f] but found `o` - ——▶ justfile:1:6 - │ -1 │ x := "\u{foo}" - │ ^^^^^^^^^ +Error: expected hex digit [0-9A-Fa-f] but found `o` + ╭─[ justfile:1:6 ] + │ + 1 │ x := "\u{foo}" +───╯ "#, ) .failure(); @@ -611,15 +601,12 @@ fn unicode_escape_invalid_character() { Test::new() .justfile("x := \"\\u{BadBad}\"") .args(["--evaluate", "x"]) - .stderr( - r#" -error: unicode escape sequence value `BadBad` greater than maximum valid code point `10FFFF` - ——▶ justfile:1:6 - │ -1 │ x := "\u{BadBad}" - │ ^^^^^^^^^^^^ -"#, - ) + .stderr(r#"Error: unicode escape sequence value `BadBad` greater than maximum valid code point `10FFFF` + ╭─[ justfile:1:6 ] + │ + 1 │ x := "\u{BadBad}" +───╯ +"#) .failure(); } @@ -630,11 +617,11 @@ fn unicode_escape_too_long() { .args(["--evaluate", "x"]) .stderr( r#" -error: unicode escape sequence starting with `\u{FFFFFFF` longer than six hex digits - ——▶ justfile:1:6 - │ -1 │ x := "\u{FFFFFFFFFF}" - │ ^^^^^^^^^^^^^^^^ +Error: unicode escape sequence starting with `\u{FFFFFFF` longer than six hex digits + ╭─[ justfile:1:6 ] + │ + 1 │ x := "\u{FFFFFFFFFF}" +───╯ "#, ) .failure(); @@ -646,12 +633,11 @@ fn unicode_escape_unterminated() { .justfile("x := \"\\u{1f917\"") .args(["--evaluate", "x"]) .stderr( - r#" -error: unterminated unicode escape sequence - ——▶ justfile:1:6 - │ -1 │ x := "\u{1f917" - │ ^^^^^^^^^^ + r#"Error: unterminated unicode escape sequence + ╭─[ justfile:1:6 ] + │ + 1 │ x := "\u{1f917" +───╯ "#, ) .failure(); diff --git a/tests/subsequents.rs b/tests/subsequents.rs index 6d06c5fb0e..5bb494ae73 100644 --- a/tests/subsequents.rs +++ b/tests/subsequents.rs @@ -64,13 +64,12 @@ fn circular_dependency() { ", ) .stderr( - " - error: Recipe `foo` depends on itself - ——▶ justfile:1:9 - │ - 1 │ foo: && foo - │ ^^^ - ", + r"Error: Recipe `foo` depends on itself + ╭─[ justfile:1:9 ] + │ + 1 │ foo: && foo +───╯ +", ) .failure(); } @@ -84,13 +83,12 @@ fn unknown() { ", ) .stderr( - " - error: Recipe `foo` has unknown dependency `bar` - ——▶ justfile:1:9 - │ - 1 │ foo: && bar - │ ^^^ - ", + r"Error: Recipe `foo` has unknown dependency `bar` + ╭─[ justfile:1:9 ] + │ + 1 │ foo: && bar +───╯ +", ) .failure(); } @@ -106,13 +104,12 @@ fn unknown_argument() { ", ) .stderr( - " - error: Variable `y` not defined - ——▶ justfile:3:14 - │ - 3 │ foo: && (bar y) - │ ^ - ", + r"Error: Variable `y` not defined + ╭─[ justfile:3:14 ] + │ + 3 │ foo: && (bar y) +───╯ +", ) .failure(); } diff --git a/tests/test.rs b/tests/test.rs index 37161d30d6..3d57e3cfe7 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,7 +1,4 @@ -use { - super::*, - pretty_assertions::{assert_eq, StrComparison}, -}; +use {super::*, pretty_assertions::assert_eq}; pub(crate) struct Output { pub(crate) pid: u32, @@ -218,7 +215,11 @@ impl Test { fn compare_string(name: &str, have: &str, want: &str) -> bool { let equal = have == want; if !equal { - eprintln!("Bad {name}: {}", StrComparison::new(&have, &want)); + //eprintln!("Bad {name}: {}", StrComparison::new(&have, &want)); + eprintln!( + "Bad {name}:\n{}||\n-------------\n{}||\n=========", + &have, &want + ); } equal } diff --git a/tests/undefined_variables.rs b/tests/undefined_variables.rs index 5d62ec44ed..393aeacafb 100644 --- a/tests/undefined_variables.rs +++ b/tests/undefined_variables.rs @@ -5,13 +5,12 @@ fn parameter_default_unknown_variable_in_expression() { Test::new() .justfile("foo a=(b+''):") .stderr( - " - error: Variable `b` not defined - ——▶ justfile:1:8 - │ - 1 │ foo a=(b+''): - │ ^ - ", + r"Error: Variable `b` not defined + ╭─[ justfile:1:8 ] + │ + 1 │ foo a=(b+''): +───╯ +", ) .failure(); } @@ -25,13 +24,12 @@ fn unknown_variable_in_unary_call() { ", ) .stderr( - " - error: Variable `a` not defined - ——▶ justfile:1:15 - │ - 1 │ foo x=env_var(a): - │ ^ - ", + r"Error: Variable `a` not defined + ╭─[ justfile:1:15 ] + │ + 1 │ foo x=env_var(a): +───╯ +", ) .failure(); } @@ -45,13 +43,12 @@ fn unknown_first_variable_in_binary_call() { ", ) .stderr( - " - error: Variable `a` not defined - ——▶ justfile:1:26 - │ - 1 │ foo x=env_var_or_default(a, b): - │ ^ - ", + r"Error: Variable `a` not defined + ╭─[ justfile:1:26 ] + │ + 1 │ foo x=env_var_or_default(a, b): +───╯ +", ) .failure(); } @@ -65,13 +62,12 @@ fn unknown_second_variable_in_binary_call() { ", ) .stderr( - " - error: Variable `b` not defined - ——▶ justfile:1:30 - │ - 1 │ foo x=env_var_or_default('', b): - │ ^ - ", + r"Error: Variable `b` not defined + ╭─[ justfile:1:30 ] + │ + 1 │ foo x=env_var_or_default('', b): +───╯ +", ) .failure(); } @@ -85,13 +81,12 @@ fn unknown_variable_in_ternary_call() { ", ) .stderr( - " - error: Variable `a` not defined - ——▶ justfile:1:15 - │ - 1 │ foo x=replace(a, b, c): - │ ^ - ", + r"Error: Variable `a` not defined + ╭─[ justfile:1:15 ] + │ + 1 │ foo x=replace(a, b, c): +───╯ +", ) .failure(); } diff --git a/tests/unexport.rs b/tests/unexport.rs index 764ef94d9a..4da0d77937 100644 --- a/tests/unexport.rs +++ b/tests/unexport.rs @@ -48,13 +48,12 @@ fn duplicate_unexport_fails() { ) .env("JUST_TEST_VARIABLE", "foo") .stderr( - " - error: Variable `JUST_TEST_VARIABLE` is unexported multiple times - ——▶ justfile:6:10 - │ - 6 │ unexport JUST_TEST_VARIABLE - │ ^^^^^^^^^^^^^^^^^^ - ", + r"Error: Variable `JUST_TEST_VARIABLE` is unexported multiple times + ╭─[ justfile:6:10 ] + │ + 6 │ unexport JUST_TEST_VARIABLE +───╯ +", ) .failure(); } @@ -73,13 +72,12 @@ fn export_unexport_conflict() { ", ) .stderr( - " - error: Variable JUST_TEST_VARIABLE is both exported and unexported - ——▶ justfile:6:8 - │ - 6 │ export JUST_TEST_VARIABLE := 'foo' - │ ^^^^^^^^^^^^^^^^^^ - ", + r"Error: Variable JUST_TEST_VARIABLE is both exported and unexported + ╭─[ justfile:6:8 ] + │ + 6 │ export JUST_TEST_VARIABLE := 'foo' +───╯ +", ) .failure(); } diff --git a/tests/working_directory.rs b/tests/working_directory.rs index c88d96c4a0..71de019cd6 100644 --- a/tests/working_directory.rs +++ b/tests/working_directory.rs @@ -343,11 +343,16 @@ fn attribute_duplicate() { ", ) .stderr( - "error: Recipe attribute `working-directory` first used on line 1 is duplicated on line 2 - ——▶ justfile:2:2 - │ -2 │ [working-directory('baz')] - │ ^^^^^^^^^^^^^^^^^ + r"Error: Duplicate attribute `working-directory` + ╭─[ justfile:2:2 ] + │ + 1 │ [working-directory('bar')] + │ ─────────────┬───────────── + │ ╰─────────────── original + 2 │ [working-directory('baz')] + │ ────────┬──────── + │ ╰────────── duplicate +───╯ ", ) .failure(); @@ -380,12 +385,12 @@ fn attribute_with_nocd_is_forbidden() { ) .stderr( " - error: Recipe `bar` has both `[no-cd]` and `[working-directory]` attributes - ——▶ justfile:3:1 - │ - 3 │ bar: - │ ^^^ - ", +Error: Recipe `bar` has both `[no-cd]` and `[working-directory]` attributes + ╭─[ justfile:3:1 ] + │ + 3 │ bar: +───╯ +", ) .failure(); }