<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::properties::{parse, parse_input};
use crate::stylesheets::block_from;
use style::computed_values::display::T as Display;
use style::properties::declaration_block::PropertyDeclarationBlock;
use style::properties::parse_property_declaration_list;
use style::properties::{Importance, PropertyDeclaration};
use style::values::specified::url::SpecifiedUrl;
use style::values::specified::NoCalcLength;
use style::values::specified::{BorderSideWidth, BorderStyle, Color};
use style::values::specified::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
use style::values::RGBA;
use style_traits::ToCss;

trait ToCssString {
    fn to_css_string(&self) -> String;
}

impl ToCssString for PropertyDeclarationBlock {
    fn to_css_string(&self) -> String {
        let mut css = String::new();
        self.to_css(&mut css).unwrap();
        css
    }
}

#[test]
fn property_declaration_block_should_serialize_correctly() {
    use style::properties::longhands::overflow_x::SpecifiedValue as OverflowValue;

    let declarations = vec![
        (
            PropertyDeclaration::Width(LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(
                70f32,
            ))),
            Importance::Normal,
        ),
        (
            PropertyDeclaration::MinHeight(LengthOrPercentage::Length(NoCalcLength::from_px(
                20f32,
            ))),
            Importance::Normal,
        ),
        (
            PropertyDeclaration::Height(LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(
                20f32,
            ))),
            Importance::Important,
        ),
        (
            PropertyDeclaration::Display(Display::InlineBlock),
            Importance::Normal,
        ),
        (
            PropertyDeclaration::OverflowX(OverflowValue::Auto),
            Importance::Normal,
        ),
        (
            PropertyDeclaration::OverflowY(OverflowValue::Auto),
            Importance::Normal,
        ),
    ];

    let block = block_from(declarations);

    let css_string = block.to_css_string();

    assert_eq!(
        css_string,
        "width: 70px; min-height: 20px; height: 20px !important; display: inline-block; overflow: auto;"
    );
}

mod shorthand_serialization {
    pub use super::*;

    pub fn shorthand_properties_to_string(properties: Vec<PropertyDeclaration>) -> String {
        let block = block_from(properties.into_iter().map(|d| (d, Importance::Normal)));

        block.to_css_string()
    }

    mod four_sides_shorthands {
        pub use super::*;

