Repository navigation
Stricter test directives #7165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Stricter test directives #7165
Changes from all commits
2d467c7
4549cdc
8be56b1
55f071f
64dca2f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -127,7 +127,7 @@ fn verify_config_used(path: &Path, config_name: &str) { | |||||
| let entry = entry.expect("couldn't get directory entry"); | ||||||
| let path = entry.path(); | ||||||
| if path.extension().map_or(false, |f| f == "rs") { | ||||||
| // check if "// rustfmt-<config_name>:" appears in the file. | ||||||
| // check if "//@ rustfmt-<config_name>:" appears in the file. | ||||||
| let filebuf = BufReader::new( | ||||||
| fs::File::open(&path) | ||||||
| .unwrap_or_else(|_| panic!("couldn't read file {}", path.display())), | ||||||
|
|
@@ -137,7 +137,7 @@ fn verify_config_used(path: &Path, config_name: &str) { | |||||
| .lines() | ||||||
| .map(Result::unwrap) | ||||||
| .take_while(|l| l.starts_with("//")) | ||||||
| .any(|l| l.starts_with(&format!("// rustfmt-{}", config_name))), | ||||||
| .any(|l| l.starts_with(&format!("//@ rustfmt-{}", config_name))), | ||||||
| "config option file {} does not contain expected config name", | ||||||
| path.display() | ||||||
| ); | ||||||
|
|
@@ -258,7 +258,7 @@ fn warning_tests() { | |||||
| let files = get_test_files(Path::new("tests/warning/source"), true); | ||||||
|
|
||||||
| for file in &files { | ||||||
| let mut config = read_config(file); | ||||||
| let mut config = read_config(file).expect("config is valid"); | ||||||
| config.set().error_on_line_overflow(true); | ||||||
| config.set().error_on_unformatted(true); | ||||||
|
|
||||||
|
|
@@ -379,7 +379,7 @@ fn modified_test() { | |||||
| // Helper function for comparing the results of rustfmt | ||||||
| // to a known output file generated by one of the write modes. | ||||||
| fn assert_output(source: &Path, expected_filename: &Path) { | ||||||
| let config = read_config(source); | ||||||
| let config = read_config(source).expect("config is valid"); | ||||||
| let (_, source_file, _) = format_file(source, config.clone()); | ||||||
|
|
||||||
| // Populate output by writing to a vec. | ||||||
|
|
@@ -790,7 +790,8 @@ fn check_files(files: Vec<PathBuf>, opt_config: &Option<PathBuf>) -> (Vec<Format | |||||
| let mut reports = vec![]; | ||||||
|
|
||||||
| for file_name in files { | ||||||
| let sig_comments = read_significant_comments(&file_name); | ||||||
| let sig_comments = | ||||||
| read_significant_comments(&file_name).expect("valid significant comments"); | ||||||
| if sig_comments.contains_key("unstable") && !is_nightly_channel!() { | ||||||
| debug!( | ||||||
| "Skipping '{}' because it requires unstable \ | ||||||
|
|
@@ -856,8 +857,8 @@ fn print_mismatches<T: Fn(u32) -> String>( | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| fn read_config(filename: &Path) -> Config { | ||||||
| let sig_comments = read_significant_comments(filename); | ||||||
| fn read_config(filename: &Path) -> Result<Config, String> { | ||||||
| let sig_comments = read_significant_comments(filename)?; | ||||||
| let (edition, style_edition, version) = get_editions_from_comments(&sig_comments); | ||||||
| // Look for a config file. If there is a 'config' property in the significant comments, use | ||||||
| // that. Otherwise, if there are no significant comments at all, look for a config file with | ||||||
|
|
@@ -880,11 +881,40 @@ fn read_config(filename: &Path) -> Config { | |||||
|
|
||||||
| for (key, val) in &sig_comments { | ||||||
| if key != "target" && key != "config" && key != "unstable" && key != "stable" { | ||||||
| if !Config::is_valid_name(key) { | ||||||
| // Check that all config names are valid | ||||||
| return Err(format!( | ||||||
| "{} set unrecognized config option {:?}", | ||||||
| &filename.display(), | ||||||
| key | ||||||
| )); | ||||||
| } | ||||||
|
|
||||||
| if !Config::is_valid_key_val(key, val) { | ||||||
| // Check that all config values are valid | ||||||
| return Err(format!( | ||||||
| "{} set unrecognized value {:?} for config option {:?}", | ||||||
| &filename.display(), | ||||||
| key, | ||||||
| val | ||||||
| )); | ||||||
| } | ||||||
|
|
||||||
| config.override_value(key, val); | ||||||
|
|
||||||
| if !config.was_option_set(key) { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what motivated adding this check/how can we end up in this situation?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just an extra check to make sure that values are actually getting set as we'd expect. I don't see any harm in keeping this check, but let me know if you think otherwise. |
||||||
| // Check that all config values were properly set | ||||||
| return Err(format!( | ||||||
| "{} didn't correctly set {}: {}", | ||||||
| &filename.display(), | ||||||
| key, | ||||||
| val | ||||||
| )); | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| config | ||||||
| Ok(config) | ||||||
| } | ||||||
|
|
||||||
| fn format_file<P: Into<PathBuf>>(filepath: P, config: Config) -> (bool, SourceFile, FormatReport) { | ||||||
|
|
@@ -923,13 +953,13 @@ fn idempotent_check( | |||||
| filename: &PathBuf, | ||||||
| opt_config: &Option<PathBuf>, | ||||||
| ) -> Result<FormatReport, IdempotentCheckError> { | ||||||
| let sig_comments = read_significant_comments(filename); | ||||||
| let sig_comments = read_significant_comments(filename).expect("valid significant comments"); | ||||||
| let config = if let Some(ref config_file_path) = opt_config { | ||||||
| let (edition, style_edition, version) = get_editions_from_comments(&sig_comments); | ||||||
| Config::from_toml_path(config_file_path, edition, style_edition, version) | ||||||
| .expect("`rustfmt.toml` not found") | ||||||
| } else { | ||||||
| read_config(filename) | ||||||
| read_config(filename).expect("config is valid") | ||||||
| }; | ||||||
| let (parsing_errors, source_file, format_report) = format_file(filename, config); | ||||||
| if parsing_errors { | ||||||
|
|
@@ -985,37 +1015,51 @@ fn get_config( | |||||
| .expect("invalid TOML") | ||||||
| } | ||||||
|
|
||||||
| // Reads significant comments of the form: `// rustfmt-key: value` into a hash map. | ||||||
| fn read_significant_comments(file_name: &Path) -> HashMap<String, String> { | ||||||
| // Reads significant comments of the form: `//@ rustfmt-key: value` into a hash map. | ||||||
| fn read_significant_comments(file_name: &Path) -> Result<HashMap<String, String>, String> { | ||||||
| let file = fs::File::open(file_name) | ||||||
| .unwrap_or_else(|_| panic!("couldn't read file {}", file_name.display())); | ||||||
| let reader = BufReader::new(file); | ||||||
| let pattern = r"^\s*//\s*rustfmt-([^:]+):\s*(\S+)"; | ||||||
| let regex = regex::Regex::new(pattern).expect("failed creating pattern 1"); | ||||||
|
|
||||||
| // Matches lines containing significant comments or whitespace. | ||||||
| let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)") | ||||||
| .expect("failed creating pattern 2"); | ||||||
| // Matches `// rustfmt-{name}: {value}` | ||||||
| let old_pattern = r"^\s*//\s+rustfmt-(?P<name>[A-Za-z_]+)\s?:\s*(?P<value>\S+)$"; | ||||||
| let old_regex = regex::Regex::new(old_pattern).expect("failed creating old pattern"); | ||||||
|
|
||||||
| // Matches `//@ rustfmt-{name}: {value}` | ||||||
| let pattern = r"^\s*//@\s+rustfmt-(?P<name>[A-Za-z_]+)\s?:\s*(?P<value>\S+)$"; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there anything us from being stricter here, there are currently no comments in files that need the extra optional spaces
Suggested change
verified via # no comments use a space between line start and `//`
git grep --perl-regexp '^\s+//@\s+rustfmt-(?P<name>[A-Za-z_]+)\s?:\s*(?P<value>\S+)$' -- tests/
# ^ changed '*' to '+'
# similarly, no comment uses a space between 'rustfmt-<name>' and then ':'
git grep --perl-regexp '^\s*//@\s+rustfmt-(?P<name>[A-Za-z_]+)\s+:\s*(?P<value>\S+)$' -- tests/
# ^ changed '?' to '+'
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could probably remove the second
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
My preference is to limit things to what we know/expect we will need, then change it in the future if needed. But I'm not opposed to leaving it as-is. |
||||||
| let regex = regex::Regex::new(pattern).expect("failed creating pattern 1"); | ||||||
|
|
||||||
| reader | ||||||
| .lines() | ||||||
| .map(|line| line.expect("failed getting line")) | ||||||
| .filter(|line| line_regex.is_match(line)) | ||||||
| .filter(|l| l.trim_start().starts_with("//")) | ||||||
| .filter_map(|line| { | ||||||
| regex.captures_iter(&line).next().map(|capture| { | ||||||
| ( | ||||||
| capture | ||||||
| .get(1) | ||||||
| .expect("couldn't unwrap capture") | ||||||
| .as_str() | ||||||
| .to_owned(), | ||||||
| capture | ||||||
| .get(2) | ||||||
| .expect("couldn't unwrap capture") | ||||||
| .as_str() | ||||||
| .to_owned(), | ||||||
| ) | ||||||
| }) | ||||||
| if let Some(c) = old_regex.captures(&line) { | ||||||
| // Don't let old syntax silently slip through. | ||||||
| // Guide test authors on how to fix issues with the old syntax. | ||||||
| return Some(Err(format!( | ||||||
| "{} uses old directive syntax. Should be //@ rustfmt-{}: {}", | ||||||
| &file_name.display(), | ||||||
| &c["name"], | ||||||
| &c["value"], | ||||||
| ))); | ||||||
| } | ||||||
|
|
||||||
| if !line.trim_start().starts_with("//@") { | ||||||
| // This is just a normal comment line | ||||||
| return None; | ||||||
| } | ||||||
|
|
||||||
| let value = match regex.captures(&line) { | ||||||
| Some(c) => Ok((c["name"].to_owned(), c["value"].to_owned())), | ||||||
| None => Err(format!( | ||||||
| "{} has a malformed config directive. Should be //@ rustfmt-{}: {}", | ||||||
| &file_name.display(), | ||||||
| "{name}", | ||||||
| "{value}", | ||||||
| )), | ||||||
| }; | ||||||
| Some(value) | ||||||
| }) | ||||||
| .collect() | ||||||
| } | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| // rustfmt-imports_granularity: Crate | ||
| //@ rustfmt-imports_granularity: Crate | ||
|
|
||
| use foo::a; | ||
| use foo::a; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| // rustfmt-imports_granularity: Module | ||
| //@ rustfmt-imports_granularity: Module | ||
|
|
||
| #![allow(dead_code)] | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| // rustfmt-imports_granularity: One | ||
| //@ rustfmt-imports_granularity: One | ||
|
|
||
| pub use foo::x; | ||
| pub use foo::x as x2; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| // rustfmt-style_edition: 2024 | ||
| //@ rustfmt-style_edition: 2024 | ||
| fn main() { | ||
| match a { | ||
| _ => | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| // rustfmt-style_edition: 2024 | ||
| //@ rustfmt-style_edition: 2024 | ||
| fn main() { | ||
| match a { | ||
| _ => // comment with => | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| // rustfmt-edition: 2018 | ||
| //@ rustfmt-edition: 2018 | ||
|
|
||
| fn main() { | ||
| let x = async { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| // rustfmt-edition: 2018 | ||
| //@ rustfmt-edition: 2018 | ||
|
|
||
| async fn bar() -> Result<(), ()> { | ||
| Ok(()) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| // rustfmt-indent_style: Visual | ||
| //@ rustfmt-indent_style: Visual | ||
|
|
||
| // #1357 | ||
| impl< | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| // rustfmt-binop_separator: Back | ||
| //@ rustfmt-binop_separator: Back | ||
|
|
||
| fn main() { | ||
| match val { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| // rustfmt-edition: 2018 | ||
| //@ rustfmt-edition: 2018 | ||
| #![feature(try_blocks)] | ||
|
|
||
| fn main() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| // rustfmt-indent_style: Visual | ||
| //@ rustfmt-indent_style: Visual | ||
| // Test chain formatting. | ||
|
|
||
| fn main() { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this causes confusing error messages, e.g. using
//@ rustfmt-foo: true, the error printed is:Reading that: is the error telling me the config is valid?. The docs recommend using
should, and I think that would work:View changes since the review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on updating all the expect calls to say something like "invalid config" or "expected valid config"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 sounds good to me