mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:18 +00:00
[ty] Add a cursor test builder
This doesn't change any functionality of the cursor tests, but does re-arrange the code a bit. Firstly, it's now in a builder. And secondly, there's an API to add multiple files to the test (but exactly one must have a `<CURSOR>` marker).
This commit is contained in:
parent
1461137407
commit
40731f0589
1 changed files with 123 additions and 42 deletions
|
@ -214,48 +214,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) fn cursor_test(source: &str) -> CursorTest {
|
pub(super) fn cursor_test(source: &str) -> CursorTest {
|
||||||
let mut db = TestDb::new();
|
CursorTest::builder().source("main.py", source).build()
|
||||||
let cursor_offset = source.find("<CURSOR>").expect(
|
|
||||||
"`source`` should contain a `<CURSOR>` marker, indicating the position of the cursor.",
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut content = source[..cursor_offset].to_string();
|
|
||||||
content.push_str(&source[cursor_offset + "<CURSOR>".len()..]);
|
|
||||||
|
|
||||||
db.write_file("main.py", &content)
|
|
||||||
.expect("write to memory file system to be successful");
|
|
||||||
|
|
||||||
let file = system_path_to_file(&db, "main.py").expect("newly written file to existing");
|
|
||||||
|
|
||||||
Program::from_settings(
|
|
||||||
&db,
|
|
||||||
ProgramSettings {
|
|
||||||
python_version: Some(PythonVersionWithSource::default()),
|
|
||||||
python_platform: PythonPlatform::default(),
|
|
||||||
search_paths: SearchPathSettings {
|
|
||||||
extra_paths: vec![],
|
|
||||||
src_roots: vec![SystemPathBuf::from("/")],
|
|
||||||
custom_typeshed: None,
|
|
||||||
python_path: PythonPath::KnownSitePackages(vec![]),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.expect("Default settings to be valid");
|
|
||||||
|
|
||||||
let mut insta_settings = insta::Settings::clone_current();
|
|
||||||
insta_settings.add_filter(r#"\\(\w\w|\s|\.|")"#, "/$1");
|
|
||||||
// Filter out TODO types because they are different between debug and release builds.
|
|
||||||
insta_settings.add_filter(r"@Todo\(.+\)", "@Todo");
|
|
||||||
|
|
||||||
let insta_settings_guard = insta_settings.bind_to_scope();
|
|
||||||
|
|
||||||
CursorTest {
|
|
||||||
db,
|
|
||||||
cursor_offset: TextSize::try_from(cursor_offset)
|
|
||||||
.expect("source to be smaller than 4GB"),
|
|
||||||
file,
|
|
||||||
_insta_settings_guard: insta_settings_guard,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct CursorTest {
|
pub(super) struct CursorTest {
|
||||||
|
@ -266,6 +225,10 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CursorTest {
|
impl CursorTest {
|
||||||
|
pub(super) fn builder() -> CursorTestBuilder {
|
||||||
|
CursorTestBuilder::default()
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn write_file(
|
pub(super) fn write_file(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: impl AsRef<SystemPath>,
|
path: impl AsRef<SystemPath>,
|
||||||
|
@ -295,6 +258,124 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) struct Cursor {
|
||||||
|
pub(super) file: File,
|
||||||
|
pub(super) offset: TextSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(super) struct CursorTestBuilder {
|
||||||
|
/// A list of source files, corresponding to the
|
||||||
|
/// file's path and its contents.
|
||||||
|
sources: Vec<Source>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CursorTestBuilder {
|
||||||
|
pub(super) fn build(&self) -> CursorTest {
|
||||||
|
let mut db = TestDb::new();
|
||||||
|
let mut cursor: Option<Cursor> = None;
|
||||||
|
for &Source {
|
||||||
|
ref path,
|
||||||
|
ref contents,
|
||||||
|
cursor_offset,
|
||||||
|
} in &self.sources
|
||||||
|
{
|
||||||
|
db.write_file(path, contents)
|
||||||
|
.expect("write to memory file system to be successful");
|
||||||
|
let Some(offset) = cursor_offset else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let file = system_path_to_file(&db, path).expect("newly written file to existing");
|
||||||
|
// This assert should generally never trip, since
|
||||||
|
// we have an assert on `CursorTestBuilder::source`
|
||||||
|
// to ensure we never have more than one marker.
|
||||||
|
assert!(
|
||||||
|
cursor.is_none(),
|
||||||
|
"found more than one source that contains `<CURSOR>`"
|
||||||
|
);
|
||||||
|
cursor = Some(Cursor { file, offset });
|
||||||
|
}
|
||||||
|
|
||||||
|
Program::from_settings(
|
||||||
|
&db,
|
||||||
|
ProgramSettings {
|
||||||
|
python_version: Some(PythonVersionWithSource::default()),
|
||||||
|
python_platform: PythonPlatform::default(),
|
||||||
|
search_paths: SearchPathSettings {
|
||||||
|
extra_paths: vec![],
|
||||||
|
src_roots: vec![SystemPathBuf::from("/")],
|
||||||
|
custom_typeshed: None,
|
||||||
|
python_path: PythonPath::KnownSitePackages(vec![]),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("Default settings to be valid");
|
||||||
|
|
||||||
|
let mut insta_settings = insta::Settings::clone_current();
|
||||||
|
insta_settings.add_filter(r#"\\(\w\w|\s|\.|")"#, "/$1");
|
||||||
|
// Filter out TODO types because they are different between debug and release builds.
|
||||||
|
insta_settings.add_filter(r"@Todo\(.+\)", "@Todo");
|
||||||
|
|
||||||
|
let insta_settings_guard = insta_settings.bind_to_scope();
|
||||||
|
let Cursor { file, offset } =
|
||||||
|
cursor.expect("at least one source to contain `<CURSOR>`");
|
||||||
|
|
||||||
|
CursorTest {
|
||||||
|
db,
|
||||||
|
cursor_offset: offset,
|
||||||
|
file,
|
||||||
|
_insta_settings_guard: insta_settings_guard,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn source(
|
||||||
|
&mut self,
|
||||||
|
path: impl Into<SystemPathBuf>,
|
||||||
|
contents: impl Into<String>,
|
||||||
|
) -> &mut CursorTestBuilder {
|
||||||
|
const MARKER: &str = "<CURSOR>";
|
||||||
|
|
||||||
|
let path = path.into();
|
||||||
|
let contents = contents.into();
|
||||||
|
let Some(cursor_offset) = contents.find(MARKER) else {
|
||||||
|
self.sources.push(Source {
|
||||||
|
path,
|
||||||
|
contents,
|
||||||
|
cursor_offset: None,
|
||||||
|
});
|
||||||
|
return self;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(source) = self.sources.iter().find(|src| src.cursor_offset.is_some()) {
|
||||||
|
panic!(
|
||||||
|
"cursor tests must contain exactly one file \
|
||||||
|
with a `<CURSOR>` marker, but found a marker \
|
||||||
|
in both `{path1}` and `{path2}`",
|
||||||
|
path1 = source.path,
|
||||||
|
path2 = path,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut without_cursor_marker = contents[..cursor_offset].to_string();
|
||||||
|
without_cursor_marker.push_str(&contents[cursor_offset + MARKER.len()..]);
|
||||||
|
let cursor_offset =
|
||||||
|
TextSize::try_from(cursor_offset).expect("source to be smaller than 4GB");
|
||||||
|
self.sources.push(Source {
|
||||||
|
path,
|
||||||
|
contents: without_cursor_marker,
|
||||||
|
cursor_offset: Some(cursor_offset),
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Source {
|
||||||
|
path: SystemPathBuf,
|
||||||
|
contents: String,
|
||||||
|
cursor_offset: Option<TextSize>,
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) trait IntoDiagnostic {
|
pub(super) trait IntoDiagnostic {
|
||||||
fn into_diagnostic(self) -> Diagnostic;
|
fn into_diagnostic(self) -> Diagnostic;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue