From f3f1035b701ba3f0aad51a2c48740a99288aaa79 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 1 Apr 2020 16:51:46 -0700 Subject: [PATCH 1/4] Remove duplicate in edge-cases tests. --- tests/edge_cases.rs | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs index e1f380a..a265c04 100644 --- a/tests/edge_cases.rs +++ b/tests/edge_cases.rs @@ -2,29 +2,22 @@ use rustfix; use std::collections::HashSet; use std::fs; -#[test] -fn multiple_fix_options_yield_no_suggestions() { - let json = fs::read_to_string("./tests/edge-cases/skip-multi-option-lints.json").unwrap(); - let expected_suggestions = - rustfix::get_suggestions_from_json(&json, &HashSet::new(), rustfix::Filter::Everything) +macro_rules! expect_empty_json_test { + ($name:ident, $file:expr) => { + #[test] + fn $name() { + let json = fs::read_to_string(concat!("./tests/edge-cases/", $file)).unwrap(); + let expected_suggestions = rustfix::get_suggestions_from_json( + &json, + &HashSet::new(), + rustfix::Filter::Everything, + ) .unwrap(); - assert!(expected_suggestions.is_empty()); + assert!(expected_suggestions.is_empty()); + } + }; } -#[test] -fn out_of_bounds_test() { - let json = fs::read_to_string("./tests/edge-cases/out_of_bounds.recorded.json").unwrap(); - let expected_suggestions = - rustfix::get_suggestions_from_json(&json, &HashSet::new(), rustfix::Filter::Everything) - .unwrap(); - assert!(expected_suggestions.is_empty()); -} - -#[test] -fn utf8_identifiers_test() { - let json = fs::read_to_string("./tests/edge-cases/utf8_idents.recorded.json").unwrap(); - let expected_suggestions = - rustfix::get_suggestions_from_json(&json, &HashSet::new(), rustfix::Filter::Everything) - .unwrap(); - assert!(expected_suggestions.is_empty()); -} +expect_empty_json_test! {multiple_fix_options_yield_no_suggestions, "skip-multi-option-lints.json"} +expect_empty_json_test! {out_of_bounds_test, "out_of_bounds.recorded.json"} +expect_empty_json_test! {utf8_identifiers_test, "utf8_idents.recorded.json"} From 892a95c714a4c1792200d18e42970c05c0a0debb Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 1 Apr 2020 16:55:49 -0700 Subject: [PATCH 2/4] Don't panic on span for empty file. --- src/lib.rs | 3 ++- tests/edge-cases/empty.json | 42 +++++++++++++++++++++++++++++++++++++ tests/edge-cases/empty.rs | 0 tests/edge_cases.rs | 1 + 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 tests/edge-cases/empty.json create mode 100644 tests/edge-cases/empty.rs diff --git a/src/lib.rs b/src/lib.rs index 8026f00..93006ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,7 +122,8 @@ fn parse_snippet(span: &DiagnosticSpan) -> Option { // If we get a DiagnosticSpanLine where highlight_end > text.len(), we prevent an 'out of // bounds' access by making sure the index is within the array bounds. - let last_tail_index = last.highlight_end.min(last.text.len()) - 1; + // `saturating_sub` is used in case of an empty file + let last_tail_index = last.highlight_end.min(last.text.len()).saturating_sub(1); let last_slice = last.text.chars().collect::>(); if span.text.len() > 1 { diff --git a/tests/edge-cases/empty.json b/tests/edge-cases/empty.json new file mode 100644 index 0000000..62df0b9 --- /dev/null +++ b/tests/edge-cases/empty.json @@ -0,0 +1,42 @@ +{ + "message": "`main` function not found in crate `empty`", + "code": { + "code": "E0601", + "explanation": "No `main` function was found in a binary crate. To fix this error, add a\n`main` function. For example:\n\n```\nfn main() {\n // Your program will start here.\n println!(\"Hello world!\");\n}\n```\n\nIf you don't know the basics of Rust, you can go look to the Rust Book to get\nstarted: https://doc.rust-lang.org/book/\n" + }, + "level": "error", + "spans": [ + { + "file_name": "empty.rs", + "byte_start": 0, + "byte_end": 0, + "line_start": 0, + "line_end": 0, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + } + ], + "children": [ + { + "message": "consider adding a `main` function to `empty.rs`", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + } + ], + "rendered": "error[E0601]: `main` function not found in crate `empty`\n |\n = note: consider adding a `main` function to `empty.rs`\n\n" +} diff --git a/tests/edge-cases/empty.rs b/tests/edge-cases/empty.rs new file mode 100644 index 0000000..e69de29 diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs index a265c04..8e8c9c9 100644 --- a/tests/edge_cases.rs +++ b/tests/edge_cases.rs @@ -21,3 +21,4 @@ macro_rules! expect_empty_json_test { expect_empty_json_test! {multiple_fix_options_yield_no_suggestions, "skip-multi-option-lints.json"} expect_empty_json_test! {out_of_bounds_test, "out_of_bounds.recorded.json"} expect_empty_json_test! {utf8_identifiers_test, "utf8_idents.recorded.json"} +expect_empty_json_test! {empty, "empty.json"} From d244f66dabc43e98d37bbfe61f2a2d79fd75e2e2 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 1 Apr 2020 17:20:51 -0700 Subject: [PATCH 3/4] Provide helpful error message if not using nightly. --- tests/parse_and_replace.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/parse_and_replace.rs b/tests/parse_and_replace.rs index c3f5701..1b6ffa9 100644 --- a/tests/parse_and_replace.rs +++ b/tests/parse_and_replace.rs @@ -54,6 +54,9 @@ fn compile(file: &Path, mode: &str) -> Result { fn compile_and_get_json_errors(file: &Path, mode: &str) -> Result { let res = compile(file, mode)?; let stderr = String::from_utf8(res.stderr)?; + if stderr.contains("is only accepted on the nightly compiler") { + panic!("rustfix tests require a nightly compiler"); + } match res.status.code() { Some(0) | Some(1) | Some(101) => Ok(stderr), @@ -160,7 +163,7 @@ fn test_rustfix_with_file>(file: P, mode: &str) -> Result<(), Err ))?; let expected_suggestions = rustfix::get_suggestions_from_json(&expected_json, &HashSet::new(), filter_suggestions) - .context("could not load expected suggesitons")?; + .context("could not load expected suggestions")?; ensure!( expected_suggestions == suggestions, From df8401b0b248f10e9b54df297b1270b3db66b72a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 1 Apr 2020 17:22:15 -0700 Subject: [PATCH 4/4] Prevent panic when span points past end of line. --- src/lib.rs | 9 +++++++-- tests/edge-cases/no_main.json | 33 +++++++++++++++++++++++++++++++++ tests/edge-cases/no_main.rs | 1 + tests/edge_cases.rs | 1 + 4 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 tests/edge-cases/no_main.json create mode 100644 tests/edge-cases/no_main.rs diff --git a/src/lib.rs b/src/lib.rs index 93006ee..8304047 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,8 +108,13 @@ fn parse_snippet(span: &DiagnosticSpan) -> Option { let text_slice = span.text[0].text.chars().collect::>(); // We subtract `1` because these highlights are 1-based - let start = span.text[0].highlight_start - 1; - let end = span.text[0].highlight_end - 1; + // Check the `min` so that it doesn't attempt to index out-of-bounds when + // the span points to the "end" of the line. For example, a line of + // "foo\n" with a highlight_start of 5 is intended to highlight *after* + // the line. This needs to compensate since the newline has been removed + // from the text slice. + let start = (span.text[0].highlight_start - 1).min(text_slice.len()); + let end = (span.text[0].highlight_end - 1).min(text_slice.len()); let lead = text_slice[indent..start].iter().collect(); let mut body: String = text_slice[start..end].iter().collect(); diff --git a/tests/edge-cases/no_main.json b/tests/edge-cases/no_main.json new file mode 100644 index 0000000..e4b1c8f --- /dev/null +++ b/tests/edge-cases/no_main.json @@ -0,0 +1,33 @@ +{ + "message": "`main` function not found in crate `no_main`", + "code": { + "code": "E0601", + "explanation": "No `main` function was found in a binary crate. To fix this error, add a\n`main` function. For example:\n\n```\nfn main() {\n // Your program will start here.\n println!(\"Hello world!\");\n}\n```\n\nIf you don't know the basics of Rust, you can go look to the Rust Book to get\nstarted: https://doc.rust-lang.org/book/\n" + }, + "level": "error", + "spans": [ + { + "file_name": "no_main.rs", + "byte_start": 26, + "byte_end": 26, + "line_start": 1, + "line_end": 1, + "column_start": 27, + "column_end": 27, + "is_primary": true, + "text": [ + { + "text": "// This file has no main.", + "highlight_start": 27, + "highlight_end": 27 + } + ], + "label": "consider adding a `main` function to `no_main.rs`", + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + } + ], + "children": [], + "rendered": "error[E0601]: `main` function not found in crate `no_main`\n --> no_main.rs:1:27\n |\n1 | // This file has no main.\n | ^ consider adding a `main` function to `no_main.rs`\n\n" +} diff --git a/tests/edge-cases/no_main.rs b/tests/edge-cases/no_main.rs new file mode 100644 index 0000000..0147ba7 --- /dev/null +++ b/tests/edge-cases/no_main.rs @@ -0,0 +1 @@ +// This file has no main. diff --git a/tests/edge_cases.rs b/tests/edge_cases.rs index 8e8c9c9..191713b 100644 --- a/tests/edge_cases.rs +++ b/tests/edge_cases.rs @@ -22,3 +22,4 @@ expect_empty_json_test! {multiple_fix_options_yield_no_suggestions, "skip-multi- expect_empty_json_test! {out_of_bounds_test, "out_of_bounds.recorded.json"} expect_empty_json_test! {utf8_identifiers_test, "utf8_idents.recorded.json"} expect_empty_json_test! {empty, "empty.json"} +expect_empty_json_test! {no_main, "no_main.json"}