diff --git a/src/ui/code_editor.rs b/src/ui/code_editor.rs index de1ab950..6ba95063 100644 --- a/src/ui/code_editor.rs +++ b/src/ui/code_editor.rs @@ -3757,6 +3757,18 @@ impl Tty7App { mod tests { use super::*; + /// A temp dir as the editor will see paths under it: resolved through + /// symlinks where the OS puts one in the way (`/var` is `/private/var` on + /// macOS). Not on Windows, where `canonicalize` answers in the `\\?\` form + /// no path the editor holds is ever in. + pub(crate) fn test_real_dir(dir: &Path) -> PathBuf { + if cfg!(windows) { + dir.to_path_buf() + } else { + dir.canonicalize().unwrap() + } + } + /// Handing a file the editor cannot read to the desktop is how a click /// opens a PNG. It must not be how a click runs a build's output. #[cfg(unix)] diff --git a/src/ui/code_editor/gutter.rs b/src/ui/code_editor/gutter.rs index 759803b1..623c665a 100644 --- a/src/ui/code_editor/gutter.rs +++ b/src/ui/code_editor/gutter.rs @@ -1294,7 +1294,7 @@ mod tests { let root = std::env::temp_dir().join(format!("tty7-gutter-base-{}", std::process::id())); let _ = std::fs::remove_dir_all(&root); std::fs::create_dir_all(root.join("sub")).unwrap(); - let root = std::fs::canonicalize(&root).unwrap(); + let root = crate::ui::code_editor::tests::test_real_dir(&root); git(&root, &["init", "--quiet"]); let file = root.join("sub").join("a b.txt"); std::fs::write(&file, "one\n").unwrap(); diff --git a/src/ui/code_editor/split.rs b/src/ui/code_editor/split.rs index f7ec6efe..1c983393 100644 --- a/src/ui/code_editor/split.rs +++ b/src/ui/code_editor/split.rs @@ -691,7 +691,7 @@ mod gpui_tests { fn a_split_is_recorded_and_comes_back(cx: &mut TestAppContext) { let dir = tempfile::tempdir().unwrap(); // Canonical, as a loaded file's path is: /var is /private/var here. - let root = dir.path().canonicalize().unwrap(); + let root = crate::ui::code_editor::tests::test_real_dir(dir.path()); let (a, b, c) = (root.join("a.rs"), root.join("b.rs"), root.join("c.rs")); for p in [&a, &b, &c] { std::fs::write(p, "fn main() {}\n").unwrap(); @@ -746,7 +746,7 @@ mod gpui_tests { // The left group held only untitled or remote buffers, which are // not recorded: only the right group's files were written down. let dir = tempfile::tempdir().unwrap(); - let root = dir.path().canonicalize().unwrap(); + let root = crate::ui::code_editor::tests::test_real_dir(dir.path()); let c = root.join("c.rs"); std::fs::write(&c, "fn main() {}\n").unwrap(); let (app, mut vcx, _streams) = harness_with_tabs(cx, 1); @@ -846,7 +846,7 @@ mod gpui_tests { #[gpui::test] fn what_is_opened_while_a_restore_loads_survives_it(cx: &mut TestAppContext) { let dir = tempfile::tempdir().unwrap(); - let root = dir.path().canonicalize().unwrap(); + let root = crate::ui::code_editor::tests::test_real_dir(dir.path()); let (a, b, c) = (root.join("a.rs"), root.join("b.rs"), root.join("c.rs")); for p in [&a, &b, &c] { std::fs::write(p, "fn main() {}\n").unwrap(); diff --git a/src/ui/lsp/locations.rs b/src/ui/lsp/locations.rs index 8f426f6f..4d8a49f0 100644 --- a/src/ui/lsp/locations.rs +++ b/src/ui/lsp/locations.rs @@ -461,7 +461,8 @@ mod tests { #[test] #[allow(deprecated)] fn workspace_symbols_become_rows_naming_where_they_live() { - let uri = super::super::path_to_uri(Path::new("/p/src/net.rs")).unwrap(); + let root = super::super::test_path("/p"); + let uri = super::super::path_to_uri(&root.join("src").join("net.rs")).unwrap(); let hits = workspace_symbols(lsp_types::WorkspaceSymbolResponse::Flat(vec![ lsp_types::SymbolInformation { name: "Server".into(), @@ -482,9 +483,13 @@ mod tests { column: 11, text: String::new(), }; - let row = symbol_item(&found, &hits[0], Path::new("/p")); + let row = symbol_item(&found, &hits[0], &root); assert_eq!(row.title, "Server"); - assert_eq!(row.subtitle.as_deref(), Some("net · src/net.rs:4")); + let rel = Path::new("src").join("net.rs"); + assert_eq!( + row.subtitle.as_deref(), + Some(format!("net · {}:4", rel.display()).as_str()) + ); assert_eq!(row.note.as_deref(), Some("struct")); } diff --git a/src/ui/lsp/mod.rs b/src/ui/lsp/mod.rs index f848647b..699a1b9b 100644 --- a/src/ui/lsp/mod.rs +++ b/src/ui/lsp/mod.rs @@ -191,6 +191,18 @@ pub(crate) fn path_to_uri(path: &Path) -> Option { url::Url::from_file_path(path).ok()?.as_str().parse().ok() } +/// An absolute path for a test, spelled for this platform: `/p/a.rs` as +/// given, `C:\p\a.rs` on Windows, where a leading slash alone is not +/// absolute and so has no `file://` URI. +#[cfg(test)] +pub(crate) fn test_path(unix: &str) -> PathBuf { + if cfg!(windows) { + PathBuf::from(format!("C:{}", unix.replace('/', "\\"))) + } else { + PathBuf::from(unix) + } +} + pub(crate) fn uri_to_path(uri: &Uri) -> Option { let url = url::Url::parse(uri.as_str()).ok()?; if url.scheme() != "file" { diff --git a/src/ui/lsp/symbols.rs b/src/ui/lsp/symbols.rs index f11523e6..09a2dd5d 100644 --- a/src/ui/lsp/symbols.rs +++ b/src/ui/lsp/symbols.rs @@ -111,7 +111,7 @@ mod tests { #[allow(deprecated)] fn a_flat_answer_is_nested_by_range() { let text = Rope::from("struct A {\n f: u8,\n}\nfn g() {}\n"); - let uri = super::super::path_to_uri(std::path::Path::new("/a.rs")).unwrap(); + let uri: lsp_types::Uri = "file:///a.rs".parse().unwrap(); let info = |name: &str, kind, r| SymbolInformation { name: name.into(), kind, diff --git a/src/ui/lsp/tests.rs b/src/ui/lsp/tests.rs index 4e5ac966..4f976c6e 100644 --- a/src/ui/lsp/tests.rs +++ b/src/ui/lsp/tests.rs @@ -8,8 +8,10 @@ use lsp_types::{ use super::*; +/// A `file://` URI spelled out, not built from a path: these tests are +/// about grouping URIs, and `/a.rs` is not an absolute path on Windows. fn uri(path: &str) -> Uri { - path_to_uri(Path::new(path)).unwrap() + format!("file://{path}").parse().unwrap() } fn edit(line: u32, text: &str) -> TextEdit { @@ -322,7 +324,7 @@ mod harness { }) }) .unwrap(); - let path = PathBuf::from("/tmp/tty7-lsp-test/src/lib.rs"); + let path = test_path("/tmp/tty7-lsp-test/src/lib.rs"); let (client_reads, server_writes) = std::io::pipe().unwrap(); let (server_reads, client_writes) = std::io::pipe().unwrap(); let (client, _events) = @@ -330,7 +332,7 @@ mod harness { client.open_gate(); let key = ServerKey { name: "rust-analyzer", - root: PathBuf::from("/tmp/tty7-lsp-test"), + root: test_path("/tmp/tty7-lsp-test"), }; cx.update(|cx| { LspStore::ensure(cx);