diff --git a/CHANGELOG.md b/CHANGELOG.md index b1dc8f20..1ef2b6ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [0.25.0] - 2024-07-24 + +### Added + +### Fixed + +* panics when ui_test tried to show diagnostics on multi-byte chars + +### Changed + +### Removed + ## [0.24.0] - 2024-07-11 diff --git a/Cargo.lock b/Cargo.lock index 4651f696..b5420d09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -454,9 +454,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -558,7 +558,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 3ba3b68e..b712a640 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ui_test" -version = "0.24.0" +version = "0.25.0" edition = "2021" license = "MIT OR Apache-2.0" description = "A test framework for testing rustc diagnostics output" @@ -28,7 +28,7 @@ indicatif = "0.17.6" prettydiff = { version = "0.7", default-features = false } annotate-snippets = { version = "0.11.2" } levenshtein = "1.0.5" -spanned = "0.2.1" +spanned = "0.3.0" [dependencies.regex] version = "1.5.5" diff --git a/src/aux_builds.rs b/src/aux_builds.rs index 1525215b..a5e35414 100644 --- a/src/aux_builds.rs +++ b/src/aux_builds.rs @@ -29,7 +29,6 @@ impl Flag for AuxBuilder { ) -> Result<(), Errored> { let aux = &self.aux_file; let aux_dir = config.aux_dir; - let line = aux.line(); let aux_file = if aux.starts_with("..") { aux_dir.parent().unwrap().join(&aux.content) } else { @@ -60,9 +59,8 @@ impl Flag for AuxBuilder { }| Errored { command, errors: vec![Error::Aux { - path: aux_file.to_path_buf(), + path: Spanned::new(aux_file.to_path_buf(), aux.span()), errors, - line, }], stderr, stdout, @@ -84,20 +82,21 @@ pub struct AuxBuilder { impl Build for AuxBuilder { fn build(&self, build_manager: &BuildManager<'_>) -> Result, Errored> { let mut config = build_manager.config().clone(); - let file_contents = std::fs::read(&self.aux_file.content).map_err(|err| Errored { - command: format!("reading aux file `{}`", display(&self.aux_file)), - errors: vec![], - stderr: err.to_string().into_bytes(), - stdout: vec![], - })?; - let comments = Comments::parse(&file_contents, &config, &self.aux_file) + let file_contents = + Spanned::read_from_file(&self.aux_file.content).map_err(|err| Errored { + command: format!("reading aux file `{}`", display(&self.aux_file)), + errors: vec![], + stderr: err.to_string().into_bytes(), + stdout: vec![], + })?; + let comments = Comments::parse(file_contents.as_ref(), &config) .map_err(|errors| Errored::new(errors, "parse aux comments"))?; assert_eq!( comments.revisions, None, "aux builds cannot specify revisions" ); - default_per_file_config(&mut config, &self.aux_file, &file_contents); + default_per_file_config(&mut config, &file_contents); match CrateType::from_file_contents(&file_contents) { // Proc macros must be run on the host diff --git a/src/custom_flags/run.rs b/src/custom_flags/run.rs index 98af12f4..20ed264f 100644 --- a/src/custom_flags/run.rs +++ b/src/custom_flags/run.rs @@ -1,11 +1,8 @@ //! Types used for running tests after they pass compilation use bstr::ByteSlice; -use spanned::{Span, Spanned}; -use std::{ - path::PathBuf, - process::{Command, Output}, -}; +use spanned::Spanned; +use std::process::{Command, Output}; use crate::{ build_manager::BuildManager, display, per_test_config::TestConfig, Error, Errored, TestOk, @@ -116,19 +113,25 @@ fn get_panic_span(stderr: &[u8]) -> Spanned { let Ok(filename) = filename.to_str() else { continue; }; - let Ok(line) = line.parse() else { + let Ok(line) = line.parse::() else { + continue; + }; + let Ok(col) = col.parse::() else { + continue; + }; + let Ok(file) = Spanned::read_from_file(filename) else { + continue; + }; + let Some(line) = line.checked_sub(1) else { continue; }; - let Ok(col) = col.parse() else { + let Some(line) = file.lines().nth(line) else { continue; }; - let span = Span { - file: PathBuf::from(filename), - line_start: line, - line_end: line, - col_start: col, - col_end: col, + let Some(col) = col.checked_sub(1) else { + continue; }; + let span = line.span.inc_col_start(col); return Spanned::new(message.into(), span); } } diff --git a/src/custom_flags/rustfix.rs b/src/custom_flags/rustfix.rs index 371c94b8..c5eaf082 100644 --- a/src/custom_flags/rustfix.rs +++ b/src/custom_flags/rustfix.rs @@ -234,7 +234,7 @@ fn compile_fixed( .iter() .flatten() .chain(diagnostics.messages_from_unknown_file_or_line.iter()) - .find_map(|message| message.line_col.clone()) + .find_map(|message| message.span.clone()) .unwrap_or_default(), ), }], diff --git a/src/diagnostics.rs b/src/diagnostics.rs index fbaeefd5..8c053834 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -56,7 +56,9 @@ pub struct Message { /// The main message of the diagnostic (what will be matched for with `//~`) pub message: String, /// Information about where in the file the message was emitted - pub line_col: Option, + pub line: Option, + /// Exact span information of the message + pub span: Option, /// Identifier of the message (E0XXX for rustc errors, or lint names) pub code: Option, } diff --git a/src/error.rs b/src/error.rs index 295f18c7..87992e97 100644 --- a/src/error.rs +++ b/src/error.rs @@ -56,7 +56,7 @@ pub enum Error { /// The main message of the error. msgs: Vec, /// File and line information of the error. - path: Option>, + path: Option<(PathBuf, NonZeroUsize)>, }, /// A comment failed to parse. InvalidComment { @@ -72,7 +72,7 @@ pub enum Error { /// The comment being looked for kind: String, /// The lines where conflicts happened - lines: Vec, + lines: Vec, }, /// A subcommand (e.g. rustfix) of a test failed. Command { @@ -86,11 +86,9 @@ pub enum Error { /// An auxiliary build failed with its own set of errors. Aux { /// Path to the aux file. - path: PathBuf, + path: Spanned, /// The errors that occurred during the build of the aux file. errors: Vec, - /// The line in which the aux file was requested to be built. - line: NonZeroUsize, }, /// An error occured applying [`rustfix`] suggestions Rustfix(anyhow::Error), diff --git a/src/lib.rs b/src/lib.rs index 70bc628c..de692a42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ pub use core::run_and_collect; pub use core::CrateType; pub use filter::Match; use per_test_config::TestConfig; +use spanned::Spanned; use status_emitter::{StatusEmitter, TestStatus}; use std::collections::VecDeque; use std::path::Path; @@ -117,7 +118,7 @@ pub fn default_any_file_filter(path: &Path, config: &Config) -> bool { } /// The default per-file config used by `run_tests`. -pub fn default_per_file_config(config: &mut Config, _path: &Path, file_contents: &[u8]) { +pub fn default_per_file_config(config: &mut Config, file_contents: &Spanned>) { config.program.args.push( match CrateType::from_file_contents(file_contents) { CrateType::ProcMacro => "--crate-type=proc-macro", @@ -137,9 +138,9 @@ pub fn test_command(mut config: Config, path: &Path) -> Result { config.fill_host_and_target()?; - let content = - std::fs::read(path).wrap_err_with(|| format!("failed to read {}", display(path)))?; - let comments = Comments::parse(&content, &config, path) + let content = Spanned::read_from_file(path) + .wrap_err_with(|| format!("failed to read {}", display(path)))?; + let comments = Comments::parse(content.as_ref(), &config) .map_err(|errors| color_eyre::eyre::eyre!("{errors:#?}"))?; let config = TestConfig { config, @@ -166,7 +167,7 @@ pub fn test_command(mut config: Config, path: &Path) -> Result { pub fn run_tests_generic( mut configs: Vec, file_filter: impl Fn(&Path, &Config) -> Option + Sync, - per_file_config: impl Fn(&mut Config, &Path, &[u8]) + Sync, + per_file_config: impl Fn(&mut Config, &Spanned>) + Sync, status_emitter: impl StatusEmitter + Send, ) -> Result<()> { if nextest::emulate(&mut configs) { @@ -232,9 +233,9 @@ pub fn run_tests_generic( |receive, finished_files_sender| -> Result<()> { for (status, build_manager) in receive { let path = status.path(); - let file_contents = std::fs::read(path).unwrap(); + let file_contents = Spanned::read_from_file(path).unwrap(); let mut config = build_manager.config().clone(); - per_file_config(&mut config, path, &file_contents); + per_file_config(&mut config, &file_contents); let result = match std::panic::catch_unwind(|| { parse_and_test_file(build_manager, &status, config, file_contents) }) { @@ -317,9 +318,9 @@ fn parse_and_test_file( build_manager: &BuildManager<'_>, status: &dyn TestStatus, config: Config, - file_contents: Vec, + file_contents: Spanned>, ) -> Result, Errored> { - let comments = Comments::parse(&file_contents, &config, status.path()) + let comments = Comments::parse(file_contents.as_ref(), &config) .map_err(|errors| Errored::new(errors, "parse comments"))?; const EMPTY: &[String] = &[String::new()]; // Run the test for all revisions diff --git a/src/parser.rs b/src/parser.rs index ecca9ea4..06309392 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,6 @@ use std::{ collections::{BTreeMap, HashMap}, num::NonZeroUsize, - path::Path, }; use bstr::{ByteSlice, Utf8Error}; @@ -60,7 +59,7 @@ impl Comments { } if let Some(found) = f(rev).into_inner() { if result.is_some() { - errors.push(found.line()); + errors.push(found.span); } else { result = found.into(); } @@ -253,15 +252,6 @@ pub(crate) enum ErrorMatchKind { Code(Spanned), } -impl ErrorMatchKind { - fn span(&self) -> &Span { - match self { - Self::Pattern { pattern, .. } => &pattern.span, - Self::Code(code) => &code.span, - } - } -} - #[derive(Debug, Clone)] pub(crate) struct ErrorMatch { pub(crate) kind: ErrorMatchKind, @@ -309,11 +299,10 @@ impl Comments { /// Parse comments in `content`. /// `path` is only used to emit diagnostics if parsing fails. pub(crate) fn parse( - content: &(impl AsRef<[u8]> + ?Sized), + content: Spanned<&[u8]>, config: &Config, - file: &Path, ) -> std::result::Result> { - CommentParser::new(config).parse(content, file) + CommentParser::new(config).parse(content) } } @@ -329,27 +318,16 @@ impl CommentParser { this } - fn parse( - mut self, - content: &(impl AsRef<[u8]> + ?Sized), - file: &Path, - ) -> std::result::Result> { + fn parse(mut self, content: Spanned<&[u8]>) -> std::result::Result> { let defaults = std::mem::take(self.comments.revisioned.get_mut(&[][..]).unwrap()); let mut delayed_fallthrough = Vec::new(); let mut fallthrough_to = None; // The line that a `|` will refer to. let mut last_line = 0; - for (l, line) in content.as_ref().lines().enumerate() { + for (l, line) in content.lines().enumerate() { last_line = l + 1; let l = NonZeroUsize::new(l + 1).unwrap(); // enumerate starts at 0, but line numbers start at 1 - let span = Span { - file: file.to_path_buf(), - line_start: l, - line_end: l, - col_start: NonZeroUsize::new(1).unwrap(), - col_end: NonZeroUsize::new(line.len() + 1).unwrap(), - }; - match self.parse_checked_line(fallthrough_to, Spanned::new(line, span)) { + match self.parse_checked_line(fallthrough_to, l, line) { Ok(ParsePatternResult::Other) => { fallthrough_to = None; } @@ -372,7 +350,7 @@ impl CommentParser { .comments .revisioned .values_mut() - .find(|rev| rev.error_matches[idx].kind.span().line_start == line) + .find(|rev| rev.error_matches[idx].line == line) { rev.error_matches[idx].line = match_line; } else { @@ -486,6 +464,7 @@ impl CommentParser { fn parse_checked_line( &mut self, fallthrough_to: Option, + current_line: NonZeroUsize, line: Spanned<&[u8]>, ) -> std::result::Result> { let mut res = ParsePatternResult::Other; @@ -494,7 +473,7 @@ impl CommentParser { } else if let Some((_, pattern)) = line.split_once_str("//~") { let (revisions, pattern) = self.parse_revisions(pattern.to_str()?); self.revisioned(revisions, |this| { - res = this.parse_pattern(pattern, fallthrough_to); + res = this.parse_pattern(pattern, fallthrough_to, current_line); }) } else { for pos in line.clone().find_iter("//") { @@ -890,6 +869,7 @@ impl CommentParser<&mut Revisioned> { &mut self, pattern: Spanned<&str>, fallthrough_to: Option, + current_line: NonZeroUsize, ) -> ParsePatternResult { let c = pattern.chars().next(); let mut res = ParsePatternResult::Other; @@ -906,7 +886,7 @@ impl CommentParser<&mut Revisioned> { span, idx: self.error_matches.len(), }; - pattern.span.line_start + current_line } }, pattern.split_at(1).1, @@ -916,9 +896,7 @@ impl CommentParser<&mut Revisioned> { span: _, }) => { let offset = pattern.chars().take_while(|c| c.content == '^').count(); - match pattern - .span() - .line_start + match current_line .get() .checked_sub(offset) .and_then(NonZeroUsize::new) @@ -933,10 +911,10 @@ impl CommentParser<&mut Revisioned> { self.error(pattern.span(), format!( "//~^ pattern is trying to refer to {} lines above, but there are only {} lines above", offset, - pattern.line().get() - 1, + current_line.get() - 1, )); return ParsePatternResult::ErrorAbove { - match_line: pattern.span().line_start, + match_line: current_line, }; } } @@ -946,9 +924,7 @@ impl CommentParser<&mut Revisioned> { span: _, }) => { let offset = pattern.chars().take_while(|c| c.content == 'v').count(); - match pattern - .span() - .line_start + match current_line .get() .checked_add(offset) .and_then(NonZeroUsize::new) @@ -969,12 +945,12 @@ impl CommentParser<&mut Revisioned> { )); return ParsePatternResult::ErrorBelow { span: pattern.span(), - match_line: pattern.span().line_start, + match_line: current_line, }; } } } - Some(_) => (pattern.span().line_start, pattern), + Some(_) => (current_line, pattern), None => { self.error(pattern.span(), "no pattern specified"); return res; diff --git a/src/parser/tests.rs b/src/parser/tests.rs index c3b69856..3fcf2fd5 100644 --- a/src/parser/tests.rs +++ b/src/parser/tests.rs @@ -1,4 +1,6 @@ -use std::path::Path; +use std::path::PathBuf; + +use spanned::{Span, Spanned}; use crate::{ parser::{Condition, ErrorMatchKind, Pattern}, @@ -7,6 +9,23 @@ use crate::{ use super::Comments; +macro_rules! line { + ($thing:expr, $s:expr) => {{ + let file = Spanned::new( + $s.as_bytes(), + Span { + file: PathBuf::new(), + bytes: 0..$s.len(), + }, + ); + let pos = file + .lines() + .position(|line| line.span.bytes.contains(&$thing.bytes.start)) + .unwrap(); + pos + 1 + }}; +} + #[test] fn parse_simple_comment() { let s = r" @@ -16,14 +35,24 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address $HEX is unallocated) } "; - let comments = Comments::parse(s, &Config::rustc(""), Path::new("")).unwrap(); + let comments = Comments::parse( + Spanned::new( + s.as_bytes(), + Span { + file: PathBuf::new(), + bytes: 0..s.len(), + }, + ), + &Config::rustc(""), + ) + .unwrap(); println!("parsed comments: {:#?}", comments); assert_eq!(comments.revisioned.len(), 1); let revisioned = &comments.revisioned[&vec![]]; let ErrorMatchKind::Pattern { pattern, .. } = &revisioned.error_matches[0].kind else { panic!("expected pattern matcher"); }; - assert_eq!(pattern.line().get(), 5); + assert_eq!(line!(&pattern.span, s), 5); match &**pattern { Pattern::SubString(s) => { assert_eq!( @@ -42,14 +71,24 @@ fn main() { let _x: i32 = 0u32; //~ E0308 } "; - let comments = Comments::parse(s, &Config::rustc(""), Path::new("")).unwrap(); + let comments = Comments::parse( + Spanned::new( + s.as_bytes(), + Span { + file: PathBuf::new(), + bytes: 0..s.len(), + }, + ), + &Config::rustc(""), + ) + .unwrap(); println!("parsed comments: {:#?}", comments); assert_eq!(comments.revisioned.len(), 1); let revisioned = &comments.revisioned[&vec![]]; let ErrorMatchKind::Code(code) = &revisioned.error_matches[0].kind else { panic!("expected diagnostic code matcher"); }; - assert_eq!(code.line().get(), 3); + assert_eq!(line!(&code.span, s), 3); assert_eq!(**code, "E0308"); } @@ -62,11 +101,21 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ encountered a dangling reference (address $HEX is unallocated) } "; - let errors = Comments::parse(s, &Config::rustc(""), Path::new("")).unwrap_err(); + let errors = Comments::parse( + Spanned::new( + s.as_bytes(), + Span { + file: PathBuf::new(), + bytes: 0..s.len(), + }, + ), + &Config::rustc(""), + ) + .unwrap_err(); println!("parsed comments: {:#?}", errors); assert_eq!(errors.len(), 1); match &errors[0] { - Error::InvalidComment { msg, span } if span.line_start.get() == 5 => { + Error::InvalidComment { msg, span } if line!(span, s) == 5 => { assert_eq!(msg, "text found after error code `encountered`") } _ => unreachable!(), @@ -80,13 +129,23 @@ fn parse_slash_slash_at() { use std::mem; "; - let comments = Comments::parse(s, &Config::rustc(""), Path::new("")).unwrap(); + let comments = Comments::parse( + Spanned::new( + s.as_bytes(), + Span { + file: PathBuf::new(), + bytes: 0..s.len(), + }, + ), + &Config::rustc(""), + ) + .unwrap(); println!("parsed comments: {:#?}", comments); assert_eq!(comments.revisioned.len(), 1); let revisioned = &comments.revisioned[&vec![]]; let pat = &revisioned.error_in_other_files[0]; assert_eq!(format!("{:?}", **pat), r#"SubString("foomp")"#); - assert_eq!(pat.line().get(), 2); + assert_eq!(line!(pat.span, s), 2); } #[test] @@ -96,13 +155,23 @@ fn parse_regex_error_pattern() { use std::mem; "; - let comments = Comments::parse(s, &Config::rustc(""), Path::new("")).unwrap(); + let comments = Comments::parse( + Spanned::new( + s.as_bytes(), + Span { + file: PathBuf::new(), + bytes: 0..s.len(), + }, + ), + &Config::rustc(""), + ) + .unwrap(); println!("parsed comments: {:#?}", comments); assert_eq!(comments.revisioned.len(), 1); let revisioned = &comments.revisioned[&vec![]]; let pat = &revisioned.error_in_other_files[0]; assert_eq!(format!("{:?}", **pat), r#"Regex(Regex("foomp"))"#); - assert_eq!(pat.line().get(), 2); + assert_eq!(line!(pat.span, s), 2); } #[test] @@ -112,17 +181,27 @@ fn parse_slash_slash_at_fail() { use std::mem; "; - let errors = Comments::parse(s, &Config::rustc(""), Path::new("")).unwrap_err(); + let errors = Comments::parse( + Spanned::new( + s.as_bytes(), + Span { + file: PathBuf::new(), + bytes: 0..s.len(), + }, + ), + &Config::rustc(""), + ) + .unwrap_err(); println!("parsed comments: {:#?}", errors); assert_eq!(errors.len(), 2); match &errors[0] { - Error::InvalidComment { msg, span } if span.line_start.get() == 2 => { + Error::InvalidComment { msg, span } if line!(span, s) == 2 => { assert!(msg.contains("must be followed by `:`")) } _ => unreachable!(), } match &errors[1] { - Error::InvalidComment { msg, span } if span.line_start.get() == 2 => { + Error::InvalidComment { msg, span } if line!(span, s) == 2 => { assert_eq!(msg, "`error-patttern` is not a command known to `ui_test`, did you mean `error-pattern`?"); } _ => unreachable!(), @@ -136,11 +215,21 @@ fn missing_colon_fail() { use std::mem; "; - let errors = Comments::parse(s, &Config::rustc(""), Path::new("")).unwrap_err(); + let errors = Comments::parse( + Spanned::new( + s.as_bytes(), + Span { + file: PathBuf::new(), + bytes: 0..s.len(), + }, + ), + &Config::rustc(""), + ) + .unwrap_err(); println!("parsed comments: {:#?}", errors); assert_eq!(errors.len(), 1); match &errors[0] { - Error::InvalidComment { msg, span } if span.line_start.get() == 2 => { + Error::InvalidComment { msg, span } if line!(span, s) == 2 => { assert!(msg.contains("must be followed by `:`")) } _ => unreachable!(), @@ -150,7 +239,17 @@ use std::mem; #[test] fn parse_x86_64() { let s = r"//@ only-target-x86_64-unknown-linux"; - let comments = Comments::parse(s, &Config::rustc(""), Path::new("")).unwrap(); + let comments = Comments::parse( + Spanned::new( + s.as_bytes(), + Span { + file: PathBuf::new(), + bytes: 0..s.len(), + }, + ), + &Config::rustc(""), + ) + .unwrap(); println!("parsed comments: {:#?}", comments); assert_eq!(comments.revisioned.len(), 1); let revisioned = &comments.revisioned[&vec![]]; diff --git a/src/per_test_config.rs b/src/per_test_config.rs index 16748e66..794cbef7 100644 --- a/src/per_test_config.rs +++ b/src/per_test_config.rs @@ -368,13 +368,7 @@ impl TestConfig<'_> { if !msgs.is_empty() { let line = NonZeroUsize::new(line).expect("line 0 is always empty"); errors.push(Error::ErrorsWithoutPattern { - path: Some(Spanned::new( - self.status.path().to_path_buf(), - spanned::Span { - line_start: line, - ..spanned::Span::default() - }, - )), + path: Some((self.status.path().to_path_buf(), line)), msgs, }); } diff --git a/src/rustc_stderr.rs b/src/rustc_stderr.rs index eae180ee..17e1082d 100644 --- a/src/rustc_stderr.rs +++ b/src/rustc_stderr.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use crate::diagnostics::{Diagnostics, Message}; -fn diag_line(diag: &Diagnostic, file: &Path) -> Option { +fn diag_line(diag: &Diagnostic, file: &Path) -> Option<(spanned::Span, usize)> { let span = |primary| { diag.spans .iter() @@ -20,20 +20,21 @@ fn insert_recursive( file: &Path, messages: &mut Vec>, messages_from_unknown_file_or_line: &mut Vec, - line: Option, + line: Option<(spanned::Span, usize)>, ) { let line = diag_line(&diag, file).or(line); let msg = Message { level: diag.level.into(), message: diag.message, - line_col: line.clone(), + line: line.as_ref().map(|&(_, l)| l), + span: line.as_ref().map(|(s, _)| s.clone()), code: diag.code.map(|x| x.code), }; - if let Some(line) = line.clone() { - if messages.len() <= line.line_start.get() { - messages.resize_with(line.line_start.get() + 1, Vec::new); + if let Some((_, line)) = line.clone() { + if messages.len() <= line { + messages.resize_with(line + 1, Vec::new); } - messages[line.line_start.get()].push(msg); + messages[line].push(msg); // All other messages go into the general bin, unless they are specifically of the // "aborting due to X previous errors" variety, as we never want to match those. They // only count the number of errors and provide no useful information about the tests. @@ -54,7 +55,7 @@ fn insert_recursive( } /// Returns the most expanded line number *in the given file*, if possible. -fn span_line(span: &DiagnosticSpan, file: &Path, primary: bool) -> Option { +fn span_line(span: &DiagnosticSpan, file: &Path, primary: bool) -> Option<(spanned::Span, usize)> { let file_name = PathBuf::from(&span.file_name); if let Some(exp) = &span.expansion { if let Some(line) = span_line(&exp.span, file, !primary || span.is_primary) { @@ -69,13 +70,14 @@ fn span_line(span: &DiagnosticSpan, file: &Path, primary: bool) -> Option { - let annot = [("expected because of this annotation", Some(span.clone()))]; - let mut lines: Vec<(&[_], _)> = vec![(&annot, span.line_start)]; - let annot = [("expected because of this mode change", Some(mode.clone()))]; + let annot = [("expected because of this annotation", span.clone())]; + let mut lines: Vec<&[_]> = vec![&annot]; + let annot = [("expected because of this mode change", mode.clone())]; if !mode.is_dummy() { - lines.push((&annot, mode.line_start)) + lines.push(&annot) } // This will print a suitable error header. create_error("error pattern found in pass test", &lines, path); @@ -619,8 +610,7 @@ fn print_error(error: &Error, path: &Path) { crate::diff::print_diff(expected, actual); } Error::ErrorsWithoutPattern { path, msgs } => { - if let Some(path) = path.as_ref() { - let line = path.line(); + if let Some((path, _)) = path.as_ref() { let msgs = msgs .iter() .map(|msg| { @@ -630,19 +620,16 @@ fn print_error(error: &Error, path: &Path) { } _ => format!("{:?}: {}", msg.level, msg.message), }; - (text, msg.line_col.clone()) + (text, msg.span.clone().unwrap_or_default()) }) .collect::>(); // This will print a suitable error header. create_error( format!("there were {} unmatched diagnostics", msgs.len()), - &[( - &msgs - .iter() - .map(|(msg, lc)| (msg.as_ref(), lc.clone().map(Into::into))) - .collect::>(), - line, - )], + &[&msgs + .iter() + .map(|(msg, lc)| (msg.as_ref(), lc.clone())) + .collect::>()], path, ); } else { @@ -653,8 +640,9 @@ fn print_error(error: &Error, path: &Path) { for Message { level, message, - line_col: _, + line: _, code: _, + span: _, } in msgs { println!(" {level:?}: {message}") @@ -663,17 +651,14 @@ fn print_error(error: &Error, path: &Path) { } Error::InvalidComment { msg, span } => { // This will print a suitable error header. - create_error(msg, &[(&[("", Some(span.clone()))], span.line_start)], path) + create_error(msg, &[&[("", span.clone())]], path) } Error::MultipleRevisionsWithResults { kind, lines } => { let title = format!("multiple {kind} found"); // This will print a suitable error header. create_error( title, - &lines - .iter() - .map(|&line| (&[] as &[_], line)) - .collect::>(), + &lines.iter().map(|_line| &[] as &[_]).collect::>(), path, ) } @@ -684,12 +669,12 @@ fn print_error(error: &Error, path: &Path) { Error::Aux { path: aux_path, errors, - line, } => { - print_error_header(format_args!( - "aux build from {}:{line} failed", - display(path) - )); + create_error( + "aux build failed", + &[&[(&path.display().to_string(), aux_path.span.clone())]], + &aux_path.span.file, + ); for error in errors { print_error(error, aux_path); } @@ -708,49 +693,32 @@ fn print_error(error: &Error, path: &Path) { } #[allow(clippy::type_complexity)] -fn create_error( - s: impl AsRef, - lines: &[(&[(&str, Option)], NonZeroUsize)], - file: &Path, -) { +fn create_error(s: impl AsRef, lines: &[&[(&str, Span)]], file: &Path) { let source = std::fs::read_to_string(file).unwrap(); - let source: Vec<_> = source.split_inclusive('\n').collect(); let file = display(file); let mut msg = annotate_snippets::Level::Error.title(s.as_ref()); - for &(label, line) in lines { - let Some(source) = source.get(line.get() - 1) else { - for (label, _) in label { - let footer = annotate_snippets::Level::Note.title(label); - msg = msg.footer(footer); - } - - continue; - }; - let len = source.len(); - let snippet = Snippet::source(source) - .line_start(line.get()) - .origin(&file) - .annotations(label.iter().map(|(label, lc)| { + for &label in lines { + let annotations = label + .iter() + .filter(|(_, span)| !span.is_dummy()) + .map(|(label, span)| { annotate_snippets::Level::Error - .span(lc.as_ref().map_or(0..len - 1, |lc| { - assert_eq!(lc.line_start, line); - if lc.line_end > lc.line_start { - lc.col_start.get() - 1..len - 1 - } else if lc.col_start == lc.col_end { - if lc.col_start.get() - 1 == len { - // rustc sometimes produces spans pointing *after* the `\n` at the end of the line, - // but we want to render an annotation at the end. - lc.col_start.get() - 2..lc.col_start.get() - 1 - } else { - lc.col_start.get() - 1..lc.col_start.get() - } - } else { - lc.col_start.get() - 1..lc.col_end.get() - 1 - } - })) + .span(span.bytes.clone()) .label(label) - })); - msg = msg.snippet(snippet); + }) + .collect::>(); + if !annotations.is_empty() { + let snippet = Snippet::source(&source) + .fold(true) + .origin(&file) + .annotations(annotations); + msg = msg.snippet(snippet); + } + let footer = label + .iter() + .filter(|(_, span)| span.is_dummy()) + .map(|(label, _)| annotate_snippets::Level::Note.title(label)); + msg = msg.footers(footer); } let renderer = if colored::control::SHOULD_COLORIZE.should_colorize() { Renderer::styled() @@ -761,6 +729,14 @@ fn create_error( } fn gha_error(error: &Error, test_path: &str, revision: &str) { + let file = Spanned::read_from_file(test_path).unwrap(); + let line = |span: &Span| { + let line = file + .lines() + .position(|line| line.span.bytes.contains(&span.bytes.start)) + .unwrap(); + NonZeroUsize::new(line + 1).unwrap() + }; match error { Error::ExitStatus { status, @@ -778,11 +754,11 @@ fn gha_error(error: &Error, test_path: &str, revision: &str) { } Error::PatternNotFound { pattern, .. } => { github_actions::error(test_path, format!("Pattern not found{revision}")) - .line(pattern.line()); + .line(line(&pattern.span)); } Error::CodeNotFound { code, .. } => { github_actions::error(test_path, format!("Diagnostic code not found{revision}")) - .line(code.line()); + .line(line(&code.span)); } Error::NoPatternsFound => { github_actions::error( @@ -862,16 +838,16 @@ fn gha_error(error: &Error, test_path: &str, revision: &str) { } } Error::ErrorsWithoutPattern { path, msgs } => { - if let Some(path) = path.as_ref() { - let line = path.line(); + if let Some((path, line)) = path.as_ref() { let path = display(path); let mut err = github_actions::error(path, format!("Unmatched diagnostics{revision}")) - .line(line); + .line(*line); for Message { level, message, - line_col: _, + line: _, + span: _, code: _, } in msgs { @@ -885,7 +861,8 @@ fn gha_error(error: &Error, test_path: &str, revision: &str) { for Message { level, message, - line_col: _, + line: _, + span: _, code: _, } in msgs { @@ -895,19 +872,20 @@ fn gha_error(error: &Error, test_path: &str, revision: &str) { } Error::InvalidComment { msg, span } => { let mut err = github_actions::error(test_path, format!("Could not parse comment")) - .line(span.line_start); + .line(line(span)); writeln!(err, "{msg}").unwrap(); } Error::MultipleRevisionsWithResults { kind, lines } => { - github_actions::error(test_path, format!("multiple {kind} found")).line(lines[0]); + github_actions::error(test_path, format!("multiple {kind} found")) + .line(line(&lines[0])); } Error::Bug(_) => {} Error::Aux { path: aux_path, errors, - line, } => { - github_actions::error(test_path, format!("Aux build failed")).line(*line); + github_actions::error(test_path, format!("Aux build failed")) + .line(line(&aux_path.span)); for error in errors { gha_error(error, &display(aux_path), "") } diff --git a/src/tests.rs b/src/tests.rs index f225226b..2262b4ea 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use spanned::Spanned; +use spanned::{Span, Spanned}; use crate::diagnostics::Level; use crate::diagnostics::Message; @@ -18,7 +18,17 @@ fn config() -> Config { macro_rules! config { ($config:ident = $s:expr) => { let path = Path::new("moobar"); - let comments = Comments::parse($s, &$config, path).unwrap(); + let comments = Comments::parse( + Spanned::new( + $s.as_bytes(), + Span { + file: path.to_path_buf(), + bytes: 0..$s.len(), + }, + ), + &$config, + ) + .unwrap(); #[allow(unused_mut)] let mut $config = TestConfig { config: $config, @@ -32,6 +42,23 @@ macro_rules! config { }; } +macro_rules! line { + ($thing:expr, $s:expr) => {{ + let file = Spanned::new( + $s.as_bytes(), + Span { + file: PathBuf::new(), + bytes: 0..$s.len(), + }, + ); + let pos = file + .lines() + .position(|line| line.span.bytes.contains(&$thing.bytes.start)) + .unwrap(); + pos + 1 + }}; +} + #[test] fn issue_2156() { let s = r" @@ -50,7 +77,8 @@ fn main() { Message { message:"Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, } ] @@ -60,7 +88,8 @@ fn main() { .unwrap(); match &errors[..] { [Error::PatternNotFound { pattern, .. }, Error::ErrorsWithoutPattern { path, .. }] - if path.as_ref().is_some_and(|p| p.line().get() == 5) && pattern.line().get() == 5 => {} + if path.as_ref().is_some_and(|(_p, line)| line.get() == 5) + && line!(pattern.span, s) == 5 => {} _ => panic!("{:#?}", errors), } } @@ -81,7 +110,8 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, } ] @@ -102,7 +132,8 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, } ] @@ -113,8 +144,8 @@ fn main() { .unwrap(); match &errors[..] { [Error::PatternNotFound { pattern, .. }, Error::ErrorsWithoutPattern { path, .. }] - if path.as_ref().is_some_and(|p| p.line().get() == 4) - && pattern.line().get() == 5 => {} + if path.as_ref().is_some_and(|(_, line)| line.get() == 4) + && line!(pattern.span, s) == 5 => {} _ => panic!("not the expected error: {:#?}", errors), } } @@ -127,7 +158,8 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Note, - line_col: None, + line: None, + span: None, code: None, } ] @@ -138,7 +170,7 @@ fn main() { .unwrap(); match &errors[..] { // Note no `ErrorsWithoutPattern`, because there are no `//~NOTE` in the test file, so we ignore them - [Error::PatternNotFound { pattern, .. }] if pattern.line().get() == 5 => {} + [Error::PatternNotFound { pattern, .. }] if line!(pattern.span, s) == 5 => {} _ => panic!("not the expected error: {:#?}", errors), } } @@ -162,7 +194,8 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, } ] @@ -172,7 +205,7 @@ fn main() { .check_annotations(messages, vec![], &mut errors) .unwrap(); match &errors[..] { - [Error::PatternNotFound { pattern, .. }] if pattern.line().get() == 6 => {} + [Error::PatternNotFound { pattern, .. }] if line!(pattern.span, s) == 6 => {} _ => panic!("{:#?}", errors), } } @@ -194,13 +227,15 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, }, Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, } ] @@ -211,7 +246,7 @@ fn main() { .unwrap(); match &errors[..] { [Error::ErrorsWithoutPattern { path, .. }] - if path.as_ref().is_some_and(|p| p.line().get() == 5) => {} + if path.as_ref().is_some_and(|(_, line)| line.get() == 5) => {} _ => panic!("{:#?}", errors), } } @@ -238,19 +273,22 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, }, Message { message: "kaboom".to_string(), level: Level::Warn, - line_col: None, + line: None, + span: None, code: None, }, Message { message: "cake".to_string(), level: Level::Warn, - line_col: None, + line: None, + span: None, code: None, }, ], @@ -261,13 +299,14 @@ fn main() { .unwrap(); match &errors[..] { [Error::ErrorsWithoutPattern { path, msgs, .. }] - if path.as_ref().is_some_and(|p| p.line().get() == 5) => + if path.as_ref().is_some_and(|(_, line)| line.get() == 5) => { match &msgs[..] { [Message { message, level: Level::Warn, - line_col: _, + line: _, + span: _, code: None, }] if message == "kaboom" => {} _ => panic!("{:#?}", msgs), @@ -299,19 +338,22 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, }, Message { message: "kaboom".to_string(), level: Level::Warn, - line_col: None, + line: None, + span: None, code: None, }, Message { message: "cake".to_string(), level: Level::Warn, - line_col: None, + line: None, + span: None, code: None, }, ], @@ -343,7 +385,8 @@ fn main() { vec![Message { message: "mismatched types".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: Some("E0308".into()), }], ]; @@ -366,7 +409,8 @@ fn main() { vec![Message { message: "mismatched types".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: Some("SomeError".into()), }], ]; @@ -376,7 +420,7 @@ fn main() { .unwrap(); match &errors[..] { [Error::CodeNotFound { code, .. }, Error::ErrorsWithoutPattern { msgs, .. }] - if **code == "E0308" && code.line().get() == 3 && msgs.len() == 1 => {} + if **code == "E0308" && line!(code.span, s) == 3 && msgs.len() == 1 => {} _ => panic!("{:#?}", errors), } } @@ -390,7 +434,8 @@ fn main() { vec![Message { message: "mismatched types".to_string(), level: Level::Warn, - line_col: None, + line: None, + span: None, code: Some("E0308".into()), }], ]; @@ -399,7 +444,8 @@ fn main() { .check_annotations(messages, vec![], &mut errors) .unwrap(); match &errors[..] { - [Error::CodeNotFound { code, .. }] if **code == "E0308" && code.line().get() == 3 => {} + [Error::CodeNotFound { code, .. }] if **code == "E0308" && line!(code.span, s) == 3 => { + } _ => panic!("{:#?}", errors), } } @@ -424,7 +470,8 @@ fn main() { vec![Message { message: "mismatched types".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: Some("prefix::E0308".into()), }], ]; @@ -447,7 +494,8 @@ fn main() { vec![Message { message: "mismatched types".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: Some("E0308".into()), }], ]; @@ -457,7 +505,7 @@ fn main() { .unwrap(); match &errors[..] { [Error::CodeNotFound { code, .. }, Error::ErrorsWithoutPattern { msgs, .. }] - if **code == "prefix::E0308" && code.line().get() == 3 && msgs.len() == 1 => {} + if **code == "prefix::E0308" && line!(code.span, s) == 3 && msgs.len() == 1 => {} _ => panic!("{:#?}", errors), } } diff --git a/tests/integration.rs b/tests/integration.rs index 845f6a3f..0c50926f 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -139,7 +139,7 @@ fn main() -> Result<()> { && default_any_file_filter(path, config), ) }, - |_, _, _| {}, + |_, _| {}, ( text, ui_test::status_emitter::Gha:: { diff --git a/tests/integrations/basic-bin/Cargo.lock b/tests/integrations/basic-bin/Cargo.lock index 1207fc73..71bc833f 100644 --- a/tests/integrations/basic-bin/Cargo.lock +++ b/tests/integrations/basic-bin/Cargo.lock @@ -597,9 +597,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -716,7 +716,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/tests/integrations/basic-fail-mode/Cargo.lock b/tests/integrations/basic-fail-mode/Cargo.lock index fbf8cdec..a1c4d89d 100644 --- a/tests/integrations/basic-fail-mode/Cargo.lock +++ b/tests/integrations/basic-fail-mode/Cargo.lock @@ -597,9 +597,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -716,7 +716,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/tests/integrations/basic-fail/Cargo.lock b/tests/integrations/basic-fail/Cargo.lock index a0962282..1c0e9dbb 100644 --- a/tests/integrations/basic-fail/Cargo.lock +++ b/tests/integrations/basic-fail/Cargo.lock @@ -597,9 +597,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -716,7 +716,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/tests/integrations/basic-fail/Cargo.stdout b/tests/integrations/basic-fail/Cargo.stdout index c7162fb5..39e6499f 100644 --- a/tests/integrations/basic-fail/Cargo.stdout +++ b/tests/integrations/basic-fail/Cargo.stdout @@ -504,6 +504,7 @@ tests/actual_tests_bless/rustfix-fail-revisions.b.fixed (revision `b`) ... FAILE tests/actual_tests_bless/rustfix-fail-revisions.rs (revision `b`) ... ok tests/actual_tests_bless/rustfix-fail.fixed ... FAILED tests/actual_tests_bless/rustfix-fail.rs ... ok +tests/actual_tests_bless/unicode.rs ... FAILED tests/actual_tests_bless/unknown_revision.rs ... FAILED tests/actual_tests_bless/unknown_revision2.rs ... FAILED tests/actual_tests_bless/wrong_diagnostic_code.rs ... FAILED @@ -637,7 +638,7 @@ error: test got exit status: 101, but expected 0 --> tests/actual_tests_bless/failing_executable.rs:4:5 | 4 | assert_eq!(5, 6); - | ^ assertion `left == right` failed + | ^^^^^^^^^^^^^^^^^ assertion `left == right` failed | full stderr: @@ -801,7 +802,7 @@ error: test got exit status: 101, but expected 0 --> tests/actual_tests_bless/revisioned_executable_panic.rs | 6 | panic!() - | ^ explicit panic + | ^^^^^^^^ explicit panic | full stderr: @@ -938,6 +939,38 @@ full stdout: +FAILED TEST: tests/actual_tests_bless/unicode.rs +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests_bless/unicode.rs" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" + +error: test got exit status: 0, but expected 1 + = note: compilation succeeded, but was expected to fail + +error: expected error patterns, but found none + +full stderr: +warning: unused variable: `Ě电脑` + --> tests/actual_tests_bless/unicode.rs:7:9 + | +7 | let Ě电脑 = 1; + | ^^^^^ help: if this is intentional, prefix it with an underscore: `_Ě电脑` + | + = note: `#[warn(unused_variables)]` on by default + +warning: variable `Ě电脑` should have a snake case name + --> tests/actual_tests_bless/unicode.rs:7:9 + | +7 | let Ě电脑 = 1; + | ^^^^^ help: convert the identifier to snake case: `ě电脑` + | + = note: `#[warn(non_snake_case)]` on by default + +warning: 2 warnings emitted + + +full stdout: + + + FAILED TEST: tests/actual_tests_bless/unknown_revision.rs command: parse comments @@ -1040,11 +1073,12 @@ FAILURES: tests/actual_tests_bless/rustfix-fail-revisions.a.fixed (revision a) tests/actual_tests_bless/rustfix-fail-revisions.b.fixed (revision b) tests/actual_tests_bless/rustfix-fail.fixed + tests/actual_tests_bless/unicode.rs tests/actual_tests_bless/unknown_revision.rs tests/actual_tests_bless/unknown_revision2.rs tests/actual_tests_bless/wrong_diagnostic_code.rs -test result: FAIL. 22 failed; 24 passed; 3 ignored; +test result: FAIL. 23 failed; 24 passed; 3 ignored; Building dependencies ... ok tests/actual_tests_bless_yolo/revisions_bad.rs (revision `foo`) ... ok diff --git a/tests/integrations/basic-fail/tests/actual_tests_bless/unicode.rs b/tests/integrations/basic-fail/tests/actual_tests_bless/unicode.rs new file mode 100644 index 00000000..d9e54ab5 --- /dev/null +++ b/tests/integrations/basic-fail/tests/actual_tests_bless/unicode.rs @@ -0,0 +1,8 @@ +#![deny(confusable_idents)] + +// Test that a missing annotation causing a +// ui_test diagnostic will not ICE due to byte vs char offsets. + +fn main() { + let Ě电脑 = 1; +} diff --git a/tests/integrations/basic-fail/tests/actual_tests_bless/unicode.stderr b/tests/integrations/basic-fail/tests/actual_tests_bless/unicode.stderr new file mode 100644 index 00000000..b92bcd9e --- /dev/null +++ b/tests/integrations/basic-fail/tests/actual_tests_bless/unicode.stderr @@ -0,0 +1,18 @@ +warning: unused variable: `Ě电脑` + --> tests/actual_tests_bless/unicode.rs:7:9 + | +7 | let Ě电脑 = 1; + | ^^^^^ help: if this is intentional, prefix it with an underscore: `_Ě电脑` + | + = note: `#[warn(unused_variables)]` on by default + +warning: variable `Ě电脑` should have a snake case name + --> tests/actual_tests_bless/unicode.rs:7:9 + | +7 | let Ě电脑 = 1; + | ^^^^^ help: convert the identifier to snake case: `ě电脑` + | + = note: `#[warn(non_snake_case)]` on by default + +warning: 2 warnings emitted + diff --git a/tests/integrations/basic/Cargo.lock b/tests/integrations/basic/Cargo.lock index 85fbb093..1039bba3 100644 --- a/tests/integrations/basic/Cargo.lock +++ b/tests/integrations/basic/Cargo.lock @@ -522,9 +522,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -639,7 +639,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/tests/integrations/cargo-run/Cargo.lock b/tests/integrations/cargo-run/Cargo.lock index 1207fc73..71bc833f 100644 --- a/tests/integrations/cargo-run/Cargo.lock +++ b/tests/integrations/cargo-run/Cargo.lock @@ -597,9 +597,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -716,7 +716,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/tests/integrations/cargo-run/tests/ui_tests.rs b/tests/integrations/cargo-run/tests/ui_tests.rs index 9b3f6d05..57d09d75 100644 --- a/tests/integrations/cargo-run/tests/ui_tests.rs +++ b/tests/integrations/cargo-run/tests/ui_tests.rs @@ -19,7 +19,7 @@ fn main() -> ui_test::color_eyre::Result<()> { run_tests_generic( vec![config], default_file_filter, - |_config, _path, _content| {}, + |_config, _content| {}, // Avoid github actions, as these would end up showing up in `Cargo.stderr` status_emitter::Text::verbose(), ) diff --git a/tests/integrations/dep-fail/Cargo.lock b/tests/integrations/dep-fail/Cargo.lock index 5f392a44..f90b0357 100644 --- a/tests/integrations/dep-fail/Cargo.lock +++ b/tests/integrations/dep-fail/Cargo.lock @@ -461,9 +461,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -565,7 +565,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/tests/integrations/ui_test_dep_bug/Cargo.lock b/tests/integrations/ui_test_dep_bug/Cargo.lock index 1d8cb9ee..0e51e6ce 100644 --- a/tests/integrations/ui_test_dep_bug/Cargo.lock +++ b/tests/integrations/ui_test_dep_bug/Cargo.lock @@ -462,9 +462,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -570,7 +570,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow",