use std::fs;
use std::path::PathBuf;
use fonts::parse_ui::*;
fn font_path(rel: &str) -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../fixtures/fonts")
.join(rel)
}
#[test]
fn test_ui_parser_single_static_font() {
let path = font_path("Molle/Molle-Italic.ttf");
if !path.exists() {
println!("Molle font not found, skipping test");
return;
}
let parser = UIFontParser::new();
let font_data = fs::read(&path).unwrap();
let font_faces = vec![UIFontFace {
face_id: "Molle-Italic.ttf".to_string(),
data: &font_data,
user_font_style_italic: None, }];
let result = parser
.analyze_family(Some("Molle".to_string()), font_faces)
.unwrap();
assert_eq!(result.family_name, "Molle");
assert_eq!(result.face_info.len(), 1);
assert!(result.italic_capability.has_italic);
assert!(!result.italic_capability.has_upright);
assert_eq!(
result.italic_capability.strategy,
UIFontItalicStrategy::StaticItalicOnly
);
assert_eq!(result.italic_capability.recipes.len(), 1);
let recipe = &result.italic_capability.recipes[0];
assert_eq!(recipe.name, "Italic");
assert!(recipe.is_italic);
assert!(recipe.description.contains("Italic"));
let face = &result.face_info[0];
assert_eq!(face.family_name, "Molle");
assert!(!face.is_variable);
}
#[test]
fn test_ui_parser_multi_static_fonts() {
let paths = vec![
font_path("PT_Serif/PTSerif-Regular.ttf"),
font_path("PT_Serif/PTSerif-Italic.ttf"),
font_path("PT_Serif/PTSerif-Bold.ttf"),
font_path("PT_Serif/PTSerif-BoldItalic.ttf"),
];
let existing_paths: Vec<_> = paths.iter().filter(|p| p.exists()).collect();
if existing_paths.len() < 2 {
println!("PT Serif fonts not found, skipping test");
return;
}
let parser = UIFontParser::new();
let font_data: Vec<_> = existing_paths
.iter()
.map(|p| fs::read(*p).unwrap())
.collect();
let font_faces: Vec<UIFontFace> = existing_paths
.iter()
.enumerate()
.map(|(i, _p)| UIFontFace {
face_id: format!("PT-Serif-{}", i),
data: &font_data[i],
user_font_style_italic: None, })
.collect();
let result = parser
.analyze_family(Some("PT Serif".to_string()), font_faces)
.unwrap();
assert_eq!(result.family_name, "PT Serif");
assert_eq!(result.face_info.len(), existing_paths.len());
assert!(result.italic_capability.has_italic);
assert!(result.italic_capability.has_upright);
assert_eq!(
result.italic_capability.strategy,
UIFontItalicStrategy::StaticFamily
);
assert!(result.italic_capability.recipes.len() >= 2);
let regular_recipe = result
.italic_capability
.recipes
.iter()
.find(|r| r.name == "Regular")
.expect("Should have Regular recipe");
assert!(!regular_recipe.is_italic);
let italic_recipe = result
.italic_capability
.recipes
.iter()
.find(|r| r.is_italic)
.expect("Should have italic recipe");
assert!(italic_recipe.is_italic);
}
#[test]
fn test_ui_parser_variable_font() {
let paths = vec![
font_path("Inter/Inter-VariableFont_opsz,wght.ttf"),
font_path("Inter/Inter-Italic-VariableFont_opsz,wght.ttf"),
];
let existing_paths: Vec<_> = paths.iter().filter(|p| p.exists()).collect();
if existing_paths.is_empty() {
println!("Inter fonts not found, skipping test");
return;
}
let parser = UIFontParser::new();
let font_data: Vec<_> = existing_paths
.iter()
.map(|p| fs::read(*p).unwrap())
.collect();
let font_faces: Vec<UIFontFace> = existing_paths
.iter()
.enumerate()
.map(|(i, _p)| UIFontFace {
face_id: format!("Inter-{}", i),
data: &font_data[i],
user_font_style_italic: None, })
.collect();
let result = parser
.analyze_family(Some("Inter".to_string()), font_faces)
.unwrap();
assert_eq!(result.family_name, "Inter");
assert_eq!(result.face_info.len(), existing_paths.len());
assert!(result.variable_font_info.is_some());
let vf_info = result.variable_font_info.unwrap();
assert!(!vf_info.axes.is_empty());
let weight_axis = vf_info
.axes
.iter()
.find(|a| a.tag == "wght")
.expect("Should have weight axis");
assert_eq!(weight_axis.name, "Weight");
assert!(weight_axis.min < weight_axis.max);
if existing_paths.len() > 1 {
assert_eq!(
result.italic_capability.strategy,
UIFontItalicStrategy::DualVariableFonts
);
} else {
assert_eq!(
result.italic_capability.strategy,
UIFontItalicStrategy::VariableFont
);
}
}
#[test]
fn test_ui_parser_slnt_axis_font() {
let path = font_path("Recursive/Recursive-VariableFont_CASL,CRSV,MONO,slnt,wght.ttf");
if !path.exists() {
println!("Recursive font not found, skipping test");
return;
}
let parser = UIFontParser::new();
let font_data = fs::read(&path).unwrap();
let font_faces = vec![UIFontFace {
face_id: "Recursive-Variable.ttf".to_string(),
data: &font_data,
user_font_style_italic: None, }];
let result = parser
.analyze_family(Some("Recursive".to_string()), font_faces)
.unwrap();
assert_eq!(result.family_name, "Recursive");
assert_eq!(result.face_info.len(), 1);
assert!(result.variable_font_info.is_some());
let vf_info = result.variable_font_info.unwrap();
let slnt_axis = vf_info
.axes
.iter()
.find(|a| a.tag == "slnt")
.expect("Should have slnt axis");
assert_eq!(slnt_axis.name, "Slant");
assert!(slnt_axis.min < slnt_axis.max);
assert_eq!(
result.italic_capability.strategy,
UIFontItalicStrategy::VariableFont
);
assert!(result.italic_capability.has_italic);
}
#[test]
fn test_ui_parser_error_handling() {
let parser = UIFontParser::new();
let result = parser.analyze_family(None, vec![]);
assert!(result.is_err());
assert!(result.unwrap_err().contains("empty"));
let result = parser.analyze_family(
None,
vec![UIFontFace {
face_id: "invalid.ttf".to_string(),
data: &[0, 1, 2, 3],
user_font_style_italic: None,
}],
);
assert!(result.is_err());
}
#[test]
fn test_recipe_generation_through_analysis() {
let path = font_path("Molle/Molle-Italic.ttf");
if !path.exists() {
println!("Molle font not found, skipping test");
return;
}
let parser = UIFontParser::new();
let font_data = fs::read(&path).unwrap();
let font_faces = vec![UIFontFace {
face_id: "Molle-Italic.ttf".to_string(),
data: &font_data,
user_font_style_italic: None, }];
let result = parser
.analyze_family(Some("Molle".to_string()), font_faces)
.unwrap();
assert_eq!(result.italic_capability.recipes.len(), 1);
let recipe = &result.italic_capability.recipes[0];
assert_eq!(recipe.name, "Italic");
assert!(recipe.is_italic);
assert!(recipe.description.contains("Italic"));
assert!(!recipe.face_id.is_empty());
}
#[test]
fn test_face_info_analysis() {
let path = font_path("Molle/Molle-Italic.ttf");
if !path.exists() {
println!("Molle font not found, skipping test");
return;
}
let parser = UIFontParser::new();
let font_data = fs::read(&path).unwrap();
let font_faces = vec![UIFontFace {
face_id: "Molle-Italic.ttf".to_string(),
data: &font_data,
user_font_style_italic: None, }];
let result = parser.analyze_family(None, font_faces).unwrap();
assert_eq!(result.face_info.len(), 1);
let face = &result.face_info[0];
assert!(!face.face_id.is_empty());
assert!(!face.family_name.is_empty());
assert!(!face.subfamily_name.is_empty());
assert!(!face.postscript_name.is_empty());
assert!(!face.is_variable);
assert!(face.features.is_empty() || !face.features.is_empty());
}
#[test]
fn test_variable_font_info_analysis() {
let path = font_path("Inter/Inter-VariableFont_opsz,wght.ttf");
if !path.exists() {
println!("Inter font not found, skipping test");
return;
}
let parser = UIFontParser::new();
let font_data = fs::read(&path).unwrap();
let font_faces = vec![UIFontFace {
face_id: "Inter-Variable.ttf".to_string(),
data: &font_data,
user_font_style_italic: None, }];
let result = parser.analyze_family(None, font_faces).unwrap();
assert!(result.variable_font_info.is_some());
let vf_info = result.variable_font_info.unwrap();
assert!(!vf_info.axes.is_empty());
for axis in &vf_info.axes {
assert!(!axis.tag.is_empty());
assert!(!axis.name.is_empty());
assert!(axis.min <= axis.default);
assert!(axis.default <= axis.max);
}
assert!(!vf_info.instances.is_empty());
for instance in &vf_info.instances {
assert!(!instance.name.is_empty());
assert!(!instance.coordinates.is_empty());
}
}