Files
ARCADIA-Studio/harness/experiments/scenario-label-measurement-20260913/attempt1/tests.rs
T

121 lines
5.9 KiB
Rust

//! Unexecuted evaluator candidates; the module is intentionally not wired yet.
use super::*;
use iced::advanced::{graphics::text::Paragraph, text::{Paragraph as _, Text as ParagraphText, Wrapping}};
// Independent paragraph construction: no candidate cache, normalization, search,
// or character-width estimate is used by this measurement oracle.
fn paragraph_size(content: &str, zoom: f32, style: Style) -> Size {
let size = Pixels(style.size.0 * zoom);
let line_height = match style.line_height {
LineHeight::Relative(factor) => LineHeight::Relative(factor),
LineHeight::Absolute(pixels) => LineHeight::Absolute(Pixels(pixels.0 * zoom)),
};
let paragraph = Paragraph::with_text(ParagraphText { content, bounds: Size::INFINITE,
size, line_height, font: style.font, align_x: Alignment::Default,
align_y: iced::alignment::Vertical::Top, shaping: style.shaping, wrapping: Wrapping::default() });
assert_eq!(paragraph.buffer().layout_runs().count(), 1);
Size::new(paragraph.min_width() / zoom, paragraph.min_height() / zoom)
}
#[test]
fn adequate_corridor_reveals_full_realistic_names_and_distinguishing_suffixes() {
let mut cache = Cache::default();
let style = Style::default();
for text in [
"1. call · Request valve repair · Technician service conversation",
"2. reply · Return pressure after repair · Technician service conversation",
"1. call · Request redundant hydraulic pressure calibration channel A",
"1. call · Request redundant hydraulic pressure calibration channel B",
] {
let wide = cache.resolve(text, 1600., 1., style).unwrap();
assert_eq!(wide.displayed, text);
assert_eq!(wide.retained_source, 0..text.len());
assert_eq!(wide.bounds.size(), paragraph_size(text, 1., style));
let narrow = cache.resolve(text, 80., 1., style).unwrap();
assert_ne!(narrow.displayed, text);
assert!(narrow.bounds.width <= 80.);
assert_eq!(narrow.bounds.size(), paragraph_size(&narrow.displayed, 1., style));
}
}
#[test]
fn normalized_visible_prefix_maps_to_original_bytes_without_claiming_hidden_operation() {
let raw = " \t1. call · Pump\r\n · Operation: Need\u{301}le ";
let expected = "1. call · Pump · Operation: Need\u{301}le";
let n = Normalized::new(raw);
assert_eq!(n.text, expected);
let prefix = "1. call · Pump ";
assert_eq!(n.source_end(prefix.len()), raw.find("· Operation").unwrap());
let mut cache = Cache::default();
let wide = cache.resolve(raw, 1600., 1., Style::default()).unwrap();
assert_eq!(wide.displayed, expected);
assert_eq!(wide.retained_source.end, raw.trim_end().len());
let field = raw.find("Need").unwrap()..raw.trim_end().len();
assert!(wide.retains_any(field.clone()));
assert!(!wide.retains_any(0..2), "normalized whitespace is not a visible field");
let small = cache.resolve(raw, 70., 1., Style::default()).unwrap();
assert!(!small.retains_any(field));
assert!(small.retained_source.end < raw.find("Operation").unwrap());
}
#[test]
fn grapheme_prefixes_and_zoom_match_actual_paragraph_layout() {
let text = "call · 戻り値 圧力 e\u{301} 👩‍🔬 safety valve verification";
let mut cache = Cache::default();
for zoom in [0.66, 1., 1.75] {
let label = cache.resolve(text, 105., zoom, Style::default()).unwrap();
assert!(label.bounds.width <= 105.);
assert_eq!(label.bounds.size(), paragraph_size(&label.displayed, zoom, Style::default()));
assert!(text.grapheme_indices(true).any(|(i, _)| i == label.retained_source.end)
|| label.retained_source.end == text.len());
let painted = label.canvas_text(Point::new(400., 90.), Color::BLACK);
assert_eq!(painted.content, label.displayed);
assert!(painted.max_width.is_infinite());
assert_eq!(label.bounds_at(painted.position).size(), label.bounds.size());
}
}
#[test]
fn empty_and_too_narrow_labels_never_claim_source_visibility() {
let mut cache = Cache::default();
for text in ["", " \t\n", "Operation: Pump"] {
let label = cache.resolve(text, 0., 1., Style::default()).unwrap();
assert_eq!(label.displayed, "");
assert_eq!(label.retained_source, 0..0);
assert_eq!(label.bounds.size(), Size::ZERO);
assert!(!label.retains_any(0..text.len()));
}
}
#[test]
fn redraws_reuse_resolution_but_width_zoom_style_and_font_epoch_are_dependencies() {
let mut cache = Cache::default();
let text = "call · Pressure verification with a descriptive operation label";
let style = Style::default();
let a = cache.resolve(text, 100., 1., style).unwrap();
let measured = cache.allocations;
let b = cache.resolve(text, 100., 1., style).unwrap();
assert!(Arc::ptr_eq(&a, &b));
assert_eq!(cache.allocations, measured);
for (width, zoom, style) in [(120., 1., style), (100., 0.66, style),
(100., 1., Style { size: Pixels(14.), ..style })] {
let other = cache.resolve(text, width, zoom, style).unwrap();
assert!(!Arc::ptr_eq(&a, &other));
}
// Simulate an invalidated local epoch without mutating the shared font DB.
cache.version = None;
let refreshed = cache.resolve(text, 100., 1., style).unwrap();
assert!(!Arc::ptr_eq(&a, &refreshed));
}
#[test]
fn malformed_metrics_and_explicit_experiment_budgets_fail_without_a_cached_candidate() {
let mut cache = Cache::default();
for (width, zoom) in [(f32::NAN, 1.), (-1., 1.), (100., 0.), (100., f32::INFINITY)] {
assert_eq!(cache.resolve("call", width, zoom, Style::default()).unwrap_err(), Error::InvalidMetrics);
}
assert_eq!(cache.resolve(&"x".repeat(MAX_SOURCE_BYTES + 1), 100., 1., Style::default()).unwrap_err(), Error::SourceBudget);
assert_eq!(cache.resolve(&"x".repeat(MAX_GRAPHEMES + 1), 100., 1., Style::default()).unwrap_err(), Error::GraphemeBudget);
assert!(cache.entries.is_empty());
}