use image::ImageFormat;
use std::path::Path;
struct Entry {
size: u32,
offset: usize,
length: usize,
}
fn entries(ico: &[u8]) -> Vec<Entry> {
let count = u16::from_le_bytes([ico[4], ico[5]]) as usize;
(0..count)
.map(|index| {
let at = 6 + index * 16;
let entry = &ico[at..at + 16];
let size = if entry[0] == 0 { 256 } else { entry[0] as u32 };
let length = u32::from_le_bytes([entry[8], entry[9], entry[10], entry[11]]) as usize;
let offset = u32::from_le_bytes([entry[12], entry[13], entry[14], entry[15]]) as usize;
assert!(ico.len() >= offset + length, "the {size}px image runs past the file");
Entry { size, offset, length }
})
.collect()
}
fn asset(name: &str) -> Vec<u8> {
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("assets").join(name);
std::fs::read(&path).unwrap_or_else(|e| panic!("{}: {e}", path.display()))
}
fn is_filled_tile(png: &[u8], what: &str) -> bool {
let decoded = image::load_from_memory_with_format(png, ImageFormat::Png).unwrap_or_else(|e| panic!("{what} is not a PNG: {e}"));
let rgba = decoded.to_rgba8();
let (visible, bright) = rgba.pixels().fold((0u32, 0u32), |(visible, bright), pixel| {
let [r, g, b, a] = pixel.0;
if a <= 40 {
return (visible, bright);
}
let brightness = u32::from(r) + u32::from(g) + u32::from(b);
(visible + 1, bright + u32::from(brightness > 180))
});
assert!(visible > 0, "{what} is fully transparent");
bright * 2 > visible
}
#[test]
fn every_size_carries_the_level_that_reads_at_it() {
let ico = asset("icon.ico");
let entries = entries(&ico);
assert!(!entries.is_empty(), "icon.ico holds no images");
for entry in &entries {
let payload = &ico[entry.offset..entry.offset + entry.length];
let what = format!("the {}px image", entry.size);
let decoded = image::load_from_memory_with_format(payload, ImageFormat::Png).unwrap_or_else(|e| panic!("{what} is not a PNG: {e}"));
assert_eq!(decoded.width(), entry.size, "{what} holds a {}px picture", decoded.width());
let filled = is_filled_tile(payload, &what);
if entry.size <= 27 {
assert!(filled, "{what} is not the filled S tile; below 28px the outline collapses into noise");
} else {
assert!(
!filled,
"{what} is the filled S tile, not the plated mark - the level rule puts S at 27px and below"
);
}
}
}
#[test]
fn the_largest_image_comes_first() {
let ico = asset("icon.ico");
let sizes: Vec<u32> = entries(&ico).iter().map(|entry| entry.size).collect();
let mut sorted = sizes.clone();
sorted.sort_unstable_by(|a, b| b.cmp(a));
assert_eq!(sizes, sorted, "the images are not ordered largest first");
}
#[test]
fn the_touch_icon_carries_the_plated_mark() {
let png = asset("apple-touch-icon.png");
assert!(
!is_filled_tile(&png, "apple-touch-icon.png"),
"apple-touch-icon.png is the filled S tile; at 180px the mark reads"
);
let docs_copy = Path::new(env!("CARGO_MANIFEST_DIR")).join("docs/public/apple-touch-icon.png");
assert_eq!(
std::fs::read(docs_copy).expect("docs/public/apple-touch-icon.png"),
png,
"the docs site serves a different touch icon"
);
}
#[test]
fn the_favicon_stays_the_filled_tile() {
let png = asset("favicon-32.png");
assert!(
is_filled_tile(&png, "favicon-32.png"),
"favicon-32.png lost the filled tile; it is drawn at 16px in a tab"
);
}