[ty_test] Extract HoverOutput type from CheckOutput enum

Create a dedicated HoverOutput struct to hold hover result data,
replacing the inline fields in CheckOutput::Hover variant.

This allows implementing Unmatched and UnmatchedWithColumn traits
directly on HoverOutput, simplifying the CheckOutput implementations
to simple delegation.

Benefits:
- Better separation of concerns
- Cleaner trait implementations
- More consistent with Diagnostic handling
- Easier to extend HoverOutput in the future

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Douglas Creager 2025-10-08 13:52:58 -04:00
parent ac1b68c56d
commit 35a5fd767d
3 changed files with 37 additions and 21 deletions

View File

@ -8,6 +8,15 @@ use ruff_source_file::{LineIndex, OneIndexed};
use ruff_text_size::TextSize; use ruff_text_size::TextSize;
use std::ops::Range; use std::ops::Range;
/// A hover result for testing hover assertions.
#[derive(Debug, Clone)]
pub(crate) struct HoverOutput {
/// The position where hover was requested
pub(crate) offset: TextSize,
/// The inferred type at that position
pub(crate) inferred_type: String,
}
/// Represents either a diagnostic or a hover result for matching against assertions. /// Represents either a diagnostic or a hover result for matching against assertions.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum CheckOutput { pub(crate) enum CheckOutput {
@ -15,12 +24,7 @@ pub(crate) enum CheckOutput {
Diagnostic(Diagnostic), Diagnostic(Diagnostic),
/// A hover result for testing hover assertions /// A hover result for testing hover assertions
Hover { Hover(HoverOutput),
/// The position where hover was requested
offset: TextSize,
/// The inferred type at that position
inferred_type: String,
},
} }
impl CheckOutput { impl CheckOutput {
@ -32,7 +36,7 @@ impl CheckOutput {
.map_or(OneIndexed::from_zero_indexed(0), |range| { .map_or(OneIndexed::from_zero_indexed(0), |range| {
line_index.line_index(range.start()) line_index.line_index(range.start())
}), }),
CheckOutput::Hover { offset, .. } => line_index.line_index(*offset), CheckOutput::Hover(hover) => line_index.line_index(hover.offset),
} }
} }
} }

View File

@ -3,7 +3,7 @@
//! This module provides functionality to extract hover assertions from comments, //! This module provides functionality to extract hover assertions from comments,
//! infer types at specified positions, and generate hover check outputs for matching. //! infer types at specified positions, and generate hover check outputs for matching.
use crate::check_output::CheckOutput; use crate::check_output::{CheckOutput, HoverOutput};
use ruff_db::files::File; use ruff_db::files::File;
use ruff_db::parsed::parsed_module; use ruff_db::parsed::parsed_module;
use ruff_db::source::{line_index, source_text}; use ruff_db::source::{line_index, source_text};
@ -107,10 +107,10 @@ pub(crate) fn generate_hover_outputs(
continue; continue;
}; };
hover_outputs.push(CheckOutput::Hover { hover_outputs.push(CheckOutput::Hover(HoverOutput {
offset: hover_offset, offset: hover_offset,
inferred_type, inferred_type,
}); }));
} }
} }

View File

@ -12,7 +12,7 @@ use ruff_db::source::{SourceText, line_index, source_text};
use ruff_source_file::{LineIndex, OneIndexed}; use ruff_source_file::{LineIndex, OneIndexed};
use crate::assertion::{InlineFileAssertions, ParsedAssertion, UnparsedAssertion}; use crate::assertion::{InlineFileAssertions, ParsedAssertion, UnparsedAssertion};
use crate::check_output::{CheckOutput, LineCheckOutputs, SortedCheckOutputs}; use crate::check_output::{CheckOutput, HoverOutput, LineCheckOutputs, SortedCheckOutputs};
use crate::db::Db; use crate::db::Db;
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -174,13 +174,28 @@ impl Unmatched for CheckOutput {
fn unmatched(&self) -> String { fn unmatched(&self) -> String {
match self { match self {
CheckOutput::Diagnostic(diag) => diag.unmatched(), CheckOutput::Diagnostic(diag) => diag.unmatched(),
CheckOutput::Hover { inferred_type, .. } => { CheckOutput::Hover(hover) => hover.unmatched(),
format!("{} hover result: {inferred_type}", "unexpected:".red())
}
} }
} }
} }
impl Unmatched for &HoverOutput {
fn unmatched(&self) -> String {
format!("{} hover result: {}", "unexpected:".red(), self.inferred_type)
}
}
impl UnmatchedWithColumn for &HoverOutput {
fn unmatched_with_column(&self, column: OneIndexed) -> String {
format!(
"{} {} hover result: {}",
"unexpected:".red(),
column,
self.inferred_type
)
}
}
impl Unmatched for &Diagnostic { impl Unmatched for &Diagnostic {
fn unmatched(&self) -> String { fn unmatched(&self) -> String {
maybe_add_undefined_reveal_clarification( maybe_add_undefined_reveal_clarification(
@ -267,8 +282,8 @@ impl Matcher {
CheckOutput::Diagnostic(diag) => { CheckOutput::Diagnostic(diag) => {
failures.push(diag.unmatched_with_column(self.column(diag))); failures.push(diag.unmatched_with_column(self.column(diag)));
} }
CheckOutput::Hover { inferred_type, .. } => { CheckOutput::Hover(hover) => {
failures.push(format!("{} hover result: {inferred_type}", "unexpected:".red())); failures.push(hover.unmatched());
} }
} }
} }
@ -401,15 +416,12 @@ impl Matcher {
// Find a hover output that matches the expected type // Find a hover output that matches the expected type
let position = unmatched.iter().position(|output| { let position = unmatched.iter().position(|output| {
let CheckOutput::Hover { let CheckOutput::Hover(hover_output) = output else {
inferred_type, ..
} = output
else {
return false; return false;
}; };
// Compare the inferred type with the expected type // Compare the inferred type with the expected type
let inferred_type = discard_todo_metadata(inferred_type); let inferred_type = discard_todo_metadata(&hover_output.inferred_type);
inferred_type == expected_type inferred_type == expected_type
}); });