[ty_test] Refactor: rename diagnostic.rs to check_output.rs
SortedDiagnostics is now replaced by SortedCheckOutputs, which handles both diagnostics and hover results. This refactoring: - Renames diagnostic.rs to check_output.rs to better reflect its purpose - Moves CheckOutput and SortedCheckOutputs definitions from matcher.rs to check_output.rs where they belong - Removes the now-unused SortedDiagnostics infrastructure - Ports the test to use SortedCheckOutputs instead of SortedDiagnostics - Updates all imports throughout the codebase The check_output module now serves as the central location for sorting and grouping all types of check outputs (diagnostics and hover results) by line number. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
205
crates/ty_test/src/check_output.rs
Normal file
205
crates/ty_test/src/check_output.rs
Normal file
@@ -0,0 +1,205 @@
|
||||
//! Sort and group check outputs (diagnostics and hover results) by line number,
|
||||
//! so they can be correlated with assertions.
|
||||
//!
|
||||
//! We don't assume that we will get the outputs in source order.
|
||||
|
||||
use ruff_db::diagnostic::Diagnostic;
|
||||
use ruff_source_file::{LineIndex, OneIndexed};
|
||||
use ruff_text_size::TextSize;
|
||||
use std::ops::Range;
|
||||
|
||||
/// Represents either a diagnostic or a hover result for matching against assertions.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum CheckOutput {
|
||||
/// A regular diagnostic from the type checker
|
||||
Diagnostic(Diagnostic),
|
||||
|
||||
/// A hover result for testing hover assertions
|
||||
Hover {
|
||||
/// The position where hover was requested
|
||||
offset: TextSize,
|
||||
/// The inferred type at that position
|
||||
inferred_type: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl CheckOutput {
|
||||
fn line_number(&self, line_index: &LineIndex) -> OneIndexed {
|
||||
match self {
|
||||
CheckOutput::Diagnostic(diag) => diag
|
||||
.primary_span()
|
||||
.and_then(|span| span.range())
|
||||
.map_or(OneIndexed::from_zero_indexed(0), |range| {
|
||||
line_index.line_index(range.start())
|
||||
}),
|
||||
CheckOutput::Hover { offset, .. } => line_index.line_index(*offset),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// All check outputs for one embedded Python file, sorted and grouped by line number.
|
||||
///
|
||||
/// The outputs are kept in a flat vector, sorted by line number. A separate vector of
|
||||
/// [`LineOutputRange`] has one entry for each contiguous slice of the outputs vector
|
||||
/// containing outputs which all start on the same line.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SortedCheckOutputs {
|
||||
outputs: Vec<CheckOutput>,
|
||||
line_ranges: Vec<LineOutputRange>,
|
||||
}
|
||||
|
||||
impl SortedCheckOutputs {
|
||||
pub(crate) fn new(outputs: &[CheckOutput], line_index: &LineIndex) -> Self {
|
||||
let mut outputs: Vec<_> = outputs
|
||||
.iter()
|
||||
.map(|output| OutputWithLine {
|
||||
line_number: output.line_number(line_index),
|
||||
output: output.clone(),
|
||||
})
|
||||
.collect();
|
||||
outputs.sort_unstable_by_key(|output_with_line| output_with_line.line_number);
|
||||
|
||||
let mut result = Self {
|
||||
outputs: Vec::with_capacity(outputs.len()),
|
||||
line_ranges: vec![],
|
||||
};
|
||||
|
||||
let mut current_line_number = None;
|
||||
let mut start = 0;
|
||||
for OutputWithLine {
|
||||
line_number,
|
||||
output,
|
||||
} in outputs
|
||||
{
|
||||
match current_line_number {
|
||||
None => {
|
||||
current_line_number = Some(line_number);
|
||||
}
|
||||
Some(current) => {
|
||||
if line_number != current {
|
||||
let end = result.outputs.len();
|
||||
result.line_ranges.push(LineOutputRange {
|
||||
line_number: current,
|
||||
output_index_range: start..end,
|
||||
});
|
||||
start = end;
|
||||
current_line_number = Some(line_number);
|
||||
}
|
||||
}
|
||||
}
|
||||
result.outputs.push(output);
|
||||
}
|
||||
if let Some(line_number) = current_line_number {
|
||||
result.line_ranges.push(LineOutputRange {
|
||||
line_number,
|
||||
output_index_range: start..result.outputs.len(),
|
||||
});
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub(crate) fn iter_lines(&self) -> LineCheckOutputsIterator<'_> {
|
||||
LineCheckOutputsIterator {
|
||||
outputs: self.outputs.as_slice(),
|
||||
inner: self.line_ranges.iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct OutputWithLine {
|
||||
line_number: OneIndexed,
|
||||
output: CheckOutput,
|
||||
}
|
||||
|
||||
/// Range delineating check outputs in [`SortedCheckOutputs`] that begin on a single line.
|
||||
#[derive(Debug)]
|
||||
struct LineOutputRange {
|
||||
line_number: OneIndexed,
|
||||
output_index_range: Range<usize>,
|
||||
}
|
||||
|
||||
/// Iterator to group sorted check outputs by line.
|
||||
pub(crate) struct LineCheckOutputsIterator<'a> {
|
||||
outputs: &'a [CheckOutput],
|
||||
inner: std::slice::Iter<'a, LineOutputRange>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for LineCheckOutputsIterator<'a> {
|
||||
type Item = LineCheckOutputs<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let LineOutputRange {
|
||||
line_number,
|
||||
output_index_range,
|
||||
} = self.inner.next()?;
|
||||
Some(LineCheckOutputs {
|
||||
line_number: *line_number,
|
||||
outputs: &self.outputs[output_index_range.clone()],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl std::iter::FusedIterator for LineCheckOutputsIterator<'_> {}
|
||||
|
||||
/// All check outputs that start on a single line of source code in one embedded Python file.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct LineCheckOutputs<'a> {
|
||||
/// Line number on which these outputs start.
|
||||
pub(crate) line_number: OneIndexed,
|
||||
|
||||
/// Check outputs starting on this line.
|
||||
pub(crate) outputs: &'a [CheckOutput],
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::db::Db;
|
||||
use ruff_db::diagnostic::{Annotation, Diagnostic, DiagnosticId, LintName, Severity, Span};
|
||||
use ruff_db::files::system_path_to_file;
|
||||
use ruff_db::source::line_index;
|
||||
use ruff_db::system::DbWithWritableSystem as _;
|
||||
use ruff_source_file::OneIndexed;
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
|
||||
#[test]
|
||||
fn sort_and_group() {
|
||||
let mut db = Db::setup();
|
||||
db.write_file("/src/test.py", "one\ntwo\n").unwrap();
|
||||
let file = system_path_to_file(&db, "/src/test.py").unwrap();
|
||||
let lines = line_index(&db, file);
|
||||
|
||||
let ranges = [
|
||||
TextRange::new(TextSize::new(0), TextSize::new(1)),
|
||||
TextRange::new(TextSize::new(5), TextSize::new(10)),
|
||||
TextRange::new(TextSize::new(1), TextSize::new(7)),
|
||||
];
|
||||
|
||||
let check_outputs: Vec<_> = ranges
|
||||
.into_iter()
|
||||
.map(|range| {
|
||||
let mut diag = Diagnostic::new(
|
||||
DiagnosticId::Lint(LintName::of("dummy")),
|
||||
Severity::Error,
|
||||
"dummy",
|
||||
);
|
||||
let span = Span::from(file).with_range(range);
|
||||
diag.annotate(Annotation::primary(span));
|
||||
super::CheckOutput::Diagnostic(diag)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let sorted = super::SortedCheckOutputs::new(&check_outputs, &lines);
|
||||
let grouped = sorted.iter_lines().collect::<Vec<_>>();
|
||||
|
||||
let [line1, line2] = &grouped[..] else {
|
||||
panic!("expected two lines");
|
||||
};
|
||||
|
||||
assert_eq!(line1.line_number, OneIndexed::from_zero_indexed(0));
|
||||
assert_eq!(line1.outputs.len(), 2);
|
||||
assert_eq!(line2.line_number, OneIndexed::from_zero_indexed(1));
|
||||
assert_eq!(line2.outputs.len(), 1);
|
||||
}
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
//! Sort and group diagnostics by line number, so they can be correlated with assertions.
|
||||
//!
|
||||
//! We don't assume that we will get the diagnostics in source order.
|
||||
|
||||
use ruff_db::diagnostic::Diagnostic;
|
||||
use ruff_source_file::{LineIndex, OneIndexed};
|
||||
use std::ops::{Deref, Range};
|
||||
|
||||
/// All diagnostics for one embedded Python file, sorted and grouped by start line number.
|
||||
///
|
||||
/// The diagnostics are kept in a flat vector, sorted by line number. A separate vector of
|
||||
/// [`LineDiagnosticRange`] has one entry for each contiguous slice of the diagnostics vector
|
||||
/// containing diagnostics which all start on the same line.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SortedDiagnostics<'a> {
|
||||
diagnostics: Vec<&'a Diagnostic>,
|
||||
line_ranges: Vec<LineDiagnosticRange>,
|
||||
}
|
||||
|
||||
impl<'a> SortedDiagnostics<'a> {
|
||||
pub(crate) fn new(
|
||||
diagnostics: impl IntoIterator<Item = &'a Diagnostic>,
|
||||
line_index: &LineIndex,
|
||||
) -> Self {
|
||||
let mut diagnostics: Vec<_> = diagnostics
|
||||
.into_iter()
|
||||
.map(|diagnostic| DiagnosticWithLine {
|
||||
line_number: diagnostic
|
||||
.primary_span()
|
||||
.and_then(|span| span.range())
|
||||
.map_or(OneIndexed::from_zero_indexed(0), |range| {
|
||||
line_index.line_index(range.start())
|
||||
}),
|
||||
diagnostic,
|
||||
})
|
||||
.collect();
|
||||
diagnostics.sort_unstable_by_key(|diagnostic_with_line| diagnostic_with_line.line_number);
|
||||
|
||||
let mut diags = Self {
|
||||
diagnostics: Vec::with_capacity(diagnostics.len()),
|
||||
line_ranges: vec![],
|
||||
};
|
||||
|
||||
let mut current_line_number = None;
|
||||
let mut start = 0;
|
||||
for DiagnosticWithLine {
|
||||
line_number,
|
||||
diagnostic,
|
||||
} in diagnostics
|
||||
{
|
||||
match current_line_number {
|
||||
None => {
|
||||
current_line_number = Some(line_number);
|
||||
}
|
||||
Some(current) => {
|
||||
if line_number != current {
|
||||
let end = diags.diagnostics.len();
|
||||
diags.line_ranges.push(LineDiagnosticRange {
|
||||
line_number: current,
|
||||
diagnostic_index_range: start..end,
|
||||
});
|
||||
start = end;
|
||||
current_line_number = Some(line_number);
|
||||
}
|
||||
}
|
||||
}
|
||||
diags.diagnostics.push(diagnostic);
|
||||
}
|
||||
if let Some(line_number) = current_line_number {
|
||||
diags.line_ranges.push(LineDiagnosticRange {
|
||||
line_number,
|
||||
diagnostic_index_range: start..diags.diagnostics.len(),
|
||||
});
|
||||
}
|
||||
|
||||
diags
|
||||
}
|
||||
|
||||
pub(crate) fn iter_lines(&self) -> LineDiagnosticsIterator<'_> {
|
||||
LineDiagnosticsIterator {
|
||||
diagnostics: self.diagnostics.as_slice(),
|
||||
inner: self.line_ranges.iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Range delineating diagnostics in [`SortedDiagnostics`] that begin on a single line.
|
||||
#[derive(Debug)]
|
||||
struct LineDiagnosticRange {
|
||||
line_number: OneIndexed,
|
||||
diagnostic_index_range: Range<usize>,
|
||||
}
|
||||
|
||||
/// Iterator to group sorted diagnostics by line.
|
||||
pub(crate) struct LineDiagnosticsIterator<'a> {
|
||||
diagnostics: &'a [&'a Diagnostic],
|
||||
inner: std::slice::Iter<'a, LineDiagnosticRange>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for LineDiagnosticsIterator<'a> {
|
||||
type Item = LineDiagnostics<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let LineDiagnosticRange {
|
||||
line_number,
|
||||
diagnostic_index_range,
|
||||
} = self.inner.next()?;
|
||||
Some(LineDiagnostics {
|
||||
line_number: *line_number,
|
||||
diagnostics: &self.diagnostics[diagnostic_index_range.clone()],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl std::iter::FusedIterator for LineDiagnosticsIterator<'_> {}
|
||||
|
||||
/// All diagnostics that start on a single line of source code in one embedded Python file.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct LineDiagnostics<'a> {
|
||||
/// Line number on which these diagnostics start.
|
||||
pub(crate) line_number: OneIndexed,
|
||||
|
||||
/// Diagnostics starting on this line.
|
||||
pub(crate) diagnostics: &'a [&'a Diagnostic],
|
||||
}
|
||||
|
||||
impl<'a> Deref for LineDiagnostics<'a> {
|
||||
type Target = [&'a Diagnostic];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.diagnostics
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DiagnosticWithLine<'a> {
|
||||
line_number: OneIndexed,
|
||||
diagnostic: &'a Diagnostic,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::db::Db;
|
||||
use ruff_db::diagnostic::{Annotation, Diagnostic, DiagnosticId, LintName, Severity, Span};
|
||||
use ruff_db::files::system_path_to_file;
|
||||
use ruff_db::source::line_index;
|
||||
use ruff_db::system::DbWithWritableSystem as _;
|
||||
use ruff_source_file::OneIndexed;
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
|
||||
#[test]
|
||||
fn sort_and_group() {
|
||||
let mut db = Db::setup();
|
||||
db.write_file("/src/test.py", "one\ntwo\n").unwrap();
|
||||
let file = system_path_to_file(&db, "/src/test.py").unwrap();
|
||||
let lines = line_index(&db, file);
|
||||
|
||||
let ranges = [
|
||||
TextRange::new(TextSize::new(0), TextSize::new(1)),
|
||||
TextRange::new(TextSize::new(5), TextSize::new(10)),
|
||||
TextRange::new(TextSize::new(1), TextSize::new(7)),
|
||||
];
|
||||
|
||||
let diagnostics: Vec<_> = ranges
|
||||
.into_iter()
|
||||
.map(|range| {
|
||||
let mut diag = Diagnostic::new(
|
||||
DiagnosticId::Lint(LintName::of("dummy")),
|
||||
Severity::Error,
|
||||
"dummy",
|
||||
);
|
||||
let span = Span::from(file).with_range(range);
|
||||
diag.annotate(Annotation::primary(span));
|
||||
diag
|
||||
})
|
||||
.collect();
|
||||
|
||||
let sorted = super::SortedDiagnostics::new(diagnostics.iter(), &lines);
|
||||
let grouped = sorted.iter_lines().collect::<Vec<_>>();
|
||||
|
||||
let [line1, line2] = &grouped[..] else {
|
||||
panic!("expected two lines");
|
||||
};
|
||||
|
||||
assert_eq!(line1.line_number, OneIndexed::from_zero_indexed(0));
|
||||
assert_eq!(line1.diagnostics.len(), 2);
|
||||
assert_eq!(line2.line_number, OneIndexed::from_zero_indexed(1));
|
||||
assert_eq!(line2.diagnostics.len(), 1);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
//! This module provides functionality to extract hover assertions from comments,
|
||||
//! infer types at specified positions, and generate hover check outputs for matching.
|
||||
|
||||
use crate::matcher;
|
||||
use crate::check_output::CheckOutput;
|
||||
use ruff_db::files::File;
|
||||
use ruff_db::parsed::parsed_module;
|
||||
use ruff_db::source::{line_index, source_text};
|
||||
@@ -74,7 +74,7 @@ pub(crate) fn generate_hover_outputs(
|
||||
db: &Db,
|
||||
file: File,
|
||||
assertions: &crate::assertion::InlineFileAssertions,
|
||||
) -> Vec<matcher::CheckOutput> {
|
||||
) -> Vec<CheckOutput> {
|
||||
let source = source_text(db, file);
|
||||
let lines = line_index(db, file);
|
||||
|
||||
@@ -107,7 +107,7 @@ pub(crate) fn generate_hover_outputs(
|
||||
continue;
|
||||
};
|
||||
|
||||
hover_outputs.push(matcher::CheckOutput::Hover {
|
||||
hover_outputs.push(CheckOutput::Hover {
|
||||
offset: hover_offset,
|
||||
inferred_type,
|
||||
});
|
||||
|
||||
@@ -24,9 +24,9 @@ use ty_python_semantic::{
|
||||
};
|
||||
|
||||
mod assertion;
|
||||
mod check_output;
|
||||
mod config;
|
||||
mod db;
|
||||
mod diagnostic;
|
||||
mod hover;
|
||||
mod matcher;
|
||||
mod parser;
|
||||
@@ -372,9 +372,9 @@ fn run_test(
|
||||
});
|
||||
|
||||
// Convert diagnostics to CheckOutput
|
||||
let mut check_outputs: Vec<matcher::CheckOutput> = diagnostics
|
||||
let mut check_outputs: Vec<check_output::CheckOutput> = diagnostics
|
||||
.iter()
|
||||
.map(|diag| matcher::CheckOutput::Diagnostic(diag.clone()))
|
||||
.map(|diag| check_output::CheckOutput::Diagnostic(diag.clone()))
|
||||
.collect();
|
||||
|
||||
// Parse assertions to get hover assertions with correct line numbers
|
||||
|
||||
@@ -10,150 +10,11 @@ use ruff_db::diagnostic::{Diagnostic, DiagnosticId};
|
||||
use ruff_db::files::File;
|
||||
use ruff_db::source::{SourceText, line_index, source_text};
|
||||
use ruff_source_file::{LineIndex, OneIndexed};
|
||||
use ruff_text_size::TextSize;
|
||||
|
||||
use crate::assertion::{InlineFileAssertions, ParsedAssertion, UnparsedAssertion};
|
||||
use crate::check_output::{CheckOutput, LineCheckOutputs, SortedCheckOutputs};
|
||||
use crate::db::Db;
|
||||
|
||||
/// Represents either a diagnostic or a hover result for matching against assertions.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum CheckOutput {
|
||||
/// A regular diagnostic from the type checker
|
||||
Diagnostic(Diagnostic),
|
||||
|
||||
/// A hover result for testing hover assertions
|
||||
Hover {
|
||||
/// The position where hover was requested
|
||||
offset: TextSize,
|
||||
/// The inferred type at that position
|
||||
inferred_type: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl CheckOutput {
|
||||
fn line_number(&self, line_index: &LineIndex) -> OneIndexed {
|
||||
match self {
|
||||
CheckOutput::Diagnostic(diag) => diag
|
||||
.primary_span()
|
||||
.and_then(|span| span.range())
|
||||
.map_or(OneIndexed::from_zero_indexed(0), |range| {
|
||||
line_index.line_index(range.start())
|
||||
}),
|
||||
CheckOutput::Hover { offset, .. } => line_index.line_index(*offset),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// All check outputs for one embedded Python file, sorted and grouped by line number.
|
||||
///
|
||||
/// Similar to `SortedDiagnostics` but works with `CheckOutput` instead.
|
||||
#[derive(Debug)]
|
||||
struct SortedCheckOutputs {
|
||||
outputs: Vec<CheckOutput>,
|
||||
line_ranges: Vec<LineOutputRange>,
|
||||
}
|
||||
|
||||
impl SortedCheckOutputs {
|
||||
fn new(outputs: &[CheckOutput], line_index: &LineIndex) -> Self {
|
||||
let mut outputs: Vec<_> = outputs
|
||||
.iter()
|
||||
.map(|output| OutputWithLine {
|
||||
line_number: output.line_number(line_index),
|
||||
output: output.clone(),
|
||||
})
|
||||
.collect();
|
||||
outputs.sort_unstable_by_key(|output_with_line| output_with_line.line_number);
|
||||
|
||||
let mut result = Self {
|
||||
outputs: Vec::with_capacity(outputs.len()),
|
||||
line_ranges: vec![],
|
||||
};
|
||||
|
||||
let mut current_line_number = None;
|
||||
let mut start = 0;
|
||||
for OutputWithLine {
|
||||
line_number,
|
||||
output,
|
||||
} in outputs
|
||||
{
|
||||
match current_line_number {
|
||||
None => {
|
||||
current_line_number = Some(line_number);
|
||||
}
|
||||
Some(current) => {
|
||||
if line_number != current {
|
||||
let end = result.outputs.len();
|
||||
result.line_ranges.push(LineOutputRange {
|
||||
line_number: current,
|
||||
output_index_range: start..end,
|
||||
});
|
||||
start = end;
|
||||
current_line_number = Some(line_number);
|
||||
}
|
||||
}
|
||||
}
|
||||
result.outputs.push(output);
|
||||
}
|
||||
if let Some(line_number) = current_line_number {
|
||||
result.line_ranges.push(LineOutputRange {
|
||||
line_number,
|
||||
output_index_range: start..result.outputs.len(),
|
||||
});
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn iter_lines(&self) -> LineCheckOutputsIterator<'_> {
|
||||
LineCheckOutputsIterator {
|
||||
outputs: self.outputs.as_slice(),
|
||||
inner: self.line_ranges.iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct OutputWithLine {
|
||||
line_number: OneIndexed,
|
||||
output: CheckOutput,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LineOutputRange {
|
||||
line_number: OneIndexed,
|
||||
output_index_range: Range<usize>,
|
||||
}
|
||||
|
||||
/// Iterator to group sorted check outputs by line.
|
||||
struct LineCheckOutputsIterator<'a> {
|
||||
outputs: &'a [CheckOutput],
|
||||
inner: std::slice::Iter<'a, LineOutputRange>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for LineCheckOutputsIterator<'a> {
|
||||
type Item = LineCheckOutputs<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let LineOutputRange {
|
||||
line_number,
|
||||
output_index_range,
|
||||
} = self.inner.next()?;
|
||||
Some(LineCheckOutputs {
|
||||
line_number: *line_number,
|
||||
outputs: &self.outputs[output_index_range.clone()],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl std::iter::FusedIterator for LineCheckOutputsIterator<'_> {}
|
||||
|
||||
/// All check outputs that start on a single line of source code.
|
||||
#[derive(Debug)]
|
||||
struct LineCheckOutputs<'a> {
|
||||
line_number: OneIndexed,
|
||||
outputs: &'a [CheckOutput],
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(super) struct FailuresByLine {
|
||||
failures: Vec<String>,
|
||||
@@ -566,6 +427,7 @@ impl Matcher {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FailuresByLine;
|
||||
use crate::check_output::CheckOutput;
|
||||
use ruff_db::Db;
|
||||
use ruff_db::diagnostic::{Annotation, Diagnostic, DiagnosticId, Severity, Span};
|
||||
use ruff_db::files::{File, system_path_to_file};
|
||||
@@ -625,11 +487,11 @@ mod tests {
|
||||
db.write_file("/src/test.py", source).unwrap();
|
||||
let file = system_path_to_file(&db, "/src/test.py").unwrap();
|
||||
|
||||
let diagnostics: Vec<Diagnostic> = expected_diagnostics
|
||||
let check_outputs: Vec<CheckOutput> = expected_diagnostics
|
||||
.into_iter()
|
||||
.map(|diagnostic| diagnostic.into_diagnostic(file))
|
||||
.map(|diagnostic| CheckOutput::Diagnostic(diagnostic.into_diagnostic(file)))
|
||||
.collect();
|
||||
super::match_file(&db, file, &diagnostics)
|
||||
super::match_file(&db, file, &check_outputs)
|
||||
}
|
||||
|
||||
fn assert_fail(result: Result<(), FailuresByLine>, messages: &[(usize, &[&str])]) {
|
||||
|
||||
Reference in New Issue
Block a user