Skip to content

Commit ce0018c

Browse files
authored
Add OsSystem support to mdtests (#16518)
## Summary This PR introduces a new mdtest option `system` that can either be `in-memory` or `os` where `in-memory` is the default. The motivation for supporting `os` is so that we can write OS/system specific tests with mdtests. Specifically, I want to write mdtests for the module resolver, testing that module resolution is case sensitive. ## Test Plan I tested that the case-sensitive module resolver test start failing when setting `system = "os"`
1 parent 48f906e commit ce0018c

File tree

31 files changed

+519
-207
lines changed

31 files changed

+519
-207
lines changed

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/red_knot_project/src/files.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ mod tests {
255255
use crate::files::Index;
256256
use crate::ProjectMetadata;
257257
use ruff_db::files::system_path_to_file;
258-
use ruff_db::system::{DbWithTestSystem, SystemPathBuf};
258+
use ruff_db::system::{DbWithWritableSystem as _, SystemPathBuf};
259259
use ruff_python_ast::name::Name;
260260

261261
#[test]

crates/red_knot_project/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ mod tests {
528528
use ruff_db::diagnostic::OldDiagnosticTrait;
529529
use ruff_db::files::system_path_to_file;
530530
use ruff_db::source::source_text;
531-
use ruff_db::system::{DbWithTestSystem, SystemPath, SystemPathBuf};
531+
use ruff_db::system::{DbWithTestSystem, DbWithWritableSystem as _, SystemPath, SystemPathBuf};
532532
use ruff_db::testing::assert_function_query_was_not_run;
533533
use ruff_python_ast::name::Name;
534534

crates/red_knot_project/src/metadata.rs

+17-17
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ mod tests {
321321

322322
system
323323
.memory_file_system()
324-
.write_files([(root.join("foo.py"), ""), (root.join("bar.py"), "")])
324+
.write_files_all([(root.join("foo.py"), ""), (root.join("bar.py"), "")])
325325
.context("Failed to write files")?;
326326

327327
let project =
@@ -349,7 +349,7 @@ mod tests {
349349

350350
system
351351
.memory_file_system()
352-
.write_files([
352+
.write_files_all([
353353
(
354354
root.join("pyproject.toml"),
355355
r#"
@@ -393,7 +393,7 @@ mod tests {
393393

394394
system
395395
.memory_file_system()
396-
.write_files([
396+
.write_files_all([
397397
(
398398
root.join("pyproject.toml"),
399399
r#"
@@ -432,7 +432,7 @@ expected `.`, `]`
432432

433433
system
434434
.memory_file_system()
435-
.write_files([
435+
.write_files_all([
436436
(
437437
root.join("pyproject.toml"),
438438
r#"
@@ -482,7 +482,7 @@ expected `.`, `]`
482482

483483
system
484484
.memory_file_system()
485-
.write_files([
485+
.write_files_all([
486486
(
487487
root.join("pyproject.toml"),
488488
r#"
@@ -532,7 +532,7 @@ expected `.`, `]`
532532

533533
system
534534
.memory_file_system()
535-
.write_files([
535+
.write_files_all([
536536
(
537537
root.join("pyproject.toml"),
538538
r#"
@@ -572,7 +572,7 @@ expected `.`, `]`
572572

573573
system
574574
.memory_file_system()
575-
.write_files([
575+
.write_files_all([
576576
(
577577
root.join("pyproject.toml"),
578578
r#"
@@ -623,7 +623,7 @@ expected `.`, `]`
623623

624624
system
625625
.memory_file_system()
626-
.write_files([
626+
.write_files_all([
627627
(
628628
root.join("pyproject.toml"),
629629
r#"
@@ -673,7 +673,7 @@ expected `.`, `]`
673673

674674
system
675675
.memory_file_system()
676-
.write_file(
676+
.write_file_all(
677677
root.join("pyproject.toml"),
678678
r#"
679679
[project]
@@ -703,7 +703,7 @@ expected `.`, `]`
703703

704704
system
705705
.memory_file_system()
706-
.write_file(
706+
.write_file_all(
707707
root.join("pyproject.toml"),
708708
r#"
709709
[project]
@@ -735,7 +735,7 @@ expected `.`, `]`
735735

736736
system
737737
.memory_file_system()
738-
.write_file(
738+
.write_file_all(
739739
root.join("pyproject.toml"),
740740
r#"
741741
[project]
@@ -765,7 +765,7 @@ expected `.`, `]`
765765

766766
system
767767
.memory_file_system()
768-
.write_file(
768+
.write_file_all(
769769
root.join("pyproject.toml"),
770770
r#"
771771
[project]
@@ -795,7 +795,7 @@ expected `.`, `]`
795795

796796
system
797797
.memory_file_system()
798-
.write_file(
798+
.write_file_all(
799799
root.join("pyproject.toml"),
800800
r#"
801801
[project]
@@ -828,7 +828,7 @@ expected `.`, `]`
828828

829829
system
830830
.memory_file_system()
831-
.write_file(
831+
.write_file_all(
832832
root.join("pyproject.toml"),
833833
r#"
834834
[project]
@@ -861,7 +861,7 @@ expected `.`, `]`
861861

862862
system
863863
.memory_file_system()
864-
.write_file(
864+
.write_file_all(
865865
root.join("pyproject.toml"),
866866
r#"
867867
[project]
@@ -886,7 +886,7 @@ expected `.`, `]`
886886

887887
system
888888
.memory_file_system()
889-
.write_file(
889+
.write_file_all(
890890
root.join("pyproject.toml"),
891891
r#"
892892
[project]
@@ -911,7 +911,7 @@ expected `.`, `]`
911911

912912
system
913913
.memory_file_system()
914-
.write_file(
914+
.write_file_all(
915915
root.join("pyproject.toml"),
916916
r#"
917917
[project]

crates/red_knot_project/tests/check.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ fn run_corpus_tests(pattern: &str) -> anyhow::Result<()> {
117117
let code = std::fs::read_to_string(source)?;
118118

119119
let mut check_with_file_name = |path: &SystemPath| {
120-
memory_fs.write_file(path, &code).unwrap();
120+
memory_fs.write_file_all(path, &code).unwrap();
121121
File::sync_path(&mut db, path);
122122

123123
// this test is only asserting that we can pull every expression type without a panic

crates/red_knot_python_semantic/resources/mdtest/import/case_sensitive.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# Case Sensitive Imports
22

3-
TODO: This test should use the real file system instead of the memory file system.
3+
```toml
4+
# TODO: This test should use the real file system instead of the memory file system.
5+
# but we can't change the file system yet because the tests would then start failing for
6+
# case-insensitive file systems.
7+
#system = "os"
8+
```
49

510
Python's import system is case-sensitive even on case-insensitive file system. This means, importing
611
a module `a` should fail if the file in the search paths is named `A.py`. See

crates/red_knot_python_semantic/src/db.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ pub(crate) mod tests {
2525
use crate::lint::{LintRegistry, RuleSelection};
2626
use anyhow::Context;
2727
use ruff_db::files::{File, Files};
28-
use ruff_db::system::{DbWithTestSystem, System, SystemPathBuf, TestSystem};
28+
use ruff_db::system::{
29+
DbWithTestSystem, DbWithWritableSystem as _, System, SystemPathBuf, TestSystem,
30+
};
2931
use ruff_db::vendored::VendoredFileSystem;
3032
use ruff_db::{Db as SourceDb, Upcast};
3133
use ruff_python_ast::PythonVersion;

crates/red_knot_python_semantic/src/module_resolver/resolver.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ impl<'db> ResolverContext<'db> {
720720
#[cfg(test)]
721721
mod tests {
722722
use ruff_db::files::{system_path_to_file, File, FilePath};
723-
use ruff_db::system::DbWithTestSystem;
723+
use ruff_db::system::{DbWithTestSystem as _, DbWithWritableSystem as _};
724724
use ruff_db::testing::{
725725
assert_const_function_query_was_not_run, assert_function_query_was_not_run,
726726
};

crates/red_knot_python_semantic/src/module_resolver/testing.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use ruff_db::system::{DbWithTestSystem, SystemPath, SystemPathBuf};
1+
use ruff_db::system::{
2+
DbWithTestSystem as _, DbWithWritableSystem as _, SystemPath, SystemPathBuf,
3+
};
24
use ruff_db::vendored::VendoredPathBuf;
35
use ruff_python_ast::PythonVersion;
46

crates/red_knot_python_semantic/src/semantic_index.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ impl FusedIterator for ChildrenIter<'_> {}
409409
mod tests {
410410
use ruff_db::files::{system_path_to_file, File};
411411
use ruff_db::parsed::parsed_module;
412-
use ruff_db::system::DbWithTestSystem;
412+
use ruff_db::system::DbWithWritableSystem as _;
413413
use ruff_python_ast as ast;
414414
use ruff_text_size::{Ranged, TextRange};
415415

@@ -440,7 +440,7 @@ mod tests {
440440
file: File,
441441
}
442442

443-
fn test_case(content: impl ToString) -> TestCase {
443+
fn test_case(content: impl AsRef<str>) -> TestCase {
444444
let mut db = TestDb::new();
445445
db.write_file("test.py", content).unwrap();
446446

crates/red_knot_python_semantic/src/site_packages.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ mod tests {
545545
system_install_sys_prefix.join(&unix_site_packages);
546546
(system_home_path, system_exe_path, system_site_packages_path)
547547
};
548-
memory_fs.write_file(system_exe_path, "").unwrap();
548+
memory_fs.write_file_all(system_exe_path, "").unwrap();
549549
memory_fs
550550
.create_directory_all(&system_site_packages_path)
551551
.unwrap();
@@ -562,7 +562,7 @@ mod tests {
562562
venv_sys_prefix.join(&unix_site_packages),
563563
)
564564
};
565-
memory_fs.write_file(&venv_exe, "").unwrap();
565+
memory_fs.write_file_all(&venv_exe, "").unwrap();
566566
memory_fs.create_directory_all(&site_packages_path).unwrap();
567567

568568
let pyvenv_cfg_path = venv_sys_prefix.join("pyvenv.cfg");
@@ -576,7 +576,7 @@ mod tests {
576576
pyvenv_cfg_contents.push_str("include-system-site-packages = TRuE\n");
577577
}
578578
memory_fs
579-
.write_file(pyvenv_cfg_path, &pyvenv_cfg_contents)
579+
.write_file_all(pyvenv_cfg_path, &pyvenv_cfg_contents)
580580
.unwrap();
581581

582582
venv_sys_prefix
@@ -740,7 +740,7 @@ mod tests {
740740
let system = TestSystem::default();
741741
system
742742
.memory_file_system()
743-
.write_file("/.venv", "")
743+
.write_file_all("/.venv", "")
744744
.unwrap();
745745
assert!(matches!(
746746
VirtualEnvironment::new("/.venv", &system),
@@ -767,7 +767,7 @@ mod tests {
767767
let memory_fs = system.memory_file_system();
768768
let pyvenv_cfg_path = SystemPathBuf::from("/.venv/pyvenv.cfg");
769769
memory_fs
770-
.write_file(&pyvenv_cfg_path, "home = bar = /.venv/bin")
770+
.write_file_all(&pyvenv_cfg_path, "home = bar = /.venv/bin")
771771
.unwrap();
772772
let venv_result = VirtualEnvironment::new("/.venv", &system);
773773
assert!(matches!(
@@ -785,7 +785,9 @@ mod tests {
785785
let system = TestSystem::default();
786786
let memory_fs = system.memory_file_system();
787787
let pyvenv_cfg_path = SystemPathBuf::from("/.venv/pyvenv.cfg");
788-
memory_fs.write_file(&pyvenv_cfg_path, "home =").unwrap();
788+
memory_fs
789+
.write_file_all(&pyvenv_cfg_path, "home =")
790+
.unwrap();
789791
let venv_result = VirtualEnvironment::new("/.venv", &system);
790792
assert!(matches!(
791793
venv_result,
@@ -803,7 +805,7 @@ mod tests {
803805
let memory_fs = system.memory_file_system();
804806
let pyvenv_cfg_path = SystemPathBuf::from("/.venv/pyvenv.cfg");
805807
memory_fs
806-
.write_file(&pyvenv_cfg_path, "= whatever")
808+
.write_file_all(&pyvenv_cfg_path, "= whatever")
807809
.unwrap();
808810
let venv_result = VirtualEnvironment::new("/.venv", &system);
809811
assert!(matches!(
@@ -821,7 +823,7 @@ mod tests {
821823
let system = TestSystem::default();
822824
let memory_fs = system.memory_file_system();
823825
let pyvenv_cfg_path = SystemPathBuf::from("/.venv/pyvenv.cfg");
824-
memory_fs.write_file(&pyvenv_cfg_path, "").unwrap();
826+
memory_fs.write_file_all(&pyvenv_cfg_path, "").unwrap();
825827
let venv_result = VirtualEnvironment::new("/.venv", &system);
826828
assert!(matches!(
827829
venv_result,
@@ -839,7 +841,7 @@ mod tests {
839841
let memory_fs = system.memory_file_system();
840842
let pyvenv_cfg_path = SystemPathBuf::from("/.venv/pyvenv.cfg");
841843
memory_fs
842-
.write_file(&pyvenv_cfg_path, "home = foo")
844+
.write_file_all(&pyvenv_cfg_path, "home = foo")
843845
.unwrap();
844846
let venv_result = VirtualEnvironment::new("/.venv", &system);
845847
assert!(matches!(

crates/red_knot_python_semantic/src/types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4350,7 +4350,7 @@ pub(crate) mod tests {
43504350
};
43514351
use ruff_db::files::system_path_to_file;
43524352
use ruff_db::parsed::parsed_module;
4353-
use ruff_db::system::DbWithTestSystem;
4353+
use ruff_db::system::DbWithWritableSystem as _;
43544354
use ruff_db::testing::assert_function_query_was_not_run;
43554355
use ruff_python_ast::PythonVersion;
43564356
use strum::IntoEnumIterator;

crates/red_knot_python_semantic/src/types/infer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6551,7 +6551,7 @@ mod tests {
65516551
use crate::symbol::global_symbol;
65526552
use crate::types::check_types;
65536553
use ruff_db::files::{system_path_to_file, File};
6554-
use ruff_db::system::DbWithTestSystem;
6554+
use ruff_db::system::DbWithWritableSystem as _;
65556555
use ruff_db::testing::{assert_function_query_was_not_run, assert_function_query_was_run};
65566556

65576557
use super::*;

crates/red_knot_python_semantic/src/types/signatures.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ mod tests {
348348
use crate::db::tests::{setup_db, TestDb};
349349
use crate::symbol::global_symbol;
350350
use crate::types::{FunctionType, KnownClass};
351-
use ruff_db::system::DbWithTestSystem;
351+
use ruff_db::system::DbWithWritableSystem as _;
352352

353353
#[track_caller]
354354
fn get_function_f<'db>(db: &'db TestDb, file: &'static str) -> FunctionType<'db> {

crates/red_knot_test/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ red_knot_python_semantic = { workspace = true, features = ["serde"] }
1515
red_knot_vendored = { workspace = true }
1616
ruff_db = { workspace = true, features = ["testing"] }
1717
ruff_index = { workspace = true }
18+
ruff_notebook = { workspace = true }
1819
ruff_python_trivia = { workspace = true }
1920
ruff_source_file = { workspace = true }
2021
ruff_text_size = { workspace = true }
@@ -30,6 +31,7 @@ rustc-hash = { workspace = true }
3031
salsa = { workspace = true }
3132
smallvec = { workspace = true }
3233
serde = { workspace = true }
34+
tempfile = { workspace = true }
3335
toml = { workspace = true }
3436
thiserror = { workspace = true }
3537

crates/red_knot_test/src/assertion.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -490,12 +490,12 @@ pub(crate) enum ErrorAssertionParseError<'a> {
490490
mod tests {
491491
use super::*;
492492
use ruff_db::files::system_path_to_file;
493-
use ruff_db::system::{DbWithTestSystem, SystemPathBuf};
493+
use ruff_db::system::DbWithWritableSystem as _;
494494
use ruff_python_trivia::textwrap::dedent;
495495
use ruff_source_file::OneIndexed;
496496

497497
fn get_assertions(source: &str) -> InlineFileAssertions {
498-
let mut db = crate::db::Db::setup(SystemPathBuf::from("/src"));
498+
let mut db = Db::setup();
499499
db.write_file("/src/test.py", source).unwrap();
500500
let file = system_path_to_file(&db, "/src/test.py").unwrap();
501501
InlineFileAssertions::from_file(&db, file)

0 commit comments

Comments
 (0)