use std::collections::HashSet;
use super::render::{entry, tx};
use crate::paint_probe::{Seen, screen_sized, seen_of};
use crate::transcript::{AutoExpand, Block, EntryKind, Transcript, Usage};
pub(super) const SIZES: [(f32, f32); 2] = [(420.0, 320.0), (800.0, 500.0)];
pub(super) const OPEN: &str = "▼";
pub(super) const SHUT: &str = "▶";
const NO_FOLD: &str = "·";
const SHORT: &str = "pong";
pub(super) fn long() -> String {
"abcdefghij".repeat(40)
}
pub(super) fn seen(t: &Transcript, auto: AutoExpand, bounded: bool, w: f32, h: f32) -> Vec<Seen> {
let ctx = egui::Context::default();
let mut folds = HashSet::new();
let mut frame = || {
ctx.run(screen_sized(w, h), |ctx| {
egui::CentralPanel::default().show(ctx, |ui| {
if bounded {
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Truncate);
}
super::plain(ui, t, false, auto, &mut folds);
});
})
};
let _ = frame();
seen_of(&frame())
}
pub(super) fn whole(seen: &Seen) -> bool {
seen.shown.width() >= seen.laid.width() - 1.0
}
pub(super) fn run(painted: &[Seen], needle: &str) -> Seen {
let seats: Vec<&String> = painted.iter().map(|s| &s.text).collect();
let hit = painted.iter().find(|s| s.text.contains(needle)).cloned();
assert!(
hit.is_some(),
"nothing on the glass carries {needle:?}: {seats:?}"
);
hit.expect("asserted present just above")
}
pub(super) fn answer(payload: &str) -> Transcript {
tx(vec![entry(EntryKind::Model {
model_id: "opus".into(),
usage: Usage::default(),
blocks: vec![Block::Text(payload.into())],
})])
}
#[test]
fn an_expanded_answer_reaches_the_glass_entire() {
let payload = long();
let t = answer(&payload);
for bounded in [false, true] {
for (w, h) in SIZES {
let painted = seen(&t, AutoExpand::default(), bounded, w, h);
let body = run(&painted, "abcdefghij");
assert_eq!(
body.text,
payload,
"the open fold shows {} of {} characters at {w}x{h} (bounded {bounded})",
body.text.chars().count(),
payload.chars().count()
);
assert!(
whole(&body),
"the open fold's body is sliced at {w}x{h} (bounded {bounded}): \
{:.0} pt laid, {:.0} pt shown",
body.laid.width(),
body.shown.width()
);
assert!(
painted.iter().any(|s| s.text == OPEN),
"an expanded row wears the open triangle at {w}x{h}"
);
}
}
}
#[test]
fn a_contracted_preview_says_it_is_abridged_and_wears_a_triangle() {
let t = answer(&long());
let auto = AutoExpand {
responses: false,
others: false,
};
for bounded in [false, true] {
for (w, h) in SIZES {
let painted = seen(&t, auto, bounded, w, h);
let preview = run(&painted, "abcdefghij");
assert!(
whole(&preview),
"the preview is cut with no ellipsis at {w}x{h} (bounded {bounded}): \
{:.0} pt laid, {:.0} pt shown, {:?}",
preview.laid.width(),
preview.shown.width(),
preview.text
);
assert!(
preview.text.ends_with('…'),
"an abridged preview must say so at {w}x{h} (bounded {bounded}): {:?}",
preview.text
);
assert!(
painted.iter().any(|s| s.text == SHUT),
"the abridged row wears the shut triangle at {w}x{h}"
);
}
}
}
#[test]
fn only_an_abridged_preview_is_faded() {
let shut = AutoExpand {
responses: false,
others: false,
};
for (w, h) in SIZES {
let complete = seen(&answer(SHORT), AutoExpand::default(), true, w, h);
let solid = run(&complete, SHORT);
assert_eq!(
solid.ink.a(),
u8::MAX,
"a row with nothing to fold IS the whole content and must not read \
as abridged at {w}x{h}: {:?}",
solid.ink
);
assert!(
complete.iter().all(|s| s.text != SHUT && s.text != OPEN),
"the fixture must have nothing to fold, or this proves nothing: {:?}",
complete.iter().map(|s| &s.text).collect::<Vec<_>>()
);
let abridged = seen(&answer(&long()), shut, true, w, h);
let faded = run(&abridged, "abcdefghij");
let want = crate::theme::tone_solidity(crate::transcript::Tone::Weak);
assert!(
(f32::from(faded.ink.a()) / f32::from(u8::MAX) - want).abs() < 0.02,
"an abridged preview paints at the §11 solidity {want} at {w}x{h}, \
got alpha {} ({:?})",
faded.ink.a(),
faded.ink
);
}
}
#[test]
fn no_run_is_hidden_without_a_triangle_beside_it() {
let t = super::parity::mixed(&long());
for bounded in [false, true] {
for auto in [
AutoExpand::default(),
AutoExpand {
responses: false,
others: false,
},
AutoExpand {
responses: true,
others: true,
},
] {
for (w, h) in SIZES {
let painted = seen(&t, auto, bounded, w, h);
for s in &painted {
let seat = format!("{:?} at {w}x{h} (bounded {bounded}, {auto:?})", s.text);
assert!(whole(s), "cut with no ellipsis: {seat}");
if !s.text.ends_with('…') {
continue;
}
let band = s.laid.top() - 1.0..=s.laid.bottom() + 1.0;
assert!(
painted.iter().any(|g| {
(g.text == SHUT || g.text == OPEN) && band.contains(&g.laid.center().y)
}),
"marked as cut with no triangle to turn: {seat}"
);
}
}
}
}
}
#[test]
fn a_row_with_nothing_to_fold_wears_the_alignment_mark() {
let painted = seen(&answer(SHORT), AutoExpand::default(), true, 800.0, 500.0);
assert!(painted.iter().any(|s| s.text == NO_FOLD));
}
#[test]
fn the_raw_view_shows_its_verbatim_bytes_whole() {
let payload = long();
let t = Transcript {
entries: vec![crate::transcript::Entry {
name: "001-opus.json".into(),
raw: payload.clone().into_bytes(),
kind: EntryKind::Raw,
}],
};
let ctx = egui::Context::default();
let mut folds = HashSet::new();
let mut frame = || {
ctx.run(screen_sized(420.0, 320.0), |ctx| {
egui::CentralPanel::default().show(ctx, |ui| {
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Truncate);
super::plain(ui, &t, true, AutoExpand::default(), &mut folds);
});
})
};
let _ = frame();
let painted = seen_of(&frame());
let bytes = run(&painted, "abcdefghij");
assert_eq!(bytes.text, payload, "the Raw view shows every byte");
assert!(whole(&bytes), "the Raw view is cut: {:?}", bytes.text);
assert!(
painted.iter().all(|s| s.text != SHUT && s.text != OPEN),
"Raw carries no fold to turn, which is why it may hide nothing"
);
}