use oxideav_ttf::{Font, GlyphNameRef, PostFormat, POST_VERSION_20};
const DEJAVU_SANS: &[u8] = include_bytes!("fixtures/DejaVuSans.ttf");
const DEJAVU_MONO: &[u8] = include_bytes!("fixtures/DejaVuSansMono.ttf");
#[test]
fn dejavu_sans_publishes_post_v2_with_custom_names() {
let font = Font::from_bytes(DEJAVU_SANS).unwrap();
assert!(font.has_post(), "DejaVu Sans is expected to ship `post`");
let post = font.post_table().expect("post table present");
assert_eq!(post.version_raw, POST_VERSION_20);
match &post.format {
PostFormat::Version20(v) => {
assert_eq!(v.num_glyphs, font.glyph_count());
assert_eq!(v.glyph_name_indices.len(), font.glyph_count() as usize);
assert!(
!v.pascal_strings.is_empty(),
"v2.0 font is expected to ship at least one Pascal string"
);
assert!(!v.has_oversize_glyph_name);
assert!(!v.has_non_conformant_glyph_name);
}
other => panic!("expected post v2.0 in DejaVu Sans, got {other:?}"),
}
}
#[test]
fn dejavu_sans_resolves_at_least_one_custom_glyph_name() {
let font = Font::from_bytes(DEJAVU_SANS).unwrap();
let mut custom_count = 0usize;
let mut std_count = 0usize;
for gid in 0..font.glyph_count() {
match font.glyph_name_ref(gid) {
Some(GlyphNameRef::Custom(_)) => custom_count += 1,
Some(GlyphNameRef::StandardMac { .. }) => std_count += 1,
None => {}
}
}
assert!(
custom_count > 0,
"DejaVu Sans is expected to carry at least one Pascal glyph name"
);
let convenience_count: usize = (0..font.glyph_count())
.filter(|gid| font.glyph_name(*gid).is_some())
.count();
assert_eq!(convenience_count, custom_count + std_count);
for gid in 0..font.glyph_count() {
if let Some(GlyphNameRef::StandardMac { index }) = font.glyph_name_ref(gid) {
let name = font
.glyph_name(gid)
.expect("StandardMac glyph name must resolve");
assert_eq!(name, oxideav_ttf::standard_mac_glyph_name(index).unwrap());
}
}
}
#[test]
fn dejavu_sans_post_metrics_are_sane() {
let font = Font::from_bytes(DEJAVU_SANS).unwrap();
let post = font.post_table().unwrap();
assert!((post.italic_angle).abs() < 0.5);
assert!(!post.is_fixed_pitch);
assert!(post.underline_thickness > 0);
}
#[test]
fn dejavu_mono_post_publishes_glyph_names() {
let font = Font::from_bytes(DEJAVU_MONO).unwrap();
let post = font.post_table().unwrap();
assert!(post.has_glyph_names());
assert!(post.is_fixed_pitch);
}
#[test]
fn glyph_name_for_out_of_range_gid_is_none() {
let font = Font::from_bytes(DEJAVU_SANS).unwrap();
let max = u16::MAX;
assert!(font.glyph_name_ref(max).is_none());
assert!(font.glyph_name(max).is_none());
}
#[test]
fn dejavu_sans_reverse_lookup_round_trips_every_named_glyph() {
let font = Font::from_bytes(DEJAVU_SANS).unwrap();
let mut named = 0usize;
for (gid, name) in font.iter_glyph_names() {
named += 1;
let back = font
.gid_for_glyph_name(name)
.expect("a named glyph must reverse-resolve");
assert!(
back <= gid,
"reverse lookup must not exceed the forward gid"
);
assert_eq!(
font.glyph_name(back),
Some(name),
"the reverse-resolved gid must carry the same name"
);
}
assert!(named > 0, "DejaVu Sans publishes glyph names");
let direct: usize = (0..font.glyph_count())
.filter(|g| font.glyph_name(*g).is_some())
.count();
assert_eq!(named, direct);
}
#[test]
fn dejavu_sans_reverse_lookup_resolves_known_names() {
let font = Font::from_bytes(DEJAVU_SANS).unwrap();
let via_cmap = font.glyph_index('A').expect("cmap maps 'A'");
let via_name = font
.gid_for_glyph_name("A")
.expect("post names a glyph 'A'");
assert_eq!(via_cmap, via_name);
assert!(font
.gid_for_glyph_name("this_is_not_a_real_glyph_name")
.is_none());
}
#[test]
fn reverse_lookup_on_fontless_post_is_none() {
let font = Font::from_bytes(DEJAVU_SANS).unwrap();
assert!(font.gid_for_glyph_name("").is_none());
}