use crate::{parser::Style, utils::CoreError, Result};
use alloc::{string::String, string::ToString};
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TextFormatting: u8 {
const BOLD = 1 << 0;
const ITALIC = 1 << 1;
const UNDERLINE = 1 << 2;
const STRIKE_OUT = 1 << 3;
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedStyle<'a> {
pub name: &'a str,
font_name: String,
font_size: f32,
primary_color: [u8; 4],
secondary_color: [u8; 4],
outline_color: [u8; 4],
back_color: [u8; 4],
formatting: TextFormatting,
scale_x: f32,
scale_y: f32,
spacing: f32,
angle: f32,
border_style: u8,
outline: f32,
shadow: f32,
alignment: u8,
margin_l: u16,
margin_r: u16,
margin_t: u16,
margin_b: u16,
encoding: u8,
complexity_score: u8,
}
impl<'a> ResolvedStyle<'a> {
pub fn from_style(style: &'a Style<'a>) -> Result<Self> {
let font_name = if style.fontname.is_empty() {
"Arial".to_string()
} else {
style.fontname.to_string()
};
let font_size = parse_font_size(style.fontsize)?;
let primary_color = parse_color_with_default(style.primary_colour)?;
let secondary_color = parse_color_with_default(style.secondary_colour)?;
let outline_color = parse_color_with_default(style.outline_colour)?;
let back_color = parse_color_with_default(style.back_colour)?;
let mut formatting = TextFormatting::empty();
if parse_bool_flag(style.bold)? {
formatting |= TextFormatting::BOLD;
}
if parse_bool_flag(style.italic)? {
formatting |= TextFormatting::ITALIC;
}
if parse_bool_flag(style.underline)? {
formatting |= TextFormatting::UNDERLINE;
}
if parse_bool_flag(style.strikeout)? {
formatting |= TextFormatting::STRIKE_OUT;
}
let scale_x = parse_percentage(style.scale_x)?;
let scale_y = parse_percentage(style.scale_y)?;
let spacing = parse_float(style.spacing)?;
let angle = parse_float(style.angle)?;
let border_style = parse_u8(style.border_style)?;
let outline = parse_float(style.outline)?;
let shadow = parse_float(style.shadow)?;
let alignment = parse_u8(style.alignment)?;
let margin_l = parse_u16(style.margin_l)?;
let margin_r = parse_u16(style.margin_r)?;
let (margin_t, margin_b) = if let (Some(t), Some(b)) = (style.margin_t, style.margin_b) {
(parse_u16(t)?, parse_u16(b)?)
} else {
let margin_v = parse_u16(style.margin_v)?;
(margin_v, margin_v)
};
let encoding = parse_u8(style.encoding)?;
let resolved = Self {
name: style.name,
font_name,
font_size,
primary_color,
secondary_color,
outline_color,
back_color,
formatting,
scale_x,
scale_y,
spacing,
angle,
border_style,
outline,
shadow,
alignment,
margin_l,
margin_r,
margin_t,
margin_b,
encoding,
complexity_score: 0, };
Ok(Self {
complexity_score: Self::calculate_complexity(&resolved),
..resolved
})
}
#[must_use]
pub fn font_name(&self) -> &str {
&self.font_name
}
#[must_use]
pub const fn font_size(&self) -> f32 {
self.font_size
}
#[must_use]
pub const fn primary_color(&self) -> [u8; 4] {
self.primary_color
}
#[must_use]
pub const fn complexity_score(&self) -> u8 {
self.complexity_score
}
#[must_use]
pub const fn has_performance_issues(&self) -> bool {
self.complexity_score > 70
}
#[must_use]
pub const fn formatting(&self) -> TextFormatting {
self.formatting
}
#[must_use]
pub const fn is_bold(&self) -> bool {
self.formatting.contains(TextFormatting::BOLD)
}
#[must_use]
pub const fn is_italic(&self) -> bool {
self.formatting.contains(TextFormatting::ITALIC)
}
#[must_use]
pub const fn is_underline(&self) -> bool {
self.formatting.contains(TextFormatting::UNDERLINE)
}
#[must_use]
pub const fn is_strike_out(&self) -> bool {
self.formatting.contains(TextFormatting::STRIKE_OUT)
}
#[must_use]
pub const fn margin_l(&self) -> u16 {
self.margin_l
}
#[must_use]
pub const fn margin_r(&self) -> u16 {
self.margin_r
}
#[must_use]
pub const fn margin_t(&self) -> u16 {
self.margin_t
}
#[must_use]
pub const fn margin_b(&self) -> u16 {
self.margin_b
}
#[must_use]
pub const fn outline(&self) -> f32 {
self.outline
}
#[must_use]
pub const fn shadow(&self) -> f32 {
self.shadow
}
#[must_use]
pub const fn secondary_color(&self) -> [u8; 4] {
self.secondary_color
}
#[must_use]
pub const fn outline_color(&self) -> [u8; 4] {
self.outline_color
}
#[must_use]
pub const fn spacing(&self) -> f32 {
self.spacing
}
#[must_use]
pub const fn angle(&self) -> f32 {
self.angle
}
#[allow(clippy::cognitive_complexity)]
pub fn from_style_with_parent(style: &'a Style<'a>, parent: &Self) -> Result<Self> {
let mut resolved = parent.clone();
resolved.name = style.name;
if !style.fontname.is_empty() {
resolved.font_name = style.fontname.to_string();
}
if !style.fontsize.is_empty() && style.fontsize != "0" {
resolved.font_size = parse_font_size(style.fontsize)?;
}
if !style.primary_colour.is_empty() {
resolved.primary_color = parse_color_with_default(style.primary_colour)?;
}
if !style.secondary_colour.is_empty() {
resolved.secondary_color = parse_color_with_default(style.secondary_colour)?;
}
if !style.outline_colour.is_empty() {
resolved.outline_color = parse_color_with_default(style.outline_colour)?;
}
if !style.back_colour.is_empty() {
resolved.back_color = parse_color_with_default(style.back_colour)?;
}
let mut formatting = resolved.formatting;
if !style.bold.is_empty() {
if style.bold == "0" {
formatting &= !TextFormatting::BOLD;
} else if style.bold == "1" {
formatting |= TextFormatting::BOLD;
}
}
if !style.italic.is_empty() {
if style.italic == "0" {
formatting &= !TextFormatting::ITALIC;
} else if style.italic == "1" {
formatting |= TextFormatting::ITALIC;
}
}
if !style.underline.is_empty() {
if style.underline == "0" {
formatting &= !TextFormatting::UNDERLINE;
} else if style.underline == "1" {
formatting |= TextFormatting::UNDERLINE;
}
}
if !style.strikeout.is_empty() {
if style.strikeout == "0" {
formatting &= !TextFormatting::STRIKE_OUT;
} else if style.strikeout == "1" {
formatting |= TextFormatting::STRIKE_OUT;
}
}
resolved.formatting = formatting;
if !style.scale_x.is_empty() && style.scale_x != "100" {
resolved.scale_x = parse_percentage(style.scale_x)?;
}
if !style.scale_y.is_empty() && style.scale_y != "100" {
resolved.scale_y = parse_percentage(style.scale_y)?;
}
if !style.spacing.is_empty() && style.spacing != "0" {
resolved.spacing = parse_float(style.spacing)?;
}
if !style.angle.is_empty() && style.angle != "0" {
resolved.angle = parse_float(style.angle)?;
}
if !style.border_style.is_empty() {
resolved.border_style = parse_u8(style.border_style)?;
}
if !style.outline.is_empty() && style.outline != "0" {
resolved.outline = parse_float(style.outline)?;
}
if !style.shadow.is_empty() && style.shadow != "0" {
resolved.shadow = parse_float(style.shadow)?;
}
if !style.alignment.is_empty() {
resolved.alignment = parse_u8(style.alignment)?;
}
if !style.margin_l.is_empty() {
resolved.margin_l = parse_u16(style.margin_l)?;
}
if !style.margin_r.is_empty() {
resolved.margin_r = parse_u16(style.margin_r)?;
}
if let (Some(t), Some(b)) = (style.margin_t, style.margin_b) {
if !t.is_empty() {
resolved.margin_t = parse_u16(t)?;
}
if !b.is_empty() {
resolved.margin_b = parse_u16(b)?;
}
} else if !style.margin_v.is_empty() && style.margin_v != "0" {
let margin_v = parse_u16(style.margin_v)?;
resolved.margin_t = margin_v;
resolved.margin_b = margin_v;
}
if !style.encoding.is_empty() {
resolved.encoding = parse_u8(style.encoding)?;
}
resolved.complexity_score = Self::calculate_complexity(&resolved);
Ok(resolved)
}
pub fn apply_resolution_scaling(&mut self, scale_x: f32, scale_y: f32) {
let avg_scale = (scale_x + scale_y) / 2.0;
self.font_size *= avg_scale;
self.spacing *= scale_x;
self.outline *= avg_scale;
self.shadow *= avg_scale;
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
{
self.margin_l = (f32::from(self.margin_l) * scale_x) as u16;
self.margin_r = (f32::from(self.margin_r) * scale_x) as u16;
self.margin_t = (f32::from(self.margin_t) * scale_y) as u16;
self.margin_b = (f32::from(self.margin_b) * scale_y) as u16;
}
self.complexity_score = Self::calculate_complexity(self);
}
fn calculate_complexity(style: &Self) -> u8 {
const EPSILON: f32 = 0.001;
let mut score = 0u8;
if style.font_size > 72.0 {
score += 20;
} else if style.font_size > 48.0 {
score += 10;
}
if style.outline > 4.0 {
score += 15;
} else if style.outline > 2.0 {
score += 8;
}
if style.shadow > 3.0 {
score += 10;
} else if style.shadow > 1.0 {
score += 5;
}
if (style.scale_x - 100.0).abs() > EPSILON || (style.scale_y - 100.0).abs() > EPSILON {
score += 10;
}
if style.angle.abs() > EPSILON {
score += 15;
}
if style.formatting.contains(TextFormatting::BOLD) {
score += 2;
}
if style.formatting.contains(TextFormatting::ITALIC) {
score += 2;
}
if style
.formatting
.intersects(TextFormatting::UNDERLINE | TextFormatting::STRIKE_OUT)
{
score += 5;
}
score.min(100)
}
}
fn parse_font_size(size_str: &str) -> Result<f32> {
let size = parse_float(size_str)?;
if size <= 0.0 || size > 1000.0 {
Err(CoreError::parse("Invalid font size"))
} else {
Ok(size)
}
}
fn parse_color_with_default(color_str: &str) -> Result<[u8; 4]> {
if color_str.trim().is_empty() {
Ok([255, 255, 255, 255]) } else {
crate::utils::parse_bgr_color(color_str)
}
}
fn parse_bool_flag(flag_str: &str) -> Result<bool> {
match flag_str {
"0" => Ok(false),
"1" => Ok(true),
_ => Err(CoreError::parse("Invalid boolean flag")),
}
}
fn parse_percentage(percent_str: &str) -> Result<f32> {
let value = parse_float(percent_str)?;
if (0.0..=1000.0).contains(&value) {
Ok(value)
} else {
Err(CoreError::parse("Invalid percentage"))
}
}
fn parse_float(float_str: &str) -> Result<f32> {
float_str
.parse::<f32>()
.map_err(|_| CoreError::parse("Invalid float value"))
}
fn parse_u8(u8_str: &str) -> Result<u8> {
u8_str
.parse::<u8>()
.map_err(|_| CoreError::parse("Invalid u8 value"))
}
fn parse_u16(u16_str: &str) -> Result<u16> {
u16_str
.parse::<u16>()
.map_err(|_| CoreError::parse("Invalid u16 value"))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parser::ast::Span;
#[cfg(not(feature = "std"))]
fn create_test_style() -> Style<'static> {
Style {
name: "Test",
parent: None,
fontname: "Arial",
fontsize: "20",
primary_colour: "&H00FFFFFF",
secondary_colour: "&H000000FF",
outline_colour: "&H00000000",
back_colour: "&H00000000",
bold: "0",
italic: "0",
underline: "0",
strikeout: "0",
scale_x: "100",
scale_y: "100",
spacing: "0",
angle: "0",
border_style: "1",
outline: "2",
shadow: "0",
alignment: "2",
margin_l: "10",
margin_r: "10",
margin_v: "10",
margin_t: None,
margin_b: None,
encoding: "1",
relative_to: None,
span: Span::new(0, 0, 0, 0),
}
}
#[cfg(feature = "std")]
fn create_test_style() -> Style<'static> {
Style {
name: "Test",
parent: None,
fontname: "Arial",
fontsize: "20",
primary_colour: "&H00FFFFFF",
secondary_colour: "&H000000FF",
outline_colour: "&H00000000",
back_colour: "&H00000000",
bold: "0",
italic: "0",
underline: "0",
strikeout: "0",
scale_x: "100",
scale_y: "100",
spacing: "0",
angle: "0",
border_style: "1",
outline: "2",
shadow: "0",
alignment: "2",
margin_l: "10",
margin_r: "10",
margin_v: "10",
margin_t: None,
margin_b: None,
encoding: "1",
relative_to: None,
span: Span::new(0, 0, 0, 0),
}
}
#[test]
fn resolved_style_creation() {
let style = create_test_style();
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert_eq!(resolved.name, "Test");
assert_eq!(resolved.font_name(), "Arial");
assert!((resolved.font_size() - 20.0).abs() < f32::EPSILON);
assert_eq!(resolved.primary_color(), [255, 255, 255, 0]);
}
#[test]
fn color_parsing() {
assert_eq!(
crate::utils::parse_bgr_color("&H000000FF").unwrap(),
[255, 0, 0, 0]
); assert_eq!(
crate::utils::parse_bgr_color("&H0000FF00").unwrap(),
[0, 255, 0, 0]
); assert_eq!(
crate::utils::parse_bgr_color("&H00FF0000").unwrap(),
[0, 0, 255, 0]
);
assert_eq!(
crate::utils::parse_bgr_color("&h000000FF").unwrap(),
[255, 0, 0, 0]
);
assert_eq!(
crate::utils::parse_bgr_color("&HFF0000").unwrap(),
[0, 0, 255, 0]
); assert_eq!(
crate::utils::parse_bgr_color("&H00FF00").unwrap(),
[0, 255, 0, 0]
); assert_eq!(
crate::utils::parse_bgr_color("&H0000FF").unwrap(),
[255, 0, 0, 0]
); }
#[test]
fn complexity_scoring() {
let mut style = create_test_style();
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.complexity_score() < 50);
style.fontsize = "100";
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.complexity_score() >= 20);
}
#[test]
fn performance_issues_detection() {
let mut style = create_test_style();
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(!resolved.has_performance_issues());
style.fontsize = "120"; style.outline = "8"; style.shadow = "5"; style.angle = "45"; style.scale_x = "150"; style.bold = "1"; style.italic = "1"; style.underline = "1";
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.has_performance_issues());
}
#[test]
fn parse_font_size_edge_cases() {
assert!(parse_font_size("-10").is_err()); assert!(parse_font_size("0").is_err()); assert!(parse_font_size("1001").is_err()); assert!(parse_font_size("abc").is_err()); assert!(parse_font_size("").is_err());
assert!(parse_font_size("1").is_ok());
assert!(parse_font_size("72").is_ok());
assert!(parse_font_size("1000").is_ok());
}
#[test]
fn parse_color_with_default_invalid_formats() {
assert!(parse_color_with_default("invalid").is_err());
assert!(parse_color_with_default("&H").is_err());
assert!(parse_color_with_default("&HZZZZZ").is_err());
assert!(parse_color_with_default("12345G").is_err());
let default_color = parse_color_with_default("").unwrap();
assert_eq!(default_color, [255, 255, 255, 255]);
let whitespace_color = parse_color_with_default(" ").unwrap();
assert_eq!(whitespace_color, [255, 255, 255, 255]);
}
#[test]
fn parse_bool_flag_invalid_values() {
assert!(parse_bool_flag("2").is_err());
assert!(parse_bool_flag("-1").is_err());
assert!(parse_bool_flag("true").is_err());
assert!(parse_bool_flag("false").is_err());
assert!(parse_bool_flag("yes").is_err());
assert!(parse_bool_flag("no").is_err());
assert!(parse_bool_flag("").is_err());
assert!(!parse_bool_flag("0").unwrap());
assert!(parse_bool_flag("1").unwrap());
}
#[test]
#[allow(clippy::float_cmp)]
fn parse_percentage_invalid_values() {
assert!(parse_percentage("-10").is_err()); assert!(parse_percentage("1001").is_err()); assert!(parse_percentage("abc").is_err()); assert!(parse_percentage("").is_err());
assert_eq!(parse_percentage("0").unwrap(), 0.0);
assert_eq!(parse_percentage("100").unwrap(), 100.0);
assert_eq!(parse_percentage("1000").unwrap(), 1000.0);
}
#[test]
#[allow(clippy::float_cmp)]
fn parse_float_invalid_values() {
assert!(parse_float("abc").is_err());
assert!(parse_float("").is_err());
assert!(parse_float("1.2.3").is_err());
assert!(parse_float("1.2.3.4").is_err());
assert!(parse_float("not_a_number").is_err());
assert_eq!(parse_float("0").unwrap(), 0.0);
assert_eq!(parse_float("-10.5").unwrap(), -10.5);
assert_eq!(parse_float("123.456").unwrap(), 123.456);
}
#[test]
fn parse_u8_invalid_values() {
assert!(parse_u8("256").is_err()); assert!(parse_u8("-1").is_err()); assert!(parse_u8("abc").is_err()); assert!(parse_u8("").is_err());
assert_eq!(parse_u8("0").unwrap(), 0);
assert_eq!(parse_u8("255").unwrap(), 255);
}
#[test]
fn parse_u16_invalid_values() {
assert!(parse_u16("65536").is_err()); assert!(parse_u16("-1").is_err()); assert!(parse_u16("abc").is_err()); assert!(parse_u16("").is_err());
assert_eq!(parse_u16("0").unwrap(), 0);
assert_eq!(parse_u16("65535").unwrap(), 65535);
}
#[test]
fn resolved_style_from_style_with_invalid_values() {
let mut style = create_test_style();
style.fontsize = "-10";
assert!(ResolvedStyle::from_style(&style).is_err());
style.fontsize = "abc";
assert!(ResolvedStyle::from_style(&style).is_err());
style.fontsize = "20"; style.primary_colour = "invalid_color";
assert!(ResolvedStyle::from_style(&style).is_err());
style.primary_colour = "&HFFFFFF"; style.bold = "2";
assert!(ResolvedStyle::from_style(&style).is_err());
}
#[test]
fn complexity_calculation_all_branches() {
let mut style = create_test_style();
let resolved = ResolvedStyle::from_style(&style).unwrap();
let baseline_score = resolved.complexity_score();
style.fontsize = "100"; let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.complexity_score() > baseline_score);
style = create_test_style(); style.outline = "5"; let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.complexity_score() > baseline_score);
style = create_test_style(); style.shadow = "5"; let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.complexity_score() > baseline_score);
style = create_test_style(); style.scale_x = "200"; let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.complexity_score() > baseline_score);
style = create_test_style(); style.angle = "45"; let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.complexity_score() > baseline_score);
style = create_test_style(); style.bold = "1";
style.italic = "1";
style.underline = "1";
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.complexity_score() > baseline_score);
}
#[test]
fn complexity_score_capped_at_100() {
let mut style = create_test_style();
style.fontsize = "200"; style.outline = "10"; style.shadow = "10"; style.scale_x = "200"; style.angle = "180"; style.bold = "1";
style.italic = "1";
style.underline = "1";
style.strikeout = "1";
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.complexity_score() <= 100); assert!(resolved.complexity_score() > 50); }
#[test]
fn text_formatting_flags_comprehensive() {
let mut style = create_test_style();
style.bold = "1";
style.italic = "0";
style.underline = "0";
style.strikeout = "0";
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.is_bold());
assert!(!resolved.is_italic());
assert!(!resolved.is_underline());
assert!(!resolved.is_strike_out());
assert_eq!(resolved.formatting(), TextFormatting::BOLD);
style.bold = "0";
style.italic = "1";
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(!resolved.is_bold());
assert!(resolved.is_italic());
assert_eq!(resolved.formatting(), TextFormatting::ITALIC);
style.italic = "0";
style.underline = "1";
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.is_underline());
assert_eq!(resolved.formatting(), TextFormatting::UNDERLINE);
style.underline = "0";
style.strikeout = "1";
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.is_strike_out());
assert_eq!(resolved.formatting(), TextFormatting::STRIKE_OUT);
style.bold = "1";
style.italic = "1";
style.underline = "1";
style.strikeout = "1";
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!(resolved.is_bold());
assert!(resolved.is_italic());
assert!(resolved.is_underline());
assert!(resolved.is_strike_out());
let expected = TextFormatting::BOLD
| TextFormatting::ITALIC
| TextFormatting::UNDERLINE
| TextFormatting::STRIKE_OUT;
assert_eq!(resolved.formatting(), expected);
}
#[test]
fn resolved_style_empty_font_name_uses_default() {
let mut style = create_test_style();
style.fontname = "";
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert_eq!(resolved.font_name(), "Arial");
}
#[test]
#[allow(clippy::float_cmp)]
fn resolved_style_getters_comprehensive() {
let style = create_test_style();
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert_eq!(resolved.font_name(), "Arial");
assert_eq!(resolved.font_size(), 20.0);
assert_eq!(resolved.primary_color(), [255, 255, 255, 0]); assert!(!resolved.has_performance_issues());
let formatting = resolved.formatting();
assert!(!resolved.is_bold());
assert!(!resolved.is_italic());
assert!(!resolved.is_underline());
assert!(!resolved.is_strike_out());
assert_eq!(formatting, TextFormatting::empty());
}
#[test]
fn resolved_style_apply_resolution_scaling_symmetric() {
let style = create_test_style();
let mut resolved = ResolvedStyle::from_style(&style).unwrap();
resolved.apply_resolution_scaling(2.0, 2.0);
assert!((resolved.font_size() - 40.0).abs() < f32::EPSILON); assert!((resolved.spacing() - 0.0).abs() < f32::EPSILON); assert!((resolved.outline() - 4.0).abs() < f32::EPSILON); assert!((resolved.shadow() - 0.0).abs() < f32::EPSILON); assert_eq!(resolved.margin_l(), 20); assert_eq!(resolved.margin_r(), 20); assert_eq!(resolved.margin_t(), 20); assert_eq!(resolved.margin_b(), 20); }
#[test]
fn resolved_style_apply_resolution_scaling_asymmetric() {
let mut style = create_test_style();
style.spacing = "4";
style.shadow = "2";
style.margin_l = "10";
style.margin_r = "20";
style.margin_v = "30";
let mut resolved = ResolvedStyle::from_style(&style).unwrap();
resolved.apply_resolution_scaling(3.0, 2.0);
assert!((resolved.font_size() - 50.0).abs() < f32::EPSILON); assert!((resolved.spacing() - 12.0).abs() < f32::EPSILON); assert!((resolved.outline() - 5.0).abs() < f32::EPSILON); assert!((resolved.shadow() - 5.0).abs() < f32::EPSILON); assert_eq!(resolved.margin_l(), 30); assert_eq!(resolved.margin_r(), 60); assert_eq!(resolved.margin_t(), 60); assert_eq!(resolved.margin_b(), 60); }
#[test]
fn resolved_style_apply_resolution_scaling_downscale() {
let style = create_test_style();
let mut resolved = ResolvedStyle::from_style(&style).unwrap();
resolved.apply_resolution_scaling(0.5, 0.5);
assert!((resolved.font_size() - 10.0).abs() < f32::EPSILON); assert!((resolved.spacing() - 0.0).abs() < f32::EPSILON); assert!((resolved.outline() - 1.0).abs() < f32::EPSILON); assert!((resolved.shadow() - 0.0).abs() < f32::EPSILON); assert_eq!(resolved.margin_l(), 5); assert_eq!(resolved.margin_r(), 5); assert_eq!(resolved.margin_t(), 5); assert_eq!(resolved.margin_b(), 5); }
#[test]
fn resolved_style_apply_resolution_scaling_updates_complexity() {
let mut style = create_test_style();
style.fontsize = "30";
let mut resolved = ResolvedStyle::from_style(&style).unwrap();
let initial_complexity = resolved.complexity_score();
resolved.apply_resolution_scaling(3.0, 3.0);
assert!((resolved.font_size() - 90.0).abs() < f32::EPSILON); assert!(resolved.complexity_score() > initial_complexity); }
#[test]
fn resolved_style_apply_resolution_scaling_preserves_other_properties() {
let mut style = create_test_style();
style.bold = "1";
style.italic = "1";
style.primary_colour = "&H00FF0000"; style.angle = "45";
let mut resolved = ResolvedStyle::from_style(&style).unwrap();
let initial_color = resolved.primary_color();
let initial_angle = resolved.angle;
let initial_formatting = resolved.formatting();
resolved.apply_resolution_scaling(2.0, 2.0);
assert_eq!(resolved.primary_color(), initial_color);
assert!((resolved.angle - initial_angle).abs() < f32::EPSILON);
assert_eq!(resolved.formatting(), initial_formatting);
assert!(resolved.is_bold());
assert!(resolved.is_italic());
}
#[test]
fn resolved_style_spacing_getter() {
let mut style = create_test_style();
style.spacing = "5.5";
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!((resolved.spacing() - 5.5).abs() < f32::EPSILON);
}
#[test]
fn resolved_style_angle_getter() {
let mut style = create_test_style();
style.angle = "45.5";
let resolved = ResolvedStyle::from_style(&style).unwrap();
assert!((resolved.angle() - 45.5).abs() < f32::EPSILON);
}
}