        // we can use margin as a base to test out the different combinations
        // but afterwards, we only need to to one test per "four sides shorthand"
        #[test]
        fn all_equal_properties_should_serialize_to_one_value() {
            let mut properties = Vec::new();

            let px_70 = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(70f32));
            properties.push(PropertyDeclaration::MarginTop(px_70.clone()));
            properties.push(PropertyDeclaration::MarginRight(px_70.clone()));
            properties.push(PropertyDeclaration::MarginBottom(px_70.clone()));
            properties.push(PropertyDeclaration::MarginLeft(px_70));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "margin: 70px;");
        }

        #[test]
        fn equal_vertical_and_equal_horizontal_properties_should_serialize_to_two_value() {
            let mut properties = Vec::new();

            let vertical_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(10f32));
            let horizontal_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(5f32));

            properties.push(PropertyDeclaration::MarginTop(vertical_px.clone()));
            properties.push(PropertyDeclaration::MarginRight(horizontal_px.clone()));
            properties.push(PropertyDeclaration::MarginBottom(vertical_px));
            properties.push(PropertyDeclaration::MarginLeft(horizontal_px));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "margin: 10px 5px;");
        }

        #[test]
        fn different_vertical_and_equal_horizontal_properties_should_serialize_to_three_values() {
            let mut properties = Vec::new();

            let top_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(8f32));
            let bottom_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(10f32));
            let horizontal_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(5f32));

            properties.push(PropertyDeclaration::MarginTop(top_px));
            properties.push(PropertyDeclaration::MarginRight(horizontal_px.clone()));
            properties.push(PropertyDeclaration::MarginBottom(bottom_px));
            properties.push(PropertyDeclaration::MarginLeft(horizontal_px));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "margin: 8px 5px 10px;");
        }

        #[test]
        fn different_properties_should_serialize_to_four_values() {
            let mut properties = Vec::new();

            let top_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(8f32));
            let right_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(12f32));
            let bottom_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(10f32));
            let left_px = LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(14f32));

            properties.push(PropertyDeclaration::MarginTop(top_px));
            properties.push(PropertyDeclaration::MarginRight(right_px));
            properties.push(PropertyDeclaration::MarginBottom(bottom_px));
            properties.push(PropertyDeclaration::MarginLeft(left_px));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "margin: 8px 12px 10px 14px;");
        }

        #[test]
        fn different_longhands_should_serialize_to_long_form() {
            let mut properties = Vec::new();

            let solid = BorderStyle::Solid;

            properties.push(PropertyDeclaration::BorderTopStyle(solid.clone()));
            properties.push(PropertyDeclaration::BorderRightStyle(solid.clone()));
            properties.push(PropertyDeclaration::BorderBottomStyle(solid.clone()));
            properties.push(PropertyDeclaration::BorderLeftStyle(solid.clone()));

            let px_30 = BorderSideWidth::Length(Length::from_px(30f32));
            let px_10 = BorderSideWidth::Length(Length::from_px(10f32));

            properties.push(PropertyDeclaration::BorderTopWidth(px_30.clone()));
            properties.push(PropertyDeclaration::BorderRightWidth(px_30.clone()));
            properties.push(PropertyDeclaration::BorderBottomWidth(px_30.clone()));
            properties.push(PropertyDeclaration::BorderLeftWidth(px_10.clone()));

            let blue = Color::rgba(RGBA::new(0, 0, 255, 255));

            properties.push(PropertyDeclaration::BorderTopColor(blue.clone()));
            properties.push(PropertyDeclaration::BorderRightColor(blue.clone()));
            properties.push(PropertyDeclaration::BorderBottomColor(blue.clone()));
            properties.push(PropertyDeclaration::BorderLeftColor(blue.clone()));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization,
          "border-style: solid; border-width: 30px 30px 30px 10px; border-color: rgb(0, 0, 255);");
        }

        #[test]
        fn same_longhands_should_serialize_correctly() {
            let mut properties = Vec::new();

            let solid = BorderStyle::Solid;

            properties.push(PropertyDeclaration::BorderTopStyle(solid.clone()));
            properties.push(PropertyDeclaration::BorderRightStyle(solid.clone()));
            properties.push(PropertyDeclaration::BorderBottomStyle(solid.clone()));
            properties.push(PropertyDeclaration::BorderLeftStyle(solid.clone()));

            let px_30 = BorderSideWidth::Length(Length::from_px(30f32));

            properties.push(PropertyDeclaration::BorderTopWidth(px_30.clone()));
            properties.push(PropertyDeclaration::BorderRightWidth(px_30.clone()));
            properties.push(PropertyDeclaration::BorderBottomWidth(px_30.clone()));
            properties.push(PropertyDeclaration::BorderLeftWidth(px_30.clone()));

            let blue = Color::rgba(RGBA::new(0, 0, 255, 255));

            properties.push(PropertyDeclaration::BorderTopColor(blue.clone()));
            properties.push(PropertyDeclaration::BorderRightColor(blue.clone()));
            properties.push(PropertyDeclaration::BorderBottomColor(blue.clone()));
            properties.push(PropertyDeclaration::BorderLeftColor(blue.clone()));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(
                serialization,
                "border-style: solid; border-width: 30px; border-color: rgb(0, 0, 255);"
            );
        }

        #[test]
        fn padding_should_serialize_correctly() {
            use style::values::specified::NonNegativeLengthOrPercentage;

            let mut properties = Vec::new();

            let px_10: NonNegativeLengthOrPercentage = NoCalcLength::from_px(10f32).into();
            let px_15: NonNegativeLengthOrPercentage = NoCalcLength::from_px(15f32).into();
            properties.push(PropertyDeclaration::PaddingTop(px_10.clone()));
            properties.push(PropertyDeclaration::PaddingRight(px_15.clone()));
            properties.push(PropertyDeclaration::PaddingBottom(px_10));
            properties.push(PropertyDeclaration::PaddingLeft(px_15));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "padding: 10px 15px;");
        }

        #[test]
        fn border_width_should_serialize_correctly() {
            let mut properties = Vec::new();

            let top_px = BorderSideWidth::Length(Length::from_px(10f32));
            let bottom_px = BorderSideWidth::Length(Length::from_px(10f32));

            let right_px = BorderSideWidth::Length(Length::from_px(15f32));
            let left_px = BorderSideWidth::Length(Length::from_px(15f32));

            properties.push(PropertyDeclaration::BorderTopWidth(top_px));
            properties.push(PropertyDeclaration::BorderRightWidth(right_px));
            properties.push(PropertyDeclaration::BorderBottomWidth(bottom_px));
            properties.push(PropertyDeclaration::BorderLeftWidth(left_px));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "border-width: 10px 15px;");
        }

        #[test]
        fn border_width_with_keywords_should_serialize_correctly() {
            let mut properties = Vec::new();

            let top_px = BorderSideWidth::Thin;
            let right_px = BorderSideWidth::Medium;
            let bottom_px = BorderSideWidth::Thick;
            let left_px = BorderSideWidth::Length(Length::from_px(15f32));

            properties.push(PropertyDeclaration::BorderTopWidth(top_px));
            properties.push(PropertyDeclaration::BorderRightWidth(right_px));
            properties.push(PropertyDeclaration::BorderBottomWidth(bottom_px));
            properties.push(PropertyDeclaration::BorderLeftWidth(left_px));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "border-width: thin medium thick 15px;");
        }

        #[test]
        fn border_color_should_serialize_correctly() {
            let mut properties = Vec::new();

            let red = Color::rgba(RGBA::new(255, 0, 0, 255));
            let blue = Color::rgba(RGBA::new(0, 0, 255, 255));

            properties.push(PropertyDeclaration::BorderTopColor(blue.clone()));
            properties.push(PropertyDeclaration::BorderRightColor(red.clone()));
            properties.push(PropertyDeclaration::BorderBottomColor(blue));
            properties.push(PropertyDeclaration::BorderLeftColor(red));

            let serialization = shorthand_properties_to_string(properties);

            // TODO: Make the rgb test show border-color as blue red instead of below tuples
            assert_eq!(
                serialization,
                "border-color: rgb(0, 0, 255) rgb(255, 0, 0);"
            );
        }

        #[test]
        fn border_style_should_serialize_correctly() {
            let mut properties = Vec::new();

            let solid = BorderStyle::Solid;
            let dotted = BorderStyle::Dotted;
            properties.push(PropertyDeclaration::BorderTopStyle(solid.clone()));
            properties.push(PropertyDeclaration::BorderRightStyle(dotted.clone()));
            properties.push(PropertyDeclaration::BorderBottomStyle(solid));
            properties.push(PropertyDeclaration::BorderLeftStyle(dotted));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "border-style: solid dotted;");
        }

        use style::values::specified::{BorderCornerRadius, Percentage};

        #[test]
        fn border_radius_should_serialize_correctly() {
            let mut properties = Vec::new();
            properties.push(PropertyDeclaration::BorderTopLeftRadius(Box::new(
                BorderCornerRadius::new(Percentage::new(0.01).into(), Percentage::new(0.05).into()),
            )));
            properties.push(PropertyDeclaration::BorderTopRightRadius(Box::new(
                BorderCornerRadius::new(Percentage::new(0.02).into(), Percentage::new(0.06).into()),
            )));
            properties.push(PropertyDeclaration::BorderBottomRightRadius(Box::new(
                BorderCornerRadius::new(Percentage::new(0.03).into(), Percentage::new(0.07).into()),
            )));
            properties.push(PropertyDeclaration::BorderBottomLeftRadius(Box::new(
                BorderCornerRadius::new(Percentage::new(0.04).into(), Percentage::new(0.08).into()),
            )));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "border-radius: 1% 2% 3% 4% / 5% 6% 7% 8%;");
        }
    }

    mod border_shorthands {
        use super::*;

        #[test]
        fn border_top_and_color() {
            let mut properties = Vec::new();
            properties.push(PropertyDeclaration::BorderTopWidth(
                BorderSideWidth::Length(Length::from_px(1.)),
            ));
            properties.push(PropertyDeclaration::BorderTopStyle(BorderStyle::Solid));
            let c = Color::Numeric {
                parsed: RGBA::new(255, 0, 0, 255),
                authored: Some("green".to_string().into_boxed_str()),
            };
            properties.push(PropertyDeclaration::BorderTopColor(c));
            let c = Color::Numeric {
                parsed: RGBA::new(0, 255, 0, 255),
                authored: Some("red".to_string().into_boxed_str()),
            };
            properties.push(PropertyDeclaration::BorderTopColor(c.clone()));
            properties.push(PropertyDeclaration::BorderBottomColor(c.clone()));
            properties.push(PropertyDeclaration::BorderLeftColor(c.clone()));
            properties.push(PropertyDeclaration::BorderRightColor(c.clone()));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(
                serialization,
                "border-top: 1px solid red; border-color: red;"
            );
        }

        #[test]
        fn border_color_and_top() {
            let mut properties = Vec::new();
            let c = Color::Numeric {
                parsed: RGBA::new(0, 255, 0, 255),
                authored: Some("red".to_string().into_boxed_str()),
            };
            properties.push(PropertyDeclaration::BorderTopColor(c.clone()));
            properties.push(PropertyDeclaration::BorderBottomColor(c.clone()));
            properties.push(PropertyDeclaration::BorderLeftColor(c.clone()));
            properties.push(PropertyDeclaration::BorderRightColor(c.clone()));

            properties.push(PropertyDeclaration::BorderTopWidth(
                BorderSideWidth::Length(Length::from_px(1.)),
            ));
            properties.push(PropertyDeclaration::BorderTopStyle(BorderStyle::Solid));
            let c = Color::Numeric {
                parsed: RGBA::new(255, 0, 0, 255),
                authored: Some("green".to_string().into_boxed_str()),
            };
            properties.push(PropertyDeclaration::BorderTopColor(c));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(
                serialization,
                "border-color: green red red; border-top: 1px solid green;"
            );
        }

        // we can use border-top as a base to test out the different combinations
        // but afterwards, we only need to to one test per "directional border shorthand"

        #[test]
        fn directional_border_should_show_all_properties_when_values_are_set() {
            let mut properties = Vec::new();

            let width = BorderSideWidth::Length(Length::from_px(4f32));
            let style = BorderStyle::Solid;
            let color = RGBA::new(255, 0, 0, 255).into();

            properties.push(PropertyDeclaration::BorderTopWidth(width));
            properties.push(PropertyDeclaration::BorderTopStyle(style));
            properties.push(PropertyDeclaration::BorderTopColor(color));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "border-top: 4px solid rgb(255, 0, 0);");
        }

        fn get_border_property_values() -> (BorderSideWidth, BorderStyle, Color) {
            (
                BorderSideWidth::Length(Length::from_px(4f32)),
                BorderStyle::Solid,
                Color::currentcolor(),
            )
        }

        #[test]
        fn border_top_should_serialize_correctly() {
            let mut properties = Vec::new();
            let (width, style, color) = get_border_property_values();
            properties.push(PropertyDeclaration::BorderTopWidth(width));
            properties.push(PropertyDeclaration::BorderTopStyle(style));
            properties.push(PropertyDeclaration::BorderTopColor(color));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "border-top: 4px solid;");
        }

        #[test]
        fn border_right_should_serialize_correctly() {
            let mut properties = Vec::new();
            let (width, style, color) = get_border_property_values();
            properties.push(PropertyDeclaration::BorderRightWidth(width));
            properties.push(PropertyDeclaration::BorderRightStyle(style));
            properties.push(PropertyDeclaration::BorderRightColor(color));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "border-right: 4px solid;");
        }

        #[test]
        fn border_bottom_should_serialize_correctly() {
            let mut properties = Vec::new();
            let (width, style, color) = get_border_property_values();
            properties.push(PropertyDeclaration::BorderBottomWidth(width));
            properties.push(PropertyDeclaration::BorderBottomStyle(style));
            properties.push(PropertyDeclaration::BorderBottomColor(color));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "border-bottom: 4px solid;");
        }

        #[test]
        fn border_left_should_serialize_correctly() {
            let mut properties = Vec::new();
            let (width, style, color) = get_border_property_values();
            properties.push(PropertyDeclaration::BorderLeftWidth(width));
            properties.push(PropertyDeclaration::BorderLeftStyle(style));
            properties.push(PropertyDeclaration::BorderLeftColor(color));

            let serialization = shorthand_properties_to_string(properties);
            assert_eq!(serialization, "border-left: 4px solid;");
        }

        #[test]
        fn border_should_serialize_correctly() {
            // According to https://drafts.csswg.org/css-backgrounds-3/#the-border-shorthands,
            // the ‘border’ shorthand resets ‘border-image’ to its initial value. To verify the
            // serialization of 'border' shorthand, we need to set 'border-image' as well.
            let block_text = "\
                              border-top: 4px solid; \
                              border-right: 4px solid; \
                              border-bottom: 4px solid; \
                              border-left: 4px solid; \
                              border-image: none;";

            let block =
                parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();

            let serialization = block.to_css_string();

            assert_eq!(serialization, "border: 4px solid;");
        }
    }

    mod list_style {
        use super::*;
        use style::properties::longhands::list_style_position::SpecifiedValue as ListStylePosition;
        use style::properties::longhands::list_style_type::SpecifiedValue as ListStyleType;
        use style::values::generics::url::UrlOrNone as ImageUrlOrNone;

        #[test]
        fn list_style_should_show_all_properties_when_values_are_set() {
            let mut properties = Vec::new();<commit_msg>style: Remove a bunch of unit tests that are not very useful.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::properties::{parse, parse_input};
use crate::stylesheets::block_from;
use style::computed_values::display::T as Display;
use style::properties::declaration_block::PropertyDeclarationBlock;
use style::properties::parse_property_declaration_list;
use style::properties::{Importance, PropertyDeclaration};
use style::values::specified::url::SpecifiedUrl;
use style::values::specified::NoCalcLength;
use style::values::specified::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
use style_traits::ToCss;

trait ToCssString {
    fn to_css_string(&self) -> String;
}

impl ToCssString for PropertyDeclarationBlock {
    fn to_css_string(&self) -> String {
        let mut css = String::new();
        self.to_css(&mut css).unwrap();
        css
    }
}

#[test]
fn property_declaration_block_should_serialize_correctly() {
    use style::properties::longhands::overflow_x::SpecifiedValue as OverflowValue;

    let declarations = vec![
        (
            PropertyDeclaration::Width(LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(
                70f32,
            ))),
            Importance::Normal,
        ),
        (
            PropertyDeclaration::MinHeight(LengthOrPercentage::Length(NoCalcLength::from_px(
                20f32,
            ))),
            Importance::Normal,
        ),
        (
            PropertyDeclaration::Height(LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(
                20f32,
            ))),
            Importance::Important,
        ),
        (
            PropertyDeclaration::Display(Display::InlineBlock),
            Importance::Normal,
        ),
        (
            PropertyDeclaration::OverflowX(OverflowValue::Auto),
            Importance::Normal,
        ),
        (
            PropertyDeclaration::OverflowY(OverflowValue::Auto),
            Importance::Normal,
        ),
    ];

    let block = block_from(declarations);

    let css_string = block.to_css_string();

    assert_eq!(
        css_string,
        "width: 70px; min-height: 20px; height: 20px !important; display: inline-block; overflow: auto;"
    );
}

mod shorthand_serialization {
    pub use super::*;

    pub fn shorthand_properties_to_string(properties: Vec<PropertyDeclaration>) -> String {
        let block = block_from(properties.into_iter().map(|d| (d, Importance::Normal)));

        block.to_css_string()
    }

    mod list_style {
        use super::*;
        use style::properties::longhands::list_style_position::SpecifiedValue as ListStylePosition;
        use style::properties::longhands::list_style_type::SpecifiedValue as ListStyleType;
        use style::values::generics::url::UrlOrNone as ImageUrlOrNone;

        #[test]
        fn list_style_should_show_all_properties_when_values_are_set() {
            let mut properties = Vec::new();
{'fraction_non_alphanumeric': 0.11537082054756306, 'fraction_numerical': 0.01394811301956721, 'mean_word_length': 2.8857231340972436, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 12, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6261905', 'n_tokens_mistral': 6878, 'n_tokens_neox': 6465, 'n_words': 1079}