use pagetop::prelude::*; use std::str::FromStr; #[pagetop::test] async fn unit_value_empty_and_auto_and_zero_without_unit() { assert_eq!(UnitValue::from_str("").unwrap(), UnitValue::None); assert_eq!(UnitValue::from_str("auto").unwrap(), UnitValue::Auto); assert_eq!(UnitValue::from_str("AUTO").unwrap(), UnitValue::Auto); // Cero sin unidad. assert_eq!(UnitValue::from_str("0").unwrap(), UnitValue::Zero); assert_eq!(UnitValue::from_str("+0").unwrap(), UnitValue::Zero); assert_eq!(UnitValue::from_str("-0").unwrap(), UnitValue::Zero); } #[pagetop::test] async fn unit_value_absolute_integers_with_signs_and_spaces_and_case() { // Positivos, negativos y con espacios. assert_eq!(UnitValue::from_str("12px").unwrap(), UnitValue::Px(12)); assert_eq!(UnitValue::from_str("-5pt").unwrap(), UnitValue::Pt(-5)); assert_eq!(UnitValue::from_str(" 7 cm ").unwrap(), UnitValue::Cm(7)); assert_eq!(UnitValue::from_str("+9 in").unwrap(), UnitValue::In(9)); assert_eq!(UnitValue::from_str(" 13 mm ").unwrap(), UnitValue::Mm(13)); assert_eq!(UnitValue::from_str("4 pc").unwrap(), UnitValue::Pc(4)); // Insensibilidad a mayúsculas. assert_eq!(UnitValue::from_str("10PX").unwrap(), UnitValue::Px(10)); assert_eq!(UnitValue::from_str("15Pt").unwrap(), UnitValue::Pt(15)); } #[pagetop::test] async fn unit_value_relative_floats_with_signs_and_spaces_and_case() { assert_eq!( UnitValue::from_str("1.25rem").unwrap(), UnitValue::RelRem(1.25) ); assert_eq!( UnitValue::from_str("-0.5em").unwrap(), UnitValue::RelEm(-0.5) ); assert_eq!( UnitValue::from_str(" 33% ").unwrap(), UnitValue::RelPct(33.0) ); assert_eq!( UnitValue::from_str(" -12.5 vh").unwrap(), UnitValue::RelVh(-12.5) ); assert_eq!( UnitValue::from_str(" 8.0 VW ").unwrap(), UnitValue::RelVw(8.0) ); } #[pagetop::test] async fn unit_value_whitespace_between_number_and_unit_is_allowed() { // Hay espacio entre número y unidad (la implementación actual lo admite). assert_eq!(UnitValue::from_str("12 px").unwrap(), UnitValue::Px(12)); assert_eq!( UnitValue::from_str("1.5 rem").unwrap(), UnitValue::RelRem(1.5) ); assert_eq!( UnitValue::from_str("25 %").unwrap(), UnitValue::RelPct(25.0) ); } #[pagetop::test] async fn unit_value_roundtrip_display_keeps_expected_format() { let cases = [ ("", UnitValue::None, ""), ("auto", UnitValue::Auto, "auto"), ("0", UnitValue::Zero, "0"), ("12px", UnitValue::Px(12), "12px"), ("-5pt", UnitValue::Pt(-5), "-5pt"), ("7cm", UnitValue::Cm(7), "7cm"), ("33%", UnitValue::RelPct(33.0), "33%"), ("1.25rem", UnitValue::RelRem(1.25), "1.25rem"), ("2em", UnitValue::RelEm(2.0), "2em"), ("-0.5vh", UnitValue::RelVh(-0.5), "-0.5vh"), ("8vw", UnitValue::RelVw(8.0), "8vw"), ]; for (input, expected_value, expected_display) in cases { let parsed = UnitValue::from_str(input).unwrap(); assert_eq!( parsed, expected_value, "parsed mismatch for input `{input}`" ); assert_eq!( parsed.to_string(), expected_display, "display mismatch for input `{input}`" ); } } #[pagetop::test] async fn unit_value_percentage_trimming_and_signs() { assert_eq!( UnitValue::from_str(" 12.5 % ").unwrap(), UnitValue::RelPct(12.5) ); assert_eq!( UnitValue::from_str("-0.0%").unwrap(), UnitValue::RelPct(-0.0) ); assert_eq!( UnitValue::from_str("+15%").unwrap(), UnitValue::RelPct(15.0) ); } // ERRORES ESPERADOS (no cambiar los mensajes; con is_err() basta). #[pagetop::test] async fn unit_value_errors_missing_unit_for_non_zero() { assert!( UnitValue::from_str("12").is_err(), "non-zero without unit must error" ); assert!( UnitValue::from_str(" -3 ").is_err(), "non-zero without unit must error" ); } #[pagetop::test] async fn unit_value_errors_decimals_in_absolute_units() { assert!(UnitValue::from_str("1.5px").is_err()); assert!(UnitValue::from_str("-2.0pt").is_err()); assert!(UnitValue::from_str("+0.1cm").is_err()); } #[pagetop::test] async fn unit_value_errors_unknown_units_or_bad_percentages() { // Unidad no soportada. assert!(UnitValue::from_str("10ch").is_err()); assert!(UnitValue::from_str("2q").is_err()); // Falta número. assert!(UnitValue::from_str("%").is_err()); assert!(UnitValue::from_str(" % ").is_err()); } #[pagetop::test] async fn unit_value_errors_non_numeric_numbers() { assert!(UnitValue::from_str("NaNem").is_err()); // Decimal no permitido por FromStr. assert!(UnitValue::from_str("1,5rem").is_err()); } #[pagetop::test] async fn unit_value_serde_deserialize_struct_and_array() { use serde::Deserialize; #[derive(Deserialize, Debug, PartialEq)] struct BoxStyle { width: UnitValue, height: UnitValue, margin: UnitValue, } let json = r#"{ "width": "12px", "height": "1.5rem", "margin": "0" }"#; let s: BoxStyle = serde_json::from_str(json).unwrap(); assert_eq!(s.width, UnitValue::Px(12)); assert_eq!(s.height, UnitValue::RelRem(1.5)); assert_eq!(s.margin, UnitValue::Zero); #[derive(Deserialize, Debug, PartialEq)] struct Many { values: Vec, } let json_arr = r#"{ "values": ["", "auto", "33%", "8vw", "7 cm", "-5pt"] }"#; let m: Many = serde_json::from_str(json_arr).unwrap(); assert_eq!( m.values, vec![ UnitValue::None, UnitValue::Auto, UnitValue::RelPct(33.0), UnitValue::RelVw(8.0), UnitValue::Cm(7), UnitValue::Pt(-5), ] ); } #[pagetop::test] async fn unit_value_accepts_dot5_and_1dot_shorthand_for_relatives() { // `.5` y `1.` se parsean correctamente en relativas. assert_eq!(UnitValue::from_str(".5em").unwrap(), UnitValue::RelEm(0.5)); assert_eq!( UnitValue::from_str("1.rem").unwrap(), UnitValue::RelRem(1.0) ); assert_eq!(UnitValue::from_str("1.vh").unwrap(), UnitValue::RelVh(1.0)); // Sin unidad debe seguir fallando. assert!(UnitValue::from_str("1.").is_err()); } #[pagetop::test] async fn unit_value_display_keeps_minus_zero_for_relatives() { // Comportamiento actual: f32 Display muestra "-0" si el valor es -0.0. let v = UnitValue::RelEm(-0.0); // Se acepta cualquiera de los dos formatos como válidos. let s = v.to_string(); assert!( s == "-0em" || s == "0em", "current Display prints `{s}` for -0.0; both are acceptable in tests" ); } #[pagetop::test] async fn unit_value_rejects_non_decimal_notations() { // Octal, los ceros a la izquierda (p.ej. `"020px"`) se interpretan en **base 10** (`20px`). assert_eq!(UnitValue::from_str("020px").unwrap(), UnitValue::Px(20)); // Notación científica y bases no decimales (p.ej. `"1e3vw"`, `"0x10px"`) no están soportadas. assert!(UnitValue::from_str("1e3vw").is_err()); assert!(UnitValue::from_str("0x10px").is_err()); }