@@ -182,10 +182,10 @@ pub fn report_install_failed(dep: &Dependency, detail: &str) {
182182fn hints_for ( err : & Error ) -> Vec < String > {
183183 match err {
184184 Error :: ReadSpec { path, source } => {
185- return io_read_hints ( "spec" , path, source. kind ( ) ) ;
185+ return io_read_hints ( "spec file " , path, source. kind ( ) ) ;
186186 }
187187 Error :: ReadConfig { path, source } => {
188- return io_read_hints ( "config" , path, source. kind ( ) ) ;
188+ return io_read_hints ( "config file " , path, source. kind ( ) ) ;
189189 }
190190 Error :: ReadRefFile { file, source } => {
191191 return io_read_hints ( "referenced file" , file, source. kind ( ) ) ;
@@ -250,11 +250,15 @@ fn hints_for(err: &Error) -> Vec<String> {
250250}
251251
252252/// Hints for a failed read, keyed on the underlying IO error kind.
253+ ///
254+ /// `what` names the kind of file, and the caller supplies the whole noun phrase
255+ /// (for example `spec file`). Every message below reads it as one noun, so no
256+ /// message adds a word of its own to it.
253257fn io_read_hints ( what : & str , path : & str , kind : ErrorKind ) -> Vec < String > {
254258 match kind {
255259 ErrorKind :: NotFound => {
256260 return vec ! [ format!(
257- "No {what} file exists at `{path}`; check the path and your working directory."
261+ "No {what} exists at `{path}`; check the path and your working directory."
258262 ) ] ;
259263 }
260264 ErrorKind :: PermissionDenied => {
@@ -419,6 +423,26 @@ mod tests {
419423 ) ;
420424 }
421425
426+ /// Every caller of [`io_read_hints`] must pass a complete noun phrase. A
427+ /// caller that passes `referenced` instead of `referenced file` reads as
428+ /// "No referenced exists at", and one that also adds `file` inside the
429+ /// message reads as "No referenced file file exists at". This pins the three
430+ /// call sites so neither mistake returns.
431+ #[ test]
432+ fn read_hints_name_the_file_kind_one_time ( ) {
433+ for ( what, expected) in [
434+ ( "spec file" , "No spec file exists at `x.yaml`" ) ,
435+ ( "config file" , "No config file exists at `x.yaml`" ) ,
436+ ( "referenced file" , "No referenced file exists at `x.yaml`" ) ,
437+ ] {
438+ let hints = io_read_hints ( what, "x.yaml" , ErrorKind :: NotFound ) ;
439+ assert ! (
440+ hints. iter( ) . any( |hint| return hint. starts_with( expected) ) ,
441+ "hint for `{what}` should start with `{expected}`, got: {hints:?}" ,
442+ ) ;
443+ }
444+ }
445+
422446 #[ test]
423447 fn invalid_path_parameter_hint_guides_the_fix ( ) {
424448 let err = Error :: InvalidPathParameter {
0 commit comments