mirror of
https://github.com/joshuadavidthomas/django-language-server.git
synced 2025-09-11 04:46:38 +00:00
fix path handling for platform differences (#212)
This commit is contained in:
parent
bc0b6c5cc8
commit
f6286f7f46
7 changed files with 148 additions and 68 deletions
|
@ -497,6 +497,7 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[ignore = "Requires Python runtime - run with --ignored flag"]
|
||||
fn test_activate_appends_paths() -> PyResult<()> {
|
||||
let temp_dir = tempdir().unwrap();
|
||||
let path1 = temp_dir.path().join("scripts");
|
||||
|
@ -534,6 +535,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "Requires Python runtime - run with --ignored flag"]
|
||||
fn test_activate_empty_sys_path() -> PyResult<()> {
|
||||
let test_env = create_test_env(vec![]);
|
||||
|
||||
|
@ -555,6 +557,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "Requires Python runtime - run with --ignored flag"]
|
||||
fn test_activate_with_non_existent_paths() -> PyResult<()> {
|
||||
let temp_dir = tempdir().unwrap();
|
||||
let path1 = temp_dir.path().join("non_existent_dir");
|
||||
|
@ -591,6 +594,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
#[ignore = "Requires Python runtime - run with --ignored flag"]
|
||||
fn test_activate_skips_non_utf8_paths_unix() -> PyResult<()> {
|
||||
use std::ffi::OsStr;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
@ -642,6 +646,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
#[cfg(windows)]
|
||||
#[ignore = "Requires Python runtime - run with --ignored flag"]
|
||||
fn test_activate_skips_non_utf8_paths_windows() -> PyResult<()> {
|
||||
use std::ffi::OsString;
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
|
|
|
@ -281,7 +281,12 @@ mod tests {
|
|||
Ok(())
|
||||
});
|
||||
|
||||
match tokio::time::timeout(Duration::from_millis(500), submit_task).await {
|
||||
#[cfg(windows)]
|
||||
let timeout_ms = 1000;
|
||||
#[cfg(not(windows))]
|
||||
let timeout_ms = 500;
|
||||
|
||||
match tokio::time::timeout(Duration::from_millis(timeout_ms), submit_task).await {
|
||||
Ok(Ok(())) => {
|
||||
println!("Successfully submitted 33rd task");
|
||||
}
|
||||
|
@ -291,7 +296,11 @@ mod tests {
|
|||
),
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
sleep(Duration::from_millis(1000)).await;
|
||||
#[cfg(not(windows))]
|
||||
sleep(Duration::from_millis(200)).await;
|
||||
|
||||
assert_eq!(counter.load(Ordering::Relaxed), 33);
|
||||
}
|
||||
|
||||
|
|
|
@ -271,6 +271,18 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
|
||||
// Helper function to create a test file path and URL that works on all platforms
|
||||
fn test_file_url(filename: &str) -> (PathBuf, Url) {
|
||||
// Use an absolute path that's valid on the platform
|
||||
#[cfg(windows)]
|
||||
let path = PathBuf::from(format!("C:\\temp\\{filename}"));
|
||||
#[cfg(not(windows))]
|
||||
let path = PathBuf::from(format!("/tmp/{filename}"));
|
||||
|
||||
let url = Url::from_file_path(&path).expect("Failed to create file URL");
|
||||
(path, url)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_session_database_operations() {
|
||||
let mut session = Session::default();
|
||||
|
@ -287,7 +299,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_session_document_lifecycle() {
|
||||
let mut session = Session::default();
|
||||
let url = Url::parse("file:///test.py").unwrap();
|
||||
let (path, url) = test_file_url("test.py");
|
||||
|
||||
// Open document
|
||||
let document = TextDocument::new("print('hello')".to_string(), 1, LanguageId::Python);
|
||||
|
@ -297,7 +309,6 @@ mod tests {
|
|||
assert!(session.get_document(&url).is_some());
|
||||
|
||||
// Should be queryable through database
|
||||
let path = PathBuf::from("/test.py");
|
||||
let file = session.get_or_create_file(&path);
|
||||
let content = session.with_db(|db| source_text(db, file).to_string());
|
||||
assert_eq!(content, "print('hello')");
|
||||
|
@ -310,7 +321,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_session_document_update() {
|
||||
let mut session = Session::default();
|
||||
let url = Url::parse("file:///test.py").unwrap();
|
||||
let (path, url) = test_file_url("test.py");
|
||||
|
||||
// Open with initial content
|
||||
let document = TextDocument::new("initial".to_string(), 1, LanguageId::Python);
|
||||
|
@ -330,7 +341,6 @@ mod tests {
|
|||
assert_eq!(doc.version(), 2);
|
||||
|
||||
// Database should also see updated content
|
||||
let path = PathBuf::from("/test.py");
|
||||
let file = session.get_or_create_file(&path);
|
||||
let content = session.with_db(|db| source_text(db, file).to_string());
|
||||
assert_eq!(content, "updated");
|
||||
|
|
|
@ -166,6 +166,14 @@ mod tests {
|
|||
use crate::document::TextDocument;
|
||||
use crate::language::LanguageId;
|
||||
|
||||
// Helper to create platform-appropriate test paths
|
||||
fn test_file_path(name: &str) -> PathBuf {
|
||||
#[cfg(windows)]
|
||||
return PathBuf::from(format!("C:\\temp\\{name}"));
|
||||
#[cfg(not(windows))]
|
||||
return PathBuf::from(format!("/tmp/{name}"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reads_from_buffer_when_present() {
|
||||
let disk = Arc::new(InMemoryFileSystem::new());
|
||||
|
@ -173,47 +181,41 @@ mod tests {
|
|||
let fs = WorkspaceFileSystem::new(buffers.clone(), disk);
|
||||
|
||||
// Add file to buffer
|
||||
let url = Url::from_file_path("/test.py").unwrap();
|
||||
let path = test_file_path("test.py");
|
||||
let url = Url::from_file_path(&path).unwrap();
|
||||
let doc = TextDocument::new("buffer content".to_string(), 1, LanguageId::Python);
|
||||
buffers.open(url, doc);
|
||||
|
||||
assert_eq!(
|
||||
fs.read_to_string(Path::new("/test.py")).unwrap(),
|
||||
"buffer content"
|
||||
);
|
||||
assert_eq!(fs.read_to_string(&path).unwrap(), "buffer content");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reads_from_disk_when_no_buffer() {
|
||||
let mut disk_fs = InMemoryFileSystem::new();
|
||||
disk_fs.add_file("/test.py".into(), "disk content".to_string());
|
||||
let path = test_file_path("test.py");
|
||||
disk_fs.add_file(path.clone(), "disk content".to_string());
|
||||
|
||||
let buffers = Buffers::new();
|
||||
let fs = WorkspaceFileSystem::new(buffers, Arc::new(disk_fs));
|
||||
|
||||
assert_eq!(
|
||||
fs.read_to_string(Path::new("/test.py")).unwrap(),
|
||||
"disk content"
|
||||
);
|
||||
assert_eq!(fs.read_to_string(&path).unwrap(), "disk content");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_buffer_overrides_disk() {
|
||||
let mut disk_fs = InMemoryFileSystem::new();
|
||||
disk_fs.add_file("/test.py".into(), "disk content".to_string());
|
||||
let path = test_file_path("test.py");
|
||||
disk_fs.add_file(path.clone(), "disk content".to_string());
|
||||
|
||||
let buffers = Buffers::new();
|
||||
let fs = WorkspaceFileSystem::new(buffers.clone(), Arc::new(disk_fs));
|
||||
|
||||
// Add buffer with different content
|
||||
let url = Url::from_file_path("/test.py").unwrap();
|
||||
let url = Url::from_file_path(&path).unwrap();
|
||||
let doc = TextDocument::new("buffer content".to_string(), 1, LanguageId::Python);
|
||||
buffers.open(url, doc);
|
||||
|
||||
assert_eq!(
|
||||
fs.read_to_string(Path::new("/test.py")).unwrap(),
|
||||
"buffer content"
|
||||
);
|
||||
assert_eq!(fs.read_to_string(&path).unwrap(), "buffer content");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -222,39 +224,42 @@ mod tests {
|
|||
let buffers = Buffers::new();
|
||||
let fs = WorkspaceFileSystem::new(buffers.clone(), disk);
|
||||
|
||||
// Add file only to buffer
|
||||
let url = Url::from_file_path("/buffer_only.py").unwrap();
|
||||
// Add file to buffer only
|
||||
let path = test_file_path("buffer_only.py");
|
||||
let url = Url::from_file_path(&path).unwrap();
|
||||
let doc = TextDocument::new("content".to_string(), 1, LanguageId::Python);
|
||||
buffers.open(url, doc);
|
||||
|
||||
assert!(fs.exists(Path::new("/buffer_only.py")));
|
||||
assert!(fs.exists(&path));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exists_for_disk_only_file() {
|
||||
let mut disk_fs = InMemoryFileSystem::new();
|
||||
disk_fs.add_file("/disk_only.py".into(), "content".to_string());
|
||||
let path = test_file_path("disk_only.py");
|
||||
disk_fs.add_file(path.clone(), "content".to_string());
|
||||
|
||||
let buffers = Buffers::new();
|
||||
let fs = WorkspaceFileSystem::new(buffers, Arc::new(disk_fs));
|
||||
|
||||
assert!(fs.exists(Path::new("/disk_only.py")));
|
||||
assert!(fs.exists(&path));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exists_for_both_buffer_and_disk() {
|
||||
let mut disk_fs = InMemoryFileSystem::new();
|
||||
disk_fs.add_file("/both.py".into(), "disk".to_string());
|
||||
let path = test_file_path("both.py");
|
||||
disk_fs.add_file(path.clone(), "disk".to_string());
|
||||
|
||||
let buffers = Buffers::new();
|
||||
let fs = WorkspaceFileSystem::new(buffers.clone(), Arc::new(disk_fs));
|
||||
|
||||
// Also add to buffer
|
||||
let url = Url::from_file_path("/both.py").unwrap();
|
||||
let url = Url::from_file_path(&path).unwrap();
|
||||
let doc = TextDocument::new("buffer".to_string(), 1, LanguageId::Python);
|
||||
buffers.open(url, doc);
|
||||
|
||||
assert!(fs.exists(Path::new("/both.py")));
|
||||
assert!(fs.exists(&path));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -263,7 +268,8 @@ mod tests {
|
|||
let buffers = Buffers::new();
|
||||
let fs = WorkspaceFileSystem::new(buffers, disk);
|
||||
|
||||
assert!(!fs.exists(Path::new("/nowhere.py")));
|
||||
let path = test_file_path("nowhere.py");
|
||||
assert!(!fs.exists(&path));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -272,7 +278,8 @@ mod tests {
|
|||
let buffers = Buffers::new();
|
||||
let fs = WorkspaceFileSystem::new(buffers, disk);
|
||||
|
||||
let result = fs.read_to_string(Path::new("/missing.py"));
|
||||
let path = test_file_path("missing.py");
|
||||
let result = fs.read_to_string(&path);
|
||||
assert!(result.is_err());
|
||||
assert_eq!(result.unwrap_err().kind(), io::ErrorKind::NotFound);
|
||||
}
|
||||
|
@ -283,49 +290,39 @@ mod tests {
|
|||
let buffers = Buffers::new();
|
||||
let fs = WorkspaceFileSystem::new(buffers.clone(), disk);
|
||||
|
||||
let url = Url::from_file_path("/test.py").unwrap();
|
||||
let path = test_file_path("test.py");
|
||||
let url = Url::from_file_path(&path).unwrap();
|
||||
|
||||
// Initial buffer content
|
||||
let doc1 = TextDocument::new("version 1".to_string(), 1, LanguageId::Python);
|
||||
buffers.open(url.clone(), doc1);
|
||||
assert_eq!(
|
||||
fs.read_to_string(Path::new("/test.py")).unwrap(),
|
||||
"version 1"
|
||||
);
|
||||
assert_eq!(fs.read_to_string(&path).unwrap(), "version 1");
|
||||
|
||||
// Update buffer content
|
||||
let doc2 = TextDocument::new("version 2".to_string(), 2, LanguageId::Python);
|
||||
buffers.update(url, doc2);
|
||||
assert_eq!(
|
||||
fs.read_to_string(Path::new("/test.py")).unwrap(),
|
||||
"version 2"
|
||||
);
|
||||
assert_eq!(fs.read_to_string(&path).unwrap(), "version 2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_handles_buffer_removal() {
|
||||
let mut disk_fs = InMemoryFileSystem::new();
|
||||
disk_fs.add_file("/test.py".into(), "disk content".to_string());
|
||||
let path = test_file_path("test.py");
|
||||
disk_fs.add_file(path.clone(), "disk content".to_string());
|
||||
|
||||
let buffers = Buffers::new();
|
||||
let fs = WorkspaceFileSystem::new(buffers.clone(), Arc::new(disk_fs));
|
||||
|
||||
let url = Url::from_file_path("/test.py").unwrap();
|
||||
let url = Url::from_file_path(&path).unwrap();
|
||||
|
||||
// Add buffer
|
||||
let doc = TextDocument::new("buffer content".to_string(), 1, LanguageId::Python);
|
||||
buffers.open(url.clone(), doc);
|
||||
assert_eq!(
|
||||
fs.read_to_string(Path::new("/test.py")).unwrap(),
|
||||
"buffer content"
|
||||
);
|
||||
assert_eq!(fs.read_to_string(&path).unwrap(), "buffer content");
|
||||
|
||||
// Remove buffer
|
||||
let _ = buffers.close(&url);
|
||||
assert_eq!(
|
||||
fs.read_to_string(Path::new("/test.py")).unwrap(),
|
||||
"disk content"
|
||||
);
|
||||
assert_eq!(fs.read_to_string(&path).unwrap(), "disk content");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,11 +27,23 @@ pub fn url_to_path(url: &Url) -> Option<PathBuf> {
|
|||
|
||||
#[cfg(windows)]
|
||||
let path = {
|
||||
// Remove leading '/' for paths like /C:/...
|
||||
path.strip_prefix('/').unwrap_or(&path)
|
||||
// Remove leading '/' only for Windows drive paths like /C:/...
|
||||
// Check if it matches the pattern /X:/ where X is a drive letter
|
||||
if path.len() >= 3 {
|
||||
let bytes = path.as_bytes();
|
||||
if bytes[0] == b'/' && bytes[2] == b':' && bytes[1].is_ascii_alphabetic() {
|
||||
// It's a drive path like /C:/, strip the leading /
|
||||
&path[1..]
|
||||
} else {
|
||||
// Keep as-is for other paths
|
||||
&path
|
||||
}
|
||||
} else {
|
||||
&path
|
||||
}
|
||||
};
|
||||
|
||||
Some(PathBuf::from(path.as_ref()))
|
||||
Some(PathBuf::from(&*path))
|
||||
}
|
||||
|
||||
/// Context for LSP operations, used for error reporting
|
||||
|
@ -132,8 +144,16 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_url_to_path_valid_file_url() {
|
||||
let url = Url::parse("file:///home/user/test.py").unwrap();
|
||||
assert_eq!(url_to_path(&url), Some(PathBuf::from("/home/user/test.py")));
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let url = Url::parse("file:///home/user/test.py").unwrap();
|
||||
assert_eq!(url_to_path(&url), Some(PathBuf::from("/home/user/test.py")));
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let url = Url::parse("file:///C:/Users/test.py").unwrap();
|
||||
assert_eq!(url_to_path(&url), Some(PathBuf::from("C:/Users/test.py")));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -144,11 +164,22 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_url_to_path_percent_encoded() {
|
||||
let url = Url::parse("file:///home/user/test%20file.py").unwrap();
|
||||
assert_eq!(
|
||||
url_to_path(&url),
|
||||
Some(PathBuf::from("/home/user/test file.py"))
|
||||
);
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let url = Url::parse("file:///home/user/test%20file.py").unwrap();
|
||||
assert_eq!(
|
||||
url_to_path(&url),
|
||||
Some(PathBuf::from("/home/user/test file.py"))
|
||||
);
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let url = Url::parse("file:///C:/Users/test%20file.py").unwrap();
|
||||
assert_eq!(
|
||||
url_to_path(&url),
|
||||
Some(PathBuf::from("C:/Users/test file.py"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -169,11 +200,22 @@ mod tests {
|
|||
// lsp_uri_to_path tests
|
||||
#[test]
|
||||
fn test_lsp_uri_to_path_valid_file() {
|
||||
let uri = lsp_types::Uri::from_str("file:///home/user/test.py").unwrap();
|
||||
assert_eq!(
|
||||
lsp_uri_to_path(&uri),
|
||||
Some(PathBuf::from("/home/user/test.py"))
|
||||
);
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let uri = lsp_types::Uri::from_str("file:///home/user/test.py").unwrap();
|
||||
assert_eq!(
|
||||
lsp_uri_to_path(&uri),
|
||||
Some(PathBuf::from("/home/user/test.py"))
|
||||
);
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let uri = lsp_types::Uri::from_str("file:///C:/Users/test.py").unwrap();
|
||||
assert_eq!(
|
||||
lsp_uri_to_path(&uri),
|
||||
Some(PathBuf::from("C:/Users/test.py"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue