use cranpose_render_common::{
image_compare::pixel_difference,
layer_transform::apply_layer_affine_to_point,
raster_cache::ScaleBucket,
style_shared::{ResolvedBrush, resolve_layer_brush},
};
use cranpose_ui_graphics::{Brush, Color, GraphicsLayer, Point, Rect};
fn bounds() -> Rect {
Rect {
x: 0.0,
y: 0.0,
width: 100.0,
height: 100.0,
}
}
#[test]
fn an_identity_layer_leaves_a_point_exactly_where_it_was() {
let point = Point::new(12.5, 37.25);
let mapped = apply_layer_affine_to_point(point, bounds(), &GraphicsLayer::default());
assert_eq!(mapped, point, "an identity layer moved the point");
}
#[test]
fn a_translated_layer_moves_a_point_by_the_translation() {
let layer = GraphicsLayer {
translation_x: 10.0,
translation_y: -4.0,
..GraphicsLayer::default()
};
let mapped = apply_layer_affine_to_point(Point::new(1.0, 2.0), bounds(), &layer);
assert_eq!(mapped, Point::new(11.0, -2.0));
}
#[test]
fn a_scaled_layer_scales_about_its_pivot_and_leaves_the_pivot_alone() {
let layer = GraphicsLayer {
scale_x: 2.0,
scale_y: 2.0,
..GraphicsLayer::default()
};
let pivot = Point::new(50.0, 50.0);
assert_eq!(
apply_layer_affine_to_point(pivot, bounds(), &layer),
pivot,
"the pivot must be the one point a scale does not move"
);
assert_eq!(
apply_layer_affine_to_point(Point::new(60.0, 50.0), bounds(), &layer),
Point::new(70.0, 50.0),
"a point ten past the pivot must end twenty past it at 2x"
);
}
#[test]
fn a_solid_brush_passes_through_an_untouched_layer_unchanged() {
let brush = Brush::Solid(Color::rgba(1.0, 0.0, 0.0, 1.0));
match resolve_layer_brush(&brush, &GraphicsLayer::default()) {
ResolvedBrush::Solid(color) => assert_eq!(color, Color::rgba(1.0, 0.0, 0.0, 1.0)),
other => panic!("an identity layer changed a solid brush: {other:?}"),
}
}
#[test]
fn a_solid_brush_takes_the_layers_alpha() {
let layer = GraphicsLayer {
alpha: 0.5,
..GraphicsLayer::default()
};
let brush = Brush::Solid(Color::rgba(1.0, 0.0, 0.0, 1.0));
match resolve_layer_brush(&brush, &layer) {
ResolvedBrush::Solid(color) => assert!(
color.a() < 1.0,
"the layer's alpha never reached the colour: {color:?}"
),
other => panic!("a solid brush stopped being solid: {other:?}"),
}
}
#[test]
fn identical_pixels_differ_by_nothing_and_opposites_differ_by_everything() {
assert_eq!(pixel_difference([1, 2, 3, 4], [1, 2, 3, 4]), 0);
assert_eq!(
pixel_difference([0, 0, 0, 0], [255, 255, 255, 255]),
255 * 4,
"the difference must sum every channel"
);
assert_eq!(
pixel_difference([10, 20, 30, 40], [40, 30, 20, 10]),
pixel_difference([40, 30, 20, 10], [10, 20, 30, 40])
);
}
#[test]
fn a_scale_bucket_normalises_a_scale_that_cannot_be_rastered_at() {
let unit = ScaleBucket::from_scale(1.0);
for impossible in [0.0, -3.0, f32::NAN] {
assert_eq!(
ScaleBucket::from_scale(impossible).raw(),
unit.raw(),
"a scale of {impossible} was given a bucket of its own"
);
}
}
#[test]
fn two_different_scales_do_not_share_one_raster_bucket() {
assert_ne!(
ScaleBucket::from_scale(1.0).raw(),
ScaleBucket::from_scale(2.0).raw(),
"1x and 2x sharing a bucket would serve a blurry raster to one of them"
);
}
#[test]
fn a_font_registry_rejects_fallback_bytes_that_are_not_a_font() {
use cranpose_render_common::font_source::SoftwareTextFontRegistry;
let mut registry = SoftwareTextFontRegistry::default();
assert!(
registry
.register_fallback_bytes(b"not a font".to_vec())
.is_err(),
"the registry accepted ten bytes of text as a typeface"
);
}
#[test]
fn a_scene_counts_the_live_modifier_slice_lookups_that_missed() {
use cranpose_render_common::graph_scene::RenderDiagnostics;
let diagnostics = RenderDiagnostics::new();
assert_eq!(diagnostics.live_modifier_slice_lookup_miss_count(), 0);
diagnostics.record_live_modifier_slice_lookup_miss();
diagnostics.record_live_modifier_slice_lookup_miss();
assert_eq!(
diagnostics.live_modifier_slice_lookup_miss_count(),
2,
"a miss counter that does not count is a diagnostic that lies"
);
}