use std::cell::RefCell;
use std::rc::Rc;
use egui_kittest::Harness;
use egui_kittest::wgpu::{WgpuTestRenderer, create_render_state, default_wgpu_setup};
use rsplot::egui::{self, Color32, Pos2};
use rsplot::{CurveSpec, PlotWidget, YAxis};
const W: usize = 400;
const H: usize = 300;
const WIDTH: f32 = 24.0;
const HALF: f32 = WIDTH / 2.0;
fn is_red(px: [u8; 4]) -> bool {
px[0] > 150 && px[1] < 100 && px[2] < 100
}
fn render_curve(x: &[f64], y: &[f64], probes: &[(f64, f64)]) -> (Vec<u8>, Vec<Pos2>) {
let rs = create_render_state(default_wgpu_setup());
rsplot::install(&rs);
let mut plot = PlotWidget::new(&rs, 0);
let mut spec = CurveSpec::new(x, y, Color32::RED);
spec.line_width = WIDTH;
plot.add_curve_spec(spec);
plot.set_show_colorbar(false);
plot.set_auto_reset_zoom(false);
plot.set_graph_x_limits(0.0, 1.0);
plot.set_graph_y_limits(0.0, 1.0, YAxis::Left);
let app = Rc::new(RefCell::new(plot));
let app_ui = app.clone();
let renderer = WgpuTestRenderer::from_render_state(rs);
let mut harness = Harness::builder()
.with_size(egui::vec2(W as f32, H as f32))
.with_pixels_per_point(1.0)
.renderer(renderer)
.build_ui(move |ui| {
app_ui.borrow_mut().show(ui);
});
harness.step();
harness.step();
let image = harness.render().expect("headless wgpu render");
let raw = image.as_raw().to_vec();
let projected = probes
.iter()
.map(|&(px, py)| {
app.borrow()
.data_to_pixel(px, py, YAxis::Left)
.expect("display transform cached after render")
})
.collect();
(raw, projected)
}
fn pixel_at(raw: &[u8], x: f32, y: f32) -> [u8; 4] {
let col = x.round() as i64;
let row = y.round() as i64;
assert!(
col >= 0 && (col as usize) < W && row >= 0 && (row as usize) < H,
"probe ({x:.1},{y:.1}) is outside the {W}x{H} frame"
);
let i = (row as usize * W + col as usize) * 4;
[raw[i], raw[i + 1], raw[i + 2], raw[i + 3]]
}
#[test]
fn solid_curve_has_round_caps_at_endpoints() {
let (raw, p) = render_curve(&[0.2, 0.8], &[0.5, 0.5], &[(0.2, 0.5)]);
let e0 = p[0];
assert!(
is_red(pixel_at(&raw, e0.x + 6.0, e0.y)),
"the line body must be red"
);
let tip = pixel_at(&raw, e0.x - (HALF - 3.0), e0.y);
assert!(
is_red(tip),
"a round cap must extend ~half the width beyond the endpoint: tip={tip:?}"
);
let corner = pixel_at(&raw, e0.x - (HALF + 2.0), e0.y - (HALF + 2.0));
assert!(
!is_red(corner),
"a round cap's corner must be background (not a square cap): corner={corner:?}"
);
}
#[test]
fn solid_curve_has_round_joins_at_turns() {
let (raw, p) = render_curve(&[0.3, 0.7, 0.7], &[0.3, 0.3, 0.7], &[(0.7, 0.3)]);
let v = p[0];
let wedge = pixel_at(&raw, v.x + 8.0, v.y + 8.0);
assert!(
is_red(wedge),
"a round join must fill the outer wedge gap at a sharp turn: wedge={wedge:?}"
);
let far = pixel_at(&raw, v.x + (HALF + 3.0), v.y + (HALF + 3.0));
assert!(
!is_red(far),
"a round join must not extend past the line width (no miter spike): far={far:?}"
);
}