mod common;
use common::*;
use zenith_core::default_provider;
use zenith_scene::compile_page;
use zenith_scene::ir::{Color, Paint, SceneCommand};
fn fill_polygon_colors(result: &zenith_scene::CompileResult) -> Vec<Color> {
result
.scene
.commands
.iter()
.filter_map(|c| match c {
SceneCommand::FillPolygon {
paint: Paint::Solid { color },
..
} => Some(*color),
_ => None,
})
.collect()
}
fn fill_rect_colors(result: &zenith_scene::CompileResult) -> Vec<Color> {
result
.scene
.commands
.iter()
.filter_map(|c| match c {
SceneCommand::FillRect {
paint: Paint::Solid { color },
..
} => Some(*color),
_ => None,
})
.collect()
}
const PALETTE_0: Color = Color::srgb(66, 133, 244, 255);
const PALETTE_1: Color = Color::srgb(234, 67, 53, 255);
#[test]
fn pie_without_slice_colors_uses_palette() {
let src = r##"zenith version=1 {
project id="proj.pf" name="PF"
tokens format="zenith-token-v1" {}
styles {}
document id="doc.pf" title="PF" {
page id="page.pf" w=(px)400 h=(px)400 {
chart id="c.pf" kind="pie" x=(px)0 y=(px)0 w=(px)400 h=(px)400 {
series 50.0 50.0
}
}
}
}"##;
let doc = parse(src);
let result = compile_page(&doc, &default_provider(), 0, None);
let colors = fill_polygon_colors(&result);
assert_eq!(
colors.len(),
2,
"two equal slices → two FillPolygon commands"
);
assert_eq!(
colors[0], PALETTE_0,
"slice 0 should use palette slot 0 (blue)"
);
assert_eq!(
colors[1], PALETTE_1,
"slice 1 should use palette slot 1 (red)"
);
}
#[test]
fn donut_without_slice_colors_uses_palette() {
let src = r##"zenith version=1 {
project id="proj.df" name="DF"
tokens format="zenith-token-v1" {}
styles {}
document id="doc.df" title="DF" {
page id="page.df" w=(px)400 h=(px)400 {
chart id="c.df" kind="donut" x=(px)0 y=(px)0 w=(px)400 h=(px)400 {
series 50.0 50.0
}
}
}
}"##;
let doc = parse(src);
let result = compile_page(&doc, &default_provider(), 0, None);
let colors = fill_polygon_colors(&result);
assert_eq!(
colors.len(),
2,
"two equal slices → two FillPolygon commands"
);
assert_eq!(
colors[0], PALETTE_0,
"donut slice 0 should use palette slot 0"
);
assert_eq!(
colors[1], PALETTE_1,
"donut slice 1 should use palette slot 1"
);
}
#[test]
fn pie_slice_colors_tokens_override_palette() {
let src = r##"zenith version=1 {
project id="proj.sc" name="SC"
tokens format="zenith-token-v1" {
token id="color.s0" type="color" value="#aa2233"
token id="color.s1" type="color" value="#115566"
}
styles {}
document id="doc.sc" title="SC" {
page id="page.sc" w=(px)400 h=(px)400 {
chart id="c.sc" kind="pie" x=(px)0 y=(px)0 w=(px)400 h=(px)400 {
slice-colors (token)"color.s0" (token)"color.s1"
series 50.0 50.0
}
}
}
}"##;
let doc = parse(src);
let result = compile_page(&doc, &default_provider(), 0, None);
let sc_diags: Vec<_> = result
.diagnostics
.iter()
.filter(|d| d.code.starts_with("chart.") || d.code.starts_with("token."))
.collect();
assert!(
sc_diags.is_empty(),
"no chart/token diagnostics expected; got: {sc_diags:?}"
);
let colors = fill_polygon_colors(&result);
assert_eq!(colors.len(), 2, "two slices → two FillPolygon commands");
assert_eq!(
colors[0],
Color::srgb(0xAA, 0x22, 0x33, 0xFF),
"slice 0 fill must be color.s0 (#aa2233), not palette"
);
assert_eq!(
colors[1],
Color::srgb(0x11, 0x55, 0x66, 0xFF),
"slice 1 fill must be color.s1 (#115566), not palette"
);
}
#[test]
fn donut_slice_colors_tokens_override_palette() {
let src = r##"zenith version=1 {
project id="proj.dsc" name="DSC"
tokens format="zenith-token-v1" {
token id="color.d0" type="color" value="#cc3344"
token id="color.d1" type="color" value="#225577"
}
styles {}
document id="doc.dsc" title="DSC" {
page id="page.dsc" w=(px)400 h=(px)400 {
chart id="c.dsc" kind="donut" x=(px)0 y=(px)0 w=(px)400 h=(px)400 {
slice-colors (token)"color.d0" (token)"color.d1"
series 60.0 40.0
}
}
}
}"##;
let doc = parse(src);
let result = compile_page(&doc, &default_provider(), 0, None);
let colors = fill_polygon_colors(&result);
assert_eq!(colors.len(), 2, "two slices → two FillPolygon commands");
assert_eq!(
colors[0],
Color::srgb(0xCC, 0x33, 0x44, 0xFF),
"donut slice 0 fill must be color.d0 (#cc3344)"
);
assert_eq!(
colors[1],
Color::srgb(0x22, 0x55, 0x77, 0xFF),
"donut slice 1 fill must be color.d1 (#225577)"
);
}
#[test]
fn pie_partial_slice_colors_falls_back_for_undeclared_slices() {
let src = r##"zenith version=1 {
project id="proj.psc" name="PSC"
tokens format="zenith-token-v1" {
token id="color.only" type="color" value="#ff8800"
}
styles {}
document id="doc.psc" title="PSC" {
page id="page.psc" w=(px)400 h=(px)400 {
chart id="c.psc" kind="pie" x=(px)0 y=(px)0 w=(px)400 h=(px)400 {
slice-colors (token)"color.only"
series 33.0 33.0 34.0
}
}
}
}"##;
let doc = parse(src);
let result = compile_page(&doc, &default_provider(), 0, None);
let colors = fill_polygon_colors(&result);
assert_eq!(colors.len(), 3, "three slices → three FillPolygon commands");
assert_eq!(
colors[0],
Color::srgb(0xFF, 0x88, 0x00, 0xFF),
"slice 0 must use the declared token color"
);
assert_eq!(
colors[1], PALETTE_1,
"slice 1 must fall back to palette slot 1"
);
assert_eq!(
colors[2],
Color::srgb(52, 168, 83, 255),
"slice 2 must fall back to palette slot 2 (green)"
);
}
#[test]
fn pie_legend_swatches_match_slice_colors() {
let src = r##"zenith version=1 {
project id="proj.ls" name="LS"
tokens format="zenith-token-v1" {
token id="color.ls0" type="color" value="#bb1122"
token id="color.ls1" type="color" value="#2233bb"
}
styles {}
document id="doc.ls" title="LS" {
page id="page.ls" w=(px)600 h=(px)400 {
chart id="c.ls" kind="pie" x=(px)0 y=(px)0 w=(px)600 h=(px)400 legend=#true {
slice-colors (token)"color.ls0" (token)"color.ls1"
series 50.0 50.0
}
}
}
}"##;
let doc = parse(src);
let result = compile_page(&doc, &default_provider(), 0, None);
let slice_colors = fill_polygon_colors(&result);
assert_eq!(
slice_colors.len(),
2,
"two slices → two FillPolygon commands"
);
assert_eq!(
slice_colors[0],
Color::srgb(0xBB, 0x11, 0x22, 0xFF),
"slice 0 fill must be color.ls0 (#bb1122)"
);
assert_eq!(
slice_colors[1],
Color::srgb(0x22, 0x33, 0xBB, 0xFF),
"slice 1 fill must be color.ls1 (#2233bb)"
);
let swatch_colors = fill_rect_colors(&result);
assert_eq!(
swatch_colors.len(),
2,
"two legend entries → two FillRect swatch commands"
);
assert_eq!(
swatch_colors[0],
Color::srgb(0xBB, 0x11, 0x22, 0xFF),
"legend swatch 0 must match slice 0 color (#bb1122), not the default palette"
);
assert_eq!(
swatch_colors[1],
Color::srgb(0x22, 0x33, 0xBB, 0xFF),
"legend swatch 1 must match slice 1 color (#2233bb), not the default palette"
);
}
#[test]
fn donut_legend_swatches_match_slice_colors() {
let src = r##"zenith version=1 {
project id="proj.dls" name="DLS"
tokens format="zenith-token-v1" {
token id="color.dls0" type="color" value="#44aa66"
token id="color.dls1" type="color" value="#aa4466"
}
styles {}
document id="doc.dls" title="DLS" {
page id="page.dls" w=(px)600 h=(px)400 {
chart id="c.dls" kind="donut" x=(px)0 y=(px)0 w=(px)600 h=(px)400 legend=#true {
slice-colors (token)"color.dls0" (token)"color.dls1"
series 60.0 40.0
}
}
}
}"##;
let doc = parse(src);
let result = compile_page(&doc, &default_provider(), 0, None);
let slice_colors = fill_polygon_colors(&result);
assert_eq!(
slice_colors.len(),
2,
"two slices → two FillPolygon commands"
);
assert_eq!(
slice_colors[0],
Color::srgb(0x44, 0xAA, 0x66, 0xFF),
"donut slice 0 color"
);
assert_eq!(
slice_colors[1],
Color::srgb(0xAA, 0x44, 0x66, 0xFF),
"donut slice 1 color"
);
let swatch_colors = fill_rect_colors(&result);
assert_eq!(
swatch_colors.len(),
2,
"two legend entries → two FillRect swatch commands"
);
assert_eq!(
swatch_colors[0],
Color::srgb(0x44, 0xAA, 0x66, 0xFF),
"donut legend swatch 0 must match slice 0 color (#44aa66), not the palette"
);
assert_eq!(
swatch_colors[1],
Color::srgb(0xAA, 0x44, 0x66, 0xFF),
"donut legend swatch 1 must match slice 1 color (#aa4466), not the palette"
);
}