Skip to content

Commit 2ef2590

Browse files
committed
Add file watching test
1 parent 2ccd0c1 commit 2ef2590

File tree

1 file changed

+80
-3
lines changed

1 file changed

+80
-3
lines changed

crates/red_knot/tests/file_watching.rs

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#![allow(clippy::disallowed_names)]
2-
31
use std::collections::HashSet;
42
use std::io::Write;
53
use std::time::{Duration, Instant};
@@ -16,7 +14,7 @@ use ruff_db::source::source_text;
1614
use ruff_db::system::{
1715
OsSystem, System, SystemPath, SystemPathBuf, UserConfigDirectoryOverrideGuard,
1816
};
19-
use ruff_db::Upcast;
17+
use ruff_db::{Db as _, Upcast};
2018
use ruff_python_ast::PythonVersion;
2119

2220
struct TestCase {
@@ -1790,3 +1788,82 @@ fn changes_to_user_configuration() -> anyhow::Result<()> {
17901788

17911789
Ok(())
17921790
}
1791+
1792+
/// Tests that renaming a file from `lib.py` to `Lib.py` is correctly reflected.
1793+
///
1794+
/// This test currently fails on case-insensitive systems because `Files` is case-sensitive
1795+
/// but the `System::metadata` call isn't. This means that
1796+
/// Red Knot considers both `Lib.py` and `lib.py` to exist when only `lib.py` does
1797+
///
1798+
/// The incoming change events then are no-ops because they don't change either file's
1799+
/// status nor does it update their last modified time (renaming a file doesn't bump it's
1800+
/// last modified timestamp).
1801+
///
1802+
/// Fixing this requires to either make `Files` case-insensitive and store the
1803+
/// real-case path (if it differs) on `File` or make `Files` use a
1804+
/// case-sensitive `System::metadata` call. This does open the question if all
1805+
/// `System` calls should be case sensitive. This would be the most consistent
1806+
/// but might be hard to pull off.
1807+
///
1808+
/// What the right solution is also depends on if Red Knot itself should be case
1809+
/// sensitive or not. E.g. should `include="src"` be case sensitive on all systems
1810+
/// or only on case-sensitive systems?
1811+
///
1812+
/// Lastly, whatever solution we pick must also work well with VS Code which,
1813+
/// unfortunately ,doesn't propagate casing-only renames.
1814+
/// <https://github.com/rust-lang/rust-analyzer/issues/9581>
1815+
#[ignore]
1816+
#[test]
1817+
fn rename_files_casing_only() -> anyhow::Result<()> {
1818+
let mut case = setup([("lib.py", "class Foo: ...")])?;
1819+
1820+
assert!(
1821+
resolve_module(case.db(), &ModuleName::new("lib").unwrap()).is_some(),
1822+
"Expected `lib` module to exist."
1823+
);
1824+
assert_eq!(
1825+
resolve_module(case.db(), &ModuleName::new("Lib").unwrap()),
1826+
None,
1827+
"Expected `Lib` module not to exist"
1828+
);
1829+
1830+
// Now rename `lib.py` to `Lib.py`
1831+
if case.db().system().case_sensitivity().is_case_sensitive() {
1832+
std::fs::rename(
1833+
case.project_path("lib.py").as_std_path(),
1834+
case.project_path("Lib.py").as_std_path(),
1835+
)
1836+
.context("Failed to rename `lib.py` to `Lib.py`")?;
1837+
} else {
1838+
// On case-insensitive file systems, renaming a file to a different casing is a no-op.
1839+
// Rename to a different name first
1840+
std::fs::rename(
1841+
case.project_path("lib.py").as_std_path(),
1842+
case.project_path("temp.py").as_std_path(),
1843+
)
1844+
.context("Failed to rename `lib.py` to `temp.py`")?;
1845+
1846+
std::fs::rename(
1847+
case.project_path("temp.py").as_std_path(),
1848+
case.project_path("Lib.py").as_std_path(),
1849+
)
1850+
.context("Failed to rename `temp.py` to `Lib.py`")?;
1851+
}
1852+
1853+
let changes = case.stop_watch(event_for_file("Lib.py"));
1854+
case.apply_changes(changes);
1855+
1856+
// Resolving `lib` should now fail but `Lib` should now succeed
1857+
assert_eq!(
1858+
resolve_module(case.db(), &ModuleName::new("lib").unwrap()),
1859+
None,
1860+
"Expected `lib` module to no longer exist."
1861+
);
1862+
1863+
assert!(
1864+
resolve_module(case.db(), &ModuleName::new("Lib").unwrap()).is_some(),
1865+
"Expected `Lib` module to exist"
1866+
);
1867+
1868+
Ok(())
1869+
}

0 commit comments

Comments
 (0)