use lightningcss::{ declaration::DeclarationBlock, properties::{Property, PropertyId}, stylesheet::{ParserOptions, PrinterOptions}, traits::ToCss, vendor_prefix::VendorPrefix, }; fn get_test(decls: &str, property_id: PropertyId, expected: Option<(&str, bool)>) { let decls = DeclarationBlock::parse_string(decls, ParserOptions::default()).unwrap(); let v = decls.get(&property_id); if let Some((expected, important)) = expected { let (value, is_important) = v.unwrap(); assert_eq!( *value, Property::parse_string(property_id, expected, ParserOptions::default()).unwrap() ); assert_eq!(is_important, important); } else { assert_eq!(v, None) } } #[test] fn test_get() { get_test("color: red", PropertyId::Color, Some(("red", false))); get_test("color: red !important", PropertyId::Color, Some(("red", true))); get_test("color: green; color: red", PropertyId::Color, Some(("red", false))); get_test( r#" margin-top: 5px; margin-bottom: 5px; margin-left: 5px; margin-right: 5px; "#, PropertyId::Margin, Some(("5px", false)), ); get_test( r#" margin-top: 5px; margin-bottom: 5px; margin-left: 6px; margin-right: 6px; "#, PropertyId::Margin, Some(("5px 6px", false)), ); get_test( r#" margin-top: 5px; margin-bottom: 5px; margin-left: 6px; margin-right: 6px; "#, PropertyId::Margin, Some(("5px 6px", false)), ); get_test( r#" margin-top: 5px; margin-bottom: 5px; "#, PropertyId::Margin, None, ); get_test( r#" margin-top: 5px; margin-bottom: 5px; margin-left: 5px !important; margin-right: 5px; "#, PropertyId::Margin, None, ); get_test( r#" margin-top: 5px !important; margin-bottom: 5px !important; margin-left: 5px !important; margin-right: 5px !important; "#, PropertyId::Margin, Some(("5px", true)), ); get_test( "margin: 5px 6px 7px 8px", PropertyId::Margin, Some(("5px 6px 7px 8px", false)), ); get_test("margin: 5px 6px 7px 8px", PropertyId::MarginTop, Some(("5px", false))); get_test( r#" border: 1px solid red; border-color: green; "#, PropertyId::Border, Some(("1px solid green", false)), ); get_test( r#" border: 1px solid red; border-left-color: green; "#, PropertyId::Border, None, ); get_test("background: red", PropertyId::Background, Some(("red", false))); get_test("background: red", PropertyId::BackgroundColor, Some(("red", false))); get_test( "background: red url(foo.png)", PropertyId::BackgroundColor, Some(("red", false)), ); get_test( "background: url(foo.png), url(bar.png) red", PropertyId::BackgroundColor, Some(("red", false)), ); get_test( "background: url(foo.png) green, url(bar.png) red", PropertyId::BackgroundColor, Some(("red", false)), ); get_test( "background: linear-gradient(red, green)", PropertyId::BackgroundImage, Some(("linear-gradient(red, green)", false)), ); get_test( "background: linear-gradient(red, green), linear-gradient(#fff, #000)", PropertyId::BackgroundImage, Some(("linear-gradient(red, green), linear-gradient(#fff, #000)", false)), ); get_test( "background: linear-gradient(red, green) repeat-x, linear-gradient(#fff, #000) repeat-y", PropertyId::BackgroundImage, Some(("linear-gradient(red, green), linear-gradient(#fff, #000)", false)), ); get_test( "background: linear-gradient(red, green) repeat-x, linear-gradient(#fff, #000) repeat-y", PropertyId::BackgroundRepeat, Some(("repeat-x, repeat-y", false)), ); get_test( r#" background: linear-gradient(red, green); background-position-x: 20px; background-position-y: 10px; background-size: 50px 100px; background-repeat: repeat no-repeat; "#, PropertyId::Background, Some(("linear-gradient(red, green) 20px 10px / 50px 100px repeat-x", false)), ); get_test( r#" background: linear-gradient(red, green); background-position-x: 20px; background-position-y: 10px !important; background-size: 50px 100px; background-repeat: repeat no-repeat; "#, PropertyId::Background, None, ); get_test( r#" background: linear-gradient(red, green), linear-gradient(#fff, #000) gray; background-position-x: right 20px, 10px; background-position-y: top 20px, 15px; background-size: 50px 50px, auto; background-repeat: repeat no-repeat, no-repeat; "#, PropertyId::Background, Some(("linear-gradient(red, green) right 20px top 20px / 50px 50px repeat-x, gray linear-gradient(#fff, #000) 10px 15px no-repeat", false)), ); get_test( r#" background: linear-gradient(red, green); background-position-x: right 20px, 10px; background-position-y: top 20px, 15px; background-size: 50px 50px, auto; background-repeat: repeat no-repeat, no-repeat; "#, PropertyId::Background, None, ); get_test( r#" background: linear-gradient(red, green); background-position: 20px 10px; background-size: 50px 100px; background-repeat: repeat no-repeat; "#, PropertyId::Background, Some(("linear-gradient(red, green) 20px 10px / 50px 100px repeat-x", false)), ); get_test( r#" background-position-x: 20px; background-position-y: 10px; "#, PropertyId::BackgroundPosition, Some(("20px 10px", false)), ); get_test( r#" background: linear-gradient(red, green) 20px 10px; "#, PropertyId::BackgroundPosition, Some(("20px 10px", false)), ); get_test( r#" background: linear-gradient(red, green) 20px 10px; "#, PropertyId::BackgroundPositionX, Some(("20px", false)), ); get_test( r#" background: linear-gradient(red, green) 20px 10px; "#, PropertyId::BackgroundPositionY, Some(("10px", false)), ); get_test( "mask-border: linear-gradient(red, green) 25", PropertyId::MaskBorderSource, Some(("linear-gradient(red, green)", false)), ); get_test("grid-area: a / b / c / d", PropertyId::GridRowStart, Some(("a", false))); get_test("grid-area: a / b / c / d", PropertyId::GridRowEnd, Some(("c", false))); get_test("grid-area: a / b / c / d", PropertyId::GridRow, Some(("a / c", false))); get_test( "grid-area: a / b / c / d", PropertyId::GridColumn, Some(("b / d", false)), ); get_test( r#" grid-template-rows: auto 1fr; grid-template-columns: auto 1fr auto; grid-template-areas: none; "#, PropertyId::GridTemplate, Some(("auto 1fr / auto 1fr auto", false)), ); get_test( r#" grid-template-areas: ". a a ." ". b b ."; grid-template-rows: auto 1fr; grid-template-columns: 10px 1fr 1fr 10px; "#, PropertyId::GridTemplate, Some(( r#" ". a a ." ". b b ." 1fr / 10px 1fr 1fr 10px "#, false, )), ); get_test( r#" grid-template-areas: "a a a" "b b b"; grid-template-columns: repeat(3, 1fr); grid-template-rows: auto 1fr; "#, PropertyId::GridTemplate, None, ); get_test( r#" grid-template-areas: "a a a" "b b b"; grid-template-rows: [header-top] auto [header-bottom main-top] 1fr [main-bottom]; grid-template-columns: auto 1fr auto; grid-auto-flow: row; grid-auto-rows: auto; grid-auto-columns: auto; "#, PropertyId::Grid, Some(( r#" [header-top] "a a a" [header-bottom] [main-top] "b b b" 1fr [main-bottom] / auto 1fr auto "#, false, )), ); get_test( r#" grid-template-areas: "a a a" "b b b"; grid-template-rows: [header-top] auto [header-bottom main-top] 1fr [main-bottom]; grid-template-columns: auto 1fr auto; grid-auto-flow: column; grid-auto-rows: 1fr; grid-auto-columns: 1fr; "#, PropertyId::Grid, None, ); get_test( r#" flex-direction: row; flex-wrap: wrap; "#, PropertyId::FlexFlow(VendorPrefix::None), Some(("row wrap", false)), ); get_test( r#" -webkit-flex-direction: row; -webkit-flex-wrap: wrap; "#, PropertyId::FlexFlow(VendorPrefix::WebKit), Some(("row wrap", false)), ); get_test( r#" flex-direction: row; flex-wrap: wrap; "#, PropertyId::FlexFlow(VendorPrefix::WebKit), None, ); get_test( r#" -webkit-flex-direction: row; flex-wrap: wrap; "#, PropertyId::FlexFlow(VendorPrefix::WebKit), None, ); get_test( r#" -webkit-flex-direction: row; flex-wrap: wrap; "#, PropertyId::FlexFlow(VendorPrefix::None), None, ); get_test( r#" -webkit-flex-flow: row; "#, PropertyId::FlexDirection(VendorPrefix::WebKit), Some(("row", false)), ); get_test( r#" -webkit-flex-flow: row; "#, PropertyId::FlexDirection(VendorPrefix::None), None, ); } fn set_test(orig: &str, property: &str, value: &str, important: bool, expected: &str) { let mut decls = DeclarationBlock::parse_string(orig, ParserOptions::default()).unwrap(); decls.set( Property::parse_string(property.into(), value, ParserOptions::default()).unwrap(), important, ); assert_eq!(decls.to_css_string(PrinterOptions::default()).unwrap(), expected); } #[test] fn test_set() { set_test("color: red", "color", "green", false, "color: green"); set_test("color: red !important", "color", "green", false, "color: green"); set_test("color: red", "color", "green", true, "color: green !important"); set_test("margin: 5px", "margin", "10px", false, "margin: 10px"); set_test("margin: 5px", "margin-top", "8px", false, "margin: 8px 5px 5px"); set_test( "margin: 5px", "margin-inline-start", "8px", false, "margin: 5px; margin-inline-start: 8px", ); set_test( "margin-inline-start: 5px; margin-top: 10px", "margin-inline-start", "8px", false, "margin-inline-start: 5px; margin-top: 10px; margin-inline-start: 8px", ); set_test( "margin: 5px; margin-inline-start: 8px", "margin-left", "10px", false, "margin: 5px; margin-inline-start: 8px; margin-left: 10px", ); set_test( "border: 1px solid red", "border-right", "1px solid green", false, "border: 1px solid red; border-right: 1px solid green", ); set_test( "border: 1px solid red", "border-right-color", "green", false, "border: 1px solid red; border-right-color: green", ); set_test( "animation: foo 2s", "animation-name", "foo, bar", false, "animation: 2s foo; animation-name: foo, bar", ); set_test("animation: foo 2s", "animation-name", "bar", false, "animation: 2s bar"); set_test( "background: linear-gradient(red, green)", "background-position-x", "20px", false, "background: linear-gradient(red, green) 20px 0", ); set_test( "background: linear-gradient(red, green)", "background-position", "20px 10px", false, "background: linear-gradient(red, green) 20px 10px", ); set_test( "flex-flow: row wrap", "flex-direction", "column", false, "flex-flow: column wrap", ); set_test( "-webkit-flex-flow: row wrap", "-webkit-flex-direction", "column", false, "-webkit-flex-flow: column wrap", ); set_test( "flex-flow: row wrap", "-webkit-flex-direction", "column", false, "flex-flow: wrap; -webkit-flex-direction: column", ); } fn remove_test(orig: &str, property_id: PropertyId, expected: &str) { let mut decls = DeclarationBlock::parse_string(orig, ParserOptions::default()).unwrap(); decls.remove(&property_id); assert_eq!(decls.to_css_string(PrinterOptions::default()).unwrap(), expected); } #[test] fn test_remove() { remove_test("margin-top: 10px", PropertyId::MarginTop, ""); remove_test( "margin-top: 10px; margin-left: 5px", PropertyId::MarginTop, "margin-left: 5px", ); remove_test( "margin-top: 10px !important; margin-left: 5px", PropertyId::MarginTop, "margin-left: 5px", ); remove_test( "margin: 10px", PropertyId::MarginTop, "margin-right: 10px; margin-bottom: 10px; margin-left: 10px", ); remove_test("margin: 10px", PropertyId::Margin, ""); remove_test( "margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px", PropertyId::Margin, "", ); remove_test( "flex-flow: column wrap", PropertyId::FlexDirection(VendorPrefix::None), "flex-wrap: wrap", ); remove_test( "flex-flow: column wrap", PropertyId::FlexDirection(VendorPrefix::WebKit), "flex-flow: column wrap", ); remove_test( "-webkit-flex-flow: column wrap", PropertyId::FlexDirection(VendorPrefix::WebKit), "-webkit-flex-wrap: wrap", ); }