Fix Windows test failures not being detected in CI (#36446)

Bug introduced in #35926 

Release Notes:

- N/A
This commit is contained in:
Cole Miller 2025-08-19 10:53:10 -04:00 committed by GitHub
parent 6c255c1973
commit 1444cd9839
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 87 additions and 114 deletions

View file

@ -56,7 +56,6 @@ runs:
$env:COMPlus_CreateDumpDiagnostics = "1" $env:COMPlus_CreateDumpDiagnostics = "1"
cargo nextest run --workspace --no-fail-fast cargo nextest run --workspace --no-fail-fast
continue-on-error: true
- name: Analyze crash dumps - name: Analyze crash dumps
if: always() if: always()

View file

@ -2155,7 +2155,7 @@ mod tests {
"} "}
); );
}); });
assert_eq!(fs.files(), vec![Path::new("/test/file-0")]); assert_eq!(fs.files(), vec![Path::new(path!("/test/file-0"))]);
cx.update(|cx| thread.update(cx, |thread, cx| thread.send(vec!["ipsum".into()], cx))) cx.update(|cx| thread.update(cx, |thread, cx| thread.send(vec!["ipsum".into()], cx)))
.await .await
@ -2185,7 +2185,10 @@ mod tests {
}); });
assert_eq!( assert_eq!(
fs.files(), fs.files(),
vec![Path::new("/test/file-0"), Path::new("/test/file-1")] vec![
Path::new(path!("/test/file-0")),
Path::new(path!("/test/file-1"))
]
); );
// Checkpoint isn't stored when there are no changes. // Checkpoint isn't stored when there are no changes.
@ -2226,7 +2229,10 @@ mod tests {
}); });
assert_eq!( assert_eq!(
fs.files(), fs.files(),
vec![Path::new("/test/file-0"), Path::new("/test/file-1")] vec![
Path::new(path!("/test/file-0")),
Path::new(path!("/test/file-1"))
]
); );
// Rewinding the conversation truncates the history and restores the checkpoint. // Rewinding the conversation truncates the history and restores the checkpoint.
@ -2254,7 +2260,7 @@ mod tests {
"} "}
); );
}); });
assert_eq!(fs.files(), vec![Path::new("/test/file-0")]); assert_eq!(fs.files(), vec![Path::new(path!("/test/file-0"))]);
} }
async fn run_until_first_tool_call( async fn run_until_first_tool_call(

View file

@ -52,6 +52,7 @@ impl MentionUri {
let path = url.path(); let path = url.path();
match url.scheme() { match url.scheme() {
"file" => { "file" => {
let path = url.to_file_path().ok().context("Extracting file path")?;
if let Some(fragment) = url.fragment() { if let Some(fragment) = url.fragment() {
let range = fragment let range = fragment
.strip_prefix("L") .strip_prefix("L")
@ -72,23 +73,17 @@ impl MentionUri {
if let Some(name) = single_query_param(&url, "symbol")? { if let Some(name) = single_query_param(&url, "symbol")? {
Ok(Self::Symbol { Ok(Self::Symbol {
name, name,
path: path.into(), path,
line_range, line_range,
}) })
} else { } else {
Ok(Self::Selection { Ok(Self::Selection { path, line_range })
path: path.into(),
line_range,
})
} }
} else { } else {
let abs_path =
PathBuf::from(format!("{}{}", url.host_str().unwrap_or(""), path));
if input.ends_with("/") { if input.ends_with("/") {
Ok(Self::Directory { abs_path }) Ok(Self::Directory { abs_path: path })
} else { } else {
Ok(Self::File { abs_path }) Ok(Self::File { abs_path: path })
} }
} }
} }
@ -162,27 +157,17 @@ impl MentionUri {
pub fn to_uri(&self) -> Url { pub fn to_uri(&self) -> Url {
match self { match self {
MentionUri::File { abs_path } => { MentionUri::File { abs_path } => {
let mut url = Url::parse("file:///").unwrap(); Url::from_file_path(abs_path).expect("mention path should be absolute")
let path = abs_path.to_string_lossy();
url.set_path(&path);
url
} }
MentionUri::Directory { abs_path } => { MentionUri::Directory { abs_path } => {
let mut url = Url::parse("file:///").unwrap(); Url::from_directory_path(abs_path).expect("mention path should be absolute")
let mut path = abs_path.to_string_lossy().to_string();
if !path.ends_with("/") {
path.push_str("/");
}
url.set_path(&path);
url
} }
MentionUri::Symbol { MentionUri::Symbol {
path, path,
name, name,
line_range, line_range,
} => { } => {
let mut url = Url::parse("file:///").unwrap(); let mut url = Url::from_file_path(path).expect("mention path should be absolute");
url.set_path(&path.to_string_lossy());
url.query_pairs_mut().append_pair("symbol", name); url.query_pairs_mut().append_pair("symbol", name);
url.set_fragment(Some(&format!( url.set_fragment(Some(&format!(
"L{}:{}", "L{}:{}",
@ -192,8 +177,7 @@ impl MentionUri {
url url
} }
MentionUri::Selection { path, line_range } => { MentionUri::Selection { path, line_range } => {
let mut url = Url::parse("file:///").unwrap(); let mut url = Url::from_file_path(path).expect("mention path should be absolute");
url.set_path(&path.to_string_lossy());
url.set_fragment(Some(&format!( url.set_fragment(Some(&format!(
"L{}:{}", "L{}:{}",
line_range.start + 1, line_range.start + 1,
@ -266,15 +250,17 @@ pub fn selection_name(path: &Path, line_range: &Range<u32>) -> String {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use util::{path, uri};
use super::*; use super::*;
#[test] #[test]
fn test_parse_file_uri() { fn test_parse_file_uri() {
let file_uri = "file:///path/to/file.rs"; let file_uri = uri!("file:///path/to/file.rs");
let parsed = MentionUri::parse(file_uri).unwrap(); let parsed = MentionUri::parse(file_uri).unwrap();
match &parsed { match &parsed {
MentionUri::File { abs_path } => { MentionUri::File { abs_path } => {
assert_eq!(abs_path.to_str().unwrap(), "/path/to/file.rs"); assert_eq!(abs_path.to_str().unwrap(), path!("/path/to/file.rs"));
} }
_ => panic!("Expected File variant"), _ => panic!("Expected File variant"),
} }
@ -283,11 +269,11 @@ mod tests {
#[test] #[test]
fn test_parse_directory_uri() { fn test_parse_directory_uri() {
let file_uri = "file:///path/to/dir/"; let file_uri = uri!("file:///path/to/dir/");
let parsed = MentionUri::parse(file_uri).unwrap(); let parsed = MentionUri::parse(file_uri).unwrap();
match &parsed { match &parsed {
MentionUri::Directory { abs_path } => { MentionUri::Directory { abs_path } => {
assert_eq!(abs_path.to_str().unwrap(), "/path/to/dir/"); assert_eq!(abs_path.to_str().unwrap(), path!("/path/to/dir/"));
} }
_ => panic!("Expected Directory variant"), _ => panic!("Expected Directory variant"),
} }
@ -297,22 +283,24 @@ mod tests {
#[test] #[test]
fn test_to_directory_uri_with_slash() { fn test_to_directory_uri_with_slash() {
let uri = MentionUri::Directory { let uri = MentionUri::Directory {
abs_path: PathBuf::from("/path/to/dir/"), abs_path: PathBuf::from(path!("/path/to/dir/")),
}; };
assert_eq!(uri.to_uri().to_string(), "file:///path/to/dir/"); let expected = uri!("file:///path/to/dir/");
assert_eq!(uri.to_uri().to_string(), expected);
} }
#[test] #[test]
fn test_to_directory_uri_without_slash() { fn test_to_directory_uri_without_slash() {
let uri = MentionUri::Directory { let uri = MentionUri::Directory {
abs_path: PathBuf::from("/path/to/dir"), abs_path: PathBuf::from(path!("/path/to/dir")),
}; };
assert_eq!(uri.to_uri().to_string(), "file:///path/to/dir/"); let expected = uri!("file:///path/to/dir/");
assert_eq!(uri.to_uri().to_string(), expected);
} }
#[test] #[test]
fn test_parse_symbol_uri() { fn test_parse_symbol_uri() {
let symbol_uri = "file:///path/to/file.rs?symbol=MySymbol#L10:20"; let symbol_uri = uri!("file:///path/to/file.rs?symbol=MySymbol#L10:20");
let parsed = MentionUri::parse(symbol_uri).unwrap(); let parsed = MentionUri::parse(symbol_uri).unwrap();
match &parsed { match &parsed {
MentionUri::Symbol { MentionUri::Symbol {
@ -320,7 +308,7 @@ mod tests {
name, name,
line_range, line_range,
} => { } => {
assert_eq!(path.to_str().unwrap(), "/path/to/file.rs"); assert_eq!(path.to_str().unwrap(), path!("/path/to/file.rs"));
assert_eq!(name, "MySymbol"); assert_eq!(name, "MySymbol");
assert_eq!(line_range.start, 9); assert_eq!(line_range.start, 9);
assert_eq!(line_range.end, 19); assert_eq!(line_range.end, 19);
@ -332,11 +320,11 @@ mod tests {
#[test] #[test]
fn test_parse_selection_uri() { fn test_parse_selection_uri() {
let selection_uri = "file:///path/to/file.rs#L5:15"; let selection_uri = uri!("file:///path/to/file.rs#L5:15");
let parsed = MentionUri::parse(selection_uri).unwrap(); let parsed = MentionUri::parse(selection_uri).unwrap();
match &parsed { match &parsed {
MentionUri::Selection { path, line_range } => { MentionUri::Selection { path, line_range } => {
assert_eq!(path.to_str().unwrap(), "/path/to/file.rs"); assert_eq!(path.to_str().unwrap(), path!("/path/to/file.rs"));
assert_eq!(line_range.start, 4); assert_eq!(line_range.start, 4);
assert_eq!(line_range.end, 14); assert_eq!(line_range.end, 14);
} }
@ -418,32 +406,35 @@ mod tests {
#[test] #[test]
fn test_invalid_line_range_format() { fn test_invalid_line_range_format() {
// Missing L prefix // Missing L prefix
assert!(MentionUri::parse("file:///path/to/file.rs#10:20").is_err()); assert!(MentionUri::parse(uri!("file:///path/to/file.rs#10:20")).is_err());
// Missing colon separator // Missing colon separator
assert!(MentionUri::parse("file:///path/to/file.rs#L1020").is_err()); assert!(MentionUri::parse(uri!("file:///path/to/file.rs#L1020")).is_err());
// Invalid numbers // Invalid numbers
assert!(MentionUri::parse("file:///path/to/file.rs#L10:abc").is_err()); assert!(MentionUri::parse(uri!("file:///path/to/file.rs#L10:abc")).is_err());
assert!(MentionUri::parse("file:///path/to/file.rs#Labc:20").is_err()); assert!(MentionUri::parse(uri!("file:///path/to/file.rs#Labc:20")).is_err());
} }
#[test] #[test]
fn test_invalid_query_parameters() { fn test_invalid_query_parameters() {
// Invalid query parameter name // Invalid query parameter name
assert!(MentionUri::parse("file:///path/to/file.rs#L10:20?invalid=test").is_err()); assert!(MentionUri::parse(uri!("file:///path/to/file.rs#L10:20?invalid=test")).is_err());
// Too many query parameters // Too many query parameters
assert!( assert!(
MentionUri::parse("file:///path/to/file.rs#L10:20?symbol=test&another=param").is_err() MentionUri::parse(uri!(
"file:///path/to/file.rs#L10:20?symbol=test&another=param"
))
.is_err()
); );
} }
#[test] #[test]
fn test_zero_based_line_numbers() { fn test_zero_based_line_numbers() {
// Test that 0-based line numbers are rejected (should be 1-based) // Test that 0-based line numbers are rejected (should be 1-based)
assert!(MentionUri::parse("file:///path/to/file.rs#L0:10").is_err()); assert!(MentionUri::parse(uri!("file:///path/to/file.rs#L0:10")).is_err());
assert!(MentionUri::parse("file:///path/to/file.rs#L1:0").is_err()); assert!(MentionUri::parse(uri!("file:///path/to/file.rs#L1:0")).is_err());
assert!(MentionUri::parse("file:///path/to/file.rs#L0:0").is_err()); assert!(MentionUri::parse(uri!("file:///path/to/file.rs#L0:0")).is_err());
} }
} }

View file

@ -1640,7 +1640,7 @@ mod tests {
use serde_json::json; use serde_json::json;
use text::Point; use text::Point;
use ui::{App, Context, IntoElement, Render, SharedString, Window}; use ui::{App, Context, IntoElement, Render, SharedString, Window};
use util::path; use util::{path, uri};
use workspace::{AppState, Item, Workspace}; use workspace::{AppState, Item, Workspace};
use crate::acp::{ use crate::acp::{
@ -1950,13 +1950,12 @@ mod tests {
editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx); editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx);
}); });
let url_one = uri!("file:///dir/a/one.txt");
editor.update(&mut cx, |editor, cx| { editor.update(&mut cx, |editor, cx| {
assert_eq!(editor.text(cx), "Lorem [@one.txt](file:///dir/a/one.txt) "); let text = editor.text(cx);
assert_eq!(text, format!("Lorem [@one.txt]({url_one}) "));
assert!(!editor.has_visible_completions_menu()); assert!(!editor.has_visible_completions_menu());
assert_eq!( assert_eq!(fold_ranges(editor, cx).len(), 1);
fold_ranges(editor, cx),
vec![Point::new(0, 6)..Point::new(0, 39)]
);
}); });
let contents = message_editor let contents = message_editor
@ -1977,47 +1976,35 @@ mod tests {
contents, contents,
[Mention::Text { [Mention::Text {
content: "1".into(), content: "1".into(),
uri: "file:///dir/a/one.txt".parse().unwrap() uri: url_one.parse().unwrap()
}] }]
); );
cx.simulate_input(" "); cx.simulate_input(" ");
editor.update(&mut cx, |editor, cx| { editor.update(&mut cx, |editor, cx| {
assert_eq!(editor.text(cx), "Lorem [@one.txt](file:///dir/a/one.txt) "); let text = editor.text(cx);
assert_eq!(text, format!("Lorem [@one.txt]({url_one}) "));
assert!(!editor.has_visible_completions_menu()); assert!(!editor.has_visible_completions_menu());
assert_eq!( assert_eq!(fold_ranges(editor, cx).len(), 1);
fold_ranges(editor, cx),
vec![Point::new(0, 6)..Point::new(0, 39)]
);
}); });
cx.simulate_input("Ipsum "); cx.simulate_input("Ipsum ");
editor.update(&mut cx, |editor, cx| { editor.update(&mut cx, |editor, cx| {
assert_eq!( let text = editor.text(cx);
editor.text(cx), assert_eq!(text, format!("Lorem [@one.txt]({url_one}) Ipsum "),);
"Lorem [@one.txt](file:///dir/a/one.txt) Ipsum ",
);
assert!(!editor.has_visible_completions_menu()); assert!(!editor.has_visible_completions_menu());
assert_eq!( assert_eq!(fold_ranges(editor, cx).len(), 1);
fold_ranges(editor, cx),
vec![Point::new(0, 6)..Point::new(0, 39)]
);
}); });
cx.simulate_input("@file "); cx.simulate_input("@file ");
editor.update(&mut cx, |editor, cx| { editor.update(&mut cx, |editor, cx| {
assert_eq!( let text = editor.text(cx);
editor.text(cx), assert_eq!(text, format!("Lorem [@one.txt]({url_one}) Ipsum @file "),);
"Lorem [@one.txt](file:///dir/a/one.txt) Ipsum @file ",
);
assert!(editor.has_visible_completions_menu()); assert!(editor.has_visible_completions_menu());
assert_eq!( assert_eq!(fold_ranges(editor, cx).len(), 1);
fold_ranges(editor, cx),
vec![Point::new(0, 6)..Point::new(0, 39)]
);
}); });
editor.update_in(&mut cx, |editor, window, cx| { editor.update_in(&mut cx, |editor, window, cx| {
@ -2041,28 +2028,23 @@ mod tests {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
assert_eq!(contents.len(), 2); assert_eq!(contents.len(), 2);
let url_eight = uri!("file:///dir/b/eight.txt");
pretty_assertions::assert_eq!( pretty_assertions::assert_eq!(
contents[1], contents[1],
Mention::Text { Mention::Text {
content: "8".to_string(), content: "8".to_string(),
uri: "file:///dir/b/eight.txt".parse().unwrap(), uri: url_eight.parse().unwrap(),
} }
); );
editor.update(&mut cx, |editor, cx| { editor.update(&mut cx, |editor, cx| {
assert_eq!( assert_eq!(
editor.text(cx), editor.text(cx),
"Lorem [@one.txt](file:///dir/a/one.txt) Ipsum [@eight.txt](file:///dir/b/eight.txt) " format!("Lorem [@one.txt]({url_one}) Ipsum [@eight.txt]({url_eight}) ")
); );
assert!(!editor.has_visible_completions_menu()); assert!(!editor.has_visible_completions_menu());
assert_eq!( assert_eq!(fold_ranges(editor, cx).len(), 2);
fold_ranges(editor, cx), });
vec![
Point::new(0, 6)..Point::new(0, 39),
Point::new(0, 47)..Point::new(0, 84)
]
);
});
let plain_text_language = Arc::new(language::Language::new( let plain_text_language = Arc::new(language::Language::new(
language::LanguageConfig { language::LanguageConfig {
@ -2108,7 +2090,7 @@ mod tests {
let fake_language_server = fake_language_servers.next().await.unwrap(); let fake_language_server = fake_language_servers.next().await.unwrap();
fake_language_server.set_request_handler::<lsp::WorkspaceSymbolRequest, _, _>( fake_language_server.set_request_handler::<lsp::WorkspaceSymbolRequest, _, _>(
|_, _| async move { move |_, _| async move {
Ok(Some(lsp::WorkspaceSymbolResponse::Flat(vec![ Ok(Some(lsp::WorkspaceSymbolResponse::Flat(vec![
#[allow(deprecated)] #[allow(deprecated)]
lsp::SymbolInformation { lsp::SymbolInformation {
@ -2132,18 +2114,13 @@ mod tests {
cx.simulate_input("@symbol "); cx.simulate_input("@symbol ");
editor.update(&mut cx, |editor, cx| { editor.update(&mut cx, |editor, cx| {
assert_eq!( assert_eq!(
editor.text(cx), editor.text(cx),
"Lorem [@one.txt](file:///dir/a/one.txt) Ipsum [@eight.txt](file:///dir/b/eight.txt) @symbol " format!("Lorem [@one.txt]({url_one}) Ipsum [@eight.txt]({url_eight}) @symbol ")
); );
assert!(editor.has_visible_completions_menu()); assert!(editor.has_visible_completions_menu());
assert_eq!( assert_eq!(current_completion_labels(editor), &["MySymbol"]);
current_completion_labels(editor), });
&[
"MySymbol",
]
);
});
editor.update_in(&mut cx, |editor, window, cx| { editor.update_in(&mut cx, |editor, window, cx| {
editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx); editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx);
@ -2165,9 +2142,7 @@ mod tests {
contents[2], contents[2],
Mention::Text { Mention::Text {
content: "1".into(), content: "1".into(),
uri: "file:///dir/a/one.txt?symbol=MySymbol#L1:1" uri: format!("{url_one}?symbol=MySymbol#L1:1").parse().unwrap(),
.parse()
.unwrap(),
} }
); );
@ -2176,7 +2151,7 @@ mod tests {
editor.read_with(&cx, |editor, cx| { editor.read_with(&cx, |editor, cx| {
assert_eq!( assert_eq!(
editor.text(cx), editor.text(cx),
"Lorem [@one.txt](file:///dir/a/one.txt) Ipsum [@eight.txt](file:///dir/b/eight.txt) [@MySymbol](file:///dir/a/one.txt?symbol=MySymbol#L1:1) " format!("Lorem [@one.txt]({url_one}) Ipsum [@eight.txt]({url_eight}) [@MySymbol]({url_one}?symbol=MySymbol#L1:1) ")
); );
}); });
} }

View file

@ -590,9 +590,9 @@ mod tests {
assert_eq!( assert_eq!(
fs.files_with_contents(Path::new("")), fs.files_with_contents(Path::new("")),
[ [
(Path::new("/bar/baz").into(), b"qux".into()), (Path::new(path!("/bar/baz")).into(), b"qux".into()),
(Path::new("/foo/a").into(), b"lorem".into()), (Path::new(path!("/foo/a")).into(), b"lorem".into()),
(Path::new("/foo/b").into(), b"ipsum".into()) (Path::new(path!("/foo/b")).into(), b"ipsum".into())
] ]
); );
} }

View file

@ -1101,7 +1101,9 @@ impl FakeFsState {
) -> Option<(&mut FakeFsEntry, PathBuf)> { ) -> Option<(&mut FakeFsEntry, PathBuf)> {
let canonical_path = self.canonicalize(target, follow_symlink)?; let canonical_path = self.canonicalize(target, follow_symlink)?;
let mut components = canonical_path.components(); let mut components = canonical_path
.components()
.skip_while(|component| matches!(component, Component::Prefix(_)));
let Some(Component::RootDir) = components.next() else { let Some(Component::RootDir) = components.next() else {
panic!( panic!(
"the path {:?} was not canonicalized properly {:?}", "the path {:?} was not canonicalized properly {:?}",