From cbef775ef41b100cb5059c0ffd022fe3d76634f4 Mon Sep 17 00:00:00 2001 From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com> Date: Tue, 14 Jan 2020 20:23:05 -0500 Subject: [PATCH] Consolidate tests to be on CSS output rather than internal representation --- src/format.rs | 164 ------------------------- src/lexer.rs | 1 + src/main.rs | 325 +++++++++++++++++++++++++++++++++++--------------- src/mixin.rs | 7 +- 4 files changed, 232 insertions(+), 265 deletions(-) diff --git a/src/format.rs b/src/format.rs index 2fc3912..7090227 100644 --- a/src/format.rs +++ b/src/format.rs @@ -130,65 +130,8 @@ mod test_scss { test!(empty, ""); test!(basic_nesting, "a {\n b {\n }\n}\n"); test!(mul_nesting, "a, b {\n a, b {\n }\n}\n"); - test!(ident_with_num, "el1 {\n}\n"); - - test!(selector_element, "a {\n}\n"); - test!(selector_id, "#id {\n}\n"); - test!(selector_class, ".class {\n}\n"); - test!(selector_el_descendant, "a a {\n}\n"); - test!(selector_universal, "* {\n}\n"); - test!(selector_el_class_and, "a.class {\n}\n"); - test!(selector_el_id_and, "a#class {\n}\n"); - test!(selector_el_class_descendant, "a .class {\n}\n"); - test!(selector_el_id_descendant, "a #class {\n}\n"); - test!(selector_el_universal_descendant, "a * {\n}\n"); - test!(selector_universal_el_descendant, "* a {\n}\n"); - - test!(selector_attribute_any, "[attr] {\n}\n"); - test!(selector_attribute_equals, "[attr=val] {\n}\n"); - test!(selector_attribute_single_quotes, "[attr='val'] {\n}\n"); - test!(selector_attribute_double_quotes, "[attr=\"val\"] {\n}\n"); - test!(selector_attribute_in, "[attr~=val] {\n}\n"); - test!( - selector_attribute_begins_hyphen_or_exact, - "[attr|=val] {\n}\n" - ); - test!(selector_attribute_starts_with, "[attr^=val] {\n}\n"); - test!(selector_attribute_ends_with, "[attr$=val] {\n}\n"); - test!(selector_attribute_contains, "[attr*=val] {\n}\n"); - test!(selector_el_attribute_and, "a[attr] {\n}\n"); - test!(selector_el_attribute_descendant, "a [attr] {\n}\n"); - test!(selector_el_mul_el, "a, b {\n}\n"); - test!(selector_el_immediate_child_el, "a > b {\n}\n"); - test!(selector_el_following_el, "a + b {\n}\n"); - test!(selector_el_preceding_el, "a ~ b {\n}\n"); - test!(selector_pseudo, ":pseudo {\n}\n"); - test!(selector_el_pseudo_and, "a:pseudo {\n}\n"); - test!(selector_el_pseudo_descendant, "a :pseudo {\n}\n"); - test!(selector_pseudo_el_descendant, ":pseudo a {\n}\n"); - test!(basic_style, "a {\n color: red;\n}\n"); test!(two_styles, "a {\n color: red;\n color: blue;\n}\n"); - test!( - multiline_style, - "a {\n color: red\n blue;\n}\n", - "a {\n color: red blue;\n}\n" - ); - test!(hyphenated_style_property, "a {\n font-family: Arial;\n}\n"); - test!(hyphenated_style_value, "a {\n color: Open-Sans;\n}\n"); - test!( - space_separated_style_value, - "a {\n border: solid red;\n}\n" - ); - test!(single_quoted_style_value, "a {\n font: 'Open-Sans';\n}\n"); - test!( - double_quoted_style_value, - "a {\n font: \"Open-Sans\";\n}\n" - ); - test!( - comma_style_value, - "a {\n font: Open-Sans, sans-serif;\n}\n" - ); test!( nested_style_in_parent, "a {\n color: red;\n b {\n }\n}\n" @@ -201,113 +144,6 @@ mod test_scss { nested_style_in_both, "a {\n color: red;\n b {\n color: red;\n }\n}\n" ); - - test!( - basic_variable, - "$height: 1px;\na {\n height: $height;\n}\n", - "a {\n height: 1px;\n}\n" - ); - test!( - variable_redeclaration, - "$a: 1px;\n$a: 2px;\na {\n height: $a;\n}\n", - "a {\n height: 2px;\n}\n" - ); - test!( - variable_shadowing, - "$a: 1px;\n$b: $a;\na {\n height: $b;\n}\n", - "a {\n height: 1px;\n}\n" - ); - test!( - variable_shadowing_val_does_not_change, - "$a: 1px;\n$b: $a; $a: 2px;\na {\n height: $b;\n}\n", - "a {\n height: 1px;\n}\n" - ); - test!( - variable_shadowing_val_does_not_change_complex, - "a {\n}\n$y: before;\n$x: 1 2 $y;\n$y: after;\nfoo {\n a: $x;\n}", - "a {\n}\nfoo {\n a: 1 2 before;\n}\n" - ); - test!( - variable_whitespace, - "$a : 1px ;\na {\n height: $a;\n}\n", - "a {\n height: 1px;\n}\n" - ); - test!( - style_after_variable, - "$a: 1px;\na {\n height: $a;\n color: red;\n}\n", - "a {\n height: 1px;\n color: red;\n}\n" - ); - test!( - literal_and_variable_as_val, - "$a: 1px;\na {\n height: 1 $a;\n}\n", - "a {\n height: 1 1px;\n}\n" - ); - test!( - literal_and_variable_as_var, - "$a: 1px;\n$b: 1 $a;\na {\n height: $b;\n}\n", - "a {\n height: 1 1px;\n}\n" - ); - - test!(keyword_important, "a {\n height: 1 !important;\n}\n"); - test!( - keyword_important_uppercase, - "a {\n height: 1 !IMPORTANT;\n}\n", - "a {\n height: 1 !important;\n}\n" - ); - test!( - keyword_important_not_at_end, - "a {\n height: !important 1;\n}\n" - ); - - test!( - combines_hyphens, - "a {\n foo: bar - baz;\n}\n", - "a {\n foo: bar-baz;\n}\n" - ); - test!(does_not_combine_hyphens, "a {\n foo: bar -baz;\n}\n"); - test!( - ident_starts_with_hyphen, - "a {\n foo: -webkit-bar-baz;\n}\n" - ); - - test!( - removes_inner_comments, - "a {\n color: red/* hi */;\n}\n", - "a {\n color: red;\n}\n" - ); - test!( - removes_inner_comments_whitespace, - "a {\n color: red /* hi */;\n}\n", - "a {\n color: red;\n}\n" - ); - test!( - preserves_outer_comments_before, - "a {\n /* hi */\n color: red;\n}\n" - ); - test!( - preserves_outer_comments_after, - "a {\n color: red;\n /* hi */\n}\n" - ); - test!( - preserves_outer_comments_two, - "a {\n /* foo */\n /* bar */\n color: red;\n}\n" - ); - test!( - preserves_toplevel_comment, - "/* foo */\na {\n color: red;\n}\n" - ); - test!( - removes_single_line_comment, - "// a { color: red }\na {\n height: 1 1px;\n}\n", - "a {\n height: 1 1px;\n}\n" - ); - - test!(unit_none, "a {\n height: 1;\n}\n"); - test!(unit_not_attached, "a {\n height: 1 px;\n}\n"); - test!(unit_px, "a {\n height: 1px;\n}\n"); - test!(unit_em, "a {\n height: 1em;\n}\n"); - test!(unit_rem, "a {\n height: 1rem;\n}\n"); - test!(unit_percent, "a {\n height: 1%;\n}\n"); test!( deeply_nested_selector, "\ diff --git a/src/lexer.rs b/src/lexer.rs index ab52375..46e6386 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -216,6 +216,7 @@ impl<'a> Lexer<'a> { fn lex_attr(&mut self) -> TokenKind { let mut attr = String::with_capacity(99); + self.devour_whitespace(); while let Some(c) = self.buf.peek() { if !c.is_alphabetic() && c != &'-' && c != &'_' { break; diff --git a/src/main.rs b/src/main.rs index 153dc61..e0f3198 100644 --- a/src/main.rs +++ b/src/main.rs @@ -573,39 +573,90 @@ fn main() -> SassResult<()> { } #[cfg(test)] -mod test_css { - use super::StyleSheet; - macro_rules! test { - ($func:ident, $input:literal) => { - #[test] - fn $func() { - let mut buf = Vec::new(); - StyleSheet::new($input) - .expect(concat!("failed to parse on ", $input)) - .print_as_css(&mut buf) - .expect(concat!("failed to pretty print on ", $input)); - assert_eq!( - String::from($input), - String::from_utf8(buf).expect("produced invalid utf8") - ); - } - }; - ($func:ident, $input:literal, $output:literal) => { - #[test] - fn $func() { - let mut buf = Vec::new(); - StyleSheet::new($input) - .expect(concat!("failed to parse on ", $input)) - .print_as_css(&mut buf) - .expect(concat!("failed to pretty print on ", $input)); - assert_eq!( - String::from($output), - String::from_utf8(buf).expect("produced invalid utf8") - ); - } - }; - } +macro_rules! test { + ($func:ident, $input:literal) => { + #[test] + fn $func() { + let mut buf = Vec::new(); + StyleSheet::new($input) + .expect(concat!("failed to parse on ", $input)) + .print_as_css(&mut buf) + .expect(concat!("failed to pretty print on ", $input)); + assert_eq!( + String::from($input), + String::from_utf8(buf).expect("produced invalid utf8") + ); + } + }; + ($func:ident, $input:literal, $output:literal) => { + #[test] + fn $func() { + let mut buf = Vec::new(); + StyleSheet::new($input) + .expect(concat!("failed to parse on ", $input)) + .print_as_css(&mut buf) + .expect(concat!("failed to pretty print on ", $input)); + assert_eq!( + String::from($output), + String::from_utf8(buf).expect("produced invalid utf8") + ); + } + }; +} +#[cfg(test)] +mod css_variables { + use super::StyleSheet; + test!( + basic_variable, + "$height: 1px;\na {\n height: $height;\n}\n", + "a {\n height: 1px;\n}\n" + ); + test!( + variable_redeclaration, + "$a: 1px;\n$a: 2px;\na {\n height: $a;\n}\n", + "a {\n height: 2px;\n}\n" + ); + test!( + variable_shadowing, + "$a: 1px;\n$b: $a;\na {\n height: $b;\n}\n", + "a {\n height: 1px;\n}\n" + ); + test!( + variable_shadowing_val_does_not_change, + "$a: 1px;\n$b: $a; $a: 2px;\na {\n height: $b;\n}\n", + "a {\n height: 1px;\n}\n" + ); + test!( + variable_shadowing_val_does_not_change_complex, + "a {\n color: red;\n}\n$y: before;\n$x: 1 2 $y;\n$y: after;\nfoo {\n a: $x;\n}", + "a {\n color: red;\n}\nfoo {\n a: 1 2 before;\n}\n" + ); + test!( + variable_whitespace, + "$a : 1px ;\na {\n height: $a;\n}\n", + "a {\n height: 1px;\n}\n" + ); + test!( + style_after_variable, + "$a: 1px;\na {\n height: $a;\n color: red;\n}\n", + "a {\n height: 1px;\n color: red;\n}\n" + ); + test!( + literal_and_variable_as_val, + "$a: 1px;\na {\n height: 1 $a;\n}\n", + "a {\n height: 1 1px;\n}\n" + ); + test!( + literal_and_variable_as_var, + "$a: 1px;\n$b: 1 $a;\na {\n height: $b;\n}\n", + "a {\n height: 1 1px;\n}\n" + ); +} + +#[cfg(test)] +mod css_selectors { + use super::StyleSheet; test!( selector_nesting_el_mul_el, "a, b {\n a, b {\n color: red\n}\n}\n", @@ -709,72 +760,7 @@ mod test_css { "a {\n :pseudo(a, b, c) {\n color: red;\n }\n}\n", "a :pseudo(a, b, c) {\n color: red;\n}\n" ); - - test!(basic_style, "a {\n color: red;\n}\n"); - test!(two_styles, "a {\n color: red;\n color: blue;\n}\n"); - test!( - two_inner_rulesets, - "a {\n b {\n color: red;\n}\n c {\n color: white;\n}\n}\n", - "a b {\n color: red;\n}\na c {\n color: white;\n}\n" - ); - test!( - two_rulesets, - "a {\n color: red;\n}\nc {\n color: white;\n}\n" - ); - test!( - two_inner_outer_rulesets, - "a {\n b {\n color: red;\n}\n c {\n color: white;\n}\n}\na {\n b {\n color: red;\n}\n c {\n color: white;\n}\n}\n", - "a b {\n color: red;\n}\na c {\n color: white;\n}\na b {\n color: red;\n}\na c {\n color: white;\n}\n" - ); test!(selector_mul, "a, b {\n color: red;\n}\n"); - test!( - removes_empty_outer_styles, - "a {\n b {\n color: red;\n }\n", - "a b {\n color: red;\n}\n" - ); - test!(removes_empty_styles, "a {}\n", ""); - test!( - doesnt_eat_style_after_ruleset, - "a {\n b {\n color: red;\n}\n color: blue;\n}\n", - "a {\n color: blue;\n}\na b {\n color: red;\n}\n" - ); - - test!( - removes_inner_comments, - "a {\n color: red/* hi */;\n}\n", - "a {\n color: red;\n}\n" - ); - test!( - removes_inner_comments_whitespace, - "a {\n color: red /* hi */;\n}\n", - "a {\n color: red;\n}\n" - ); - test!( - preserves_outer_comments_before, - "a {\n /* hi */\n color: red;\n}\n" - ); - test!( - preserves_outer_comments_after, - "a {\n color: red;\n /* hi */\n}\n" - ); - test!( - preserves_outer_comments_two, - "a {\n /* foo */\n /* bar */\n color: red;\n}\n" - ); - test!( - preserves_toplevel_comment_before, - "/* foo */\na {\n color: red;\n}\n" - ); - test!( - preserves_toplevel_comment_after, - "a {\n color: red;\n}\n/* foo */\n" - ); - test!( - removes_single_line_comment, - "// a { color: red }\na {\n height: 1 1px;\n}\n", - "a {\n height: 1 1px;\n}\n" - ); - test!( outer_ampersand, "a, b {\n& c {\n color: red;\n}\n}\n", @@ -825,6 +811,114 @@ mod test_css { "$a: foo;\nab#{$a} {\n color: red;\n}\n", "abfoo {\n color: red;\n}\n" ); + test!( + selector_whitespace, + " a > b , c ~ d e .f #g :h i.j [ k ] { color: red }", + "a > b, c ~ d e .f #g :h i.j [k] {\n color: red;\n}\n" + ); +} + +#[cfg(test)] +mod css_units { + use super::StyleSheet; + test!(unit_none, "a {\n height: 1;\n}\n"); + test!(unit_not_attached, "a {\n height: 1 px;\n}\n"); + test!(unit_px, "a {\n height: 1px;\n}\n"); + test!(unit_em, "a {\n height: 1em;\n}\n"); + test!(unit_rem, "a {\n height: 1rem;\n}\n"); + test!(unit_percent, "a {\n height: 1%;\n}\n"); +} + +#[cfg(test)] +mod css_comments { + use super::StyleSheet; + test!( + removes_inner_comments, + "a {\n color: red/* hi */;\n}\n", + "a {\n color: red;\n}\n" + ); + test!( + removes_inner_comments_whitespace, + "a {\n color: red /* hi */;\n}\n", + "a {\n color: red;\n}\n" + ); + test!( + preserves_outer_comments_before, + "a {\n /* hi */\n color: red;\n}\n" + ); + test!( + preserves_outer_comments_after, + "a {\n color: red;\n /* hi */\n}\n" + ); + test!( + preserves_outer_comments_two, + "a {\n /* foo */\n /* bar */\n color: red;\n}\n" + ); + test!( + preserves_toplevel_comment_before, + "/* foo */\na {\n color: red;\n}\n" + ); + test!( + preserves_toplevel_comment_after, + "a {\n color: red;\n}\n/* foo */\n" + ); + test!( + removes_single_line_comment, + "// a { color: red }\na {\n height: 1 1px;\n}\n", + "a {\n height: 1 1px;\n}\n" + ); +} + +#[cfg(test)] +mod css_styles { + use super::StyleSheet; + test!(basic_style, "a {\n color: red;\n}\n"); + test!(two_styles, "a {\n color: red;\n color: blue;\n}\n"); + test!( + two_inner_rulesets, + "a {\n b {\n color: red;\n}\n c {\n color: white;\n}\n}\n", + "a b {\n color: red;\n}\na c {\n color: white;\n}\n" + ); + test!( + two_rulesets, + "a {\n color: red;\n}\nc {\n color: white;\n}\n" + ); + test!( + two_inner_outer_rulesets, + "a {\n b {\n color: red;\n}\n c {\n color: white;\n}\n}\na {\n b {\n color: red;\n}\n c {\n color: white;\n}\n}\n", + "a b {\n color: red;\n}\na c {\n color: white;\n}\na b {\n color: red;\n}\na c {\n color: white;\n}\n" + ); + test!( + removes_empty_outer_styles, + "a {\n b {\n color: red;\n }\n", + "a b {\n color: red;\n}\n" + ); + test!(removes_empty_styles, "a {}\n", ""); + test!( + doesnt_eat_style_after_ruleset, + "a {\n b {\n color: red;\n}\n color: blue;\n}\n", + "a {\n color: blue;\n}\na b {\n color: red;\n}\n" + ); + test!( + multiline_style, + "a {\n color: red\n blue;\n}\n", + "a {\n color: red blue;\n}\n" + ); + test!(hyphenated_style_property, "a {\n font-family: Arial;\n}\n"); + test!(hyphenated_style_value, "a {\n color: Open-Sans;\n}\n"); + test!( + space_separated_style_value, + "a {\n border: solid red;\n}\n" + ); + test!(single_quoted_style_value, "a {\n font: 'Open-Sans';\n}\n"); + test!( + double_quoted_style_value, + "a {\n font: \"Open-Sans\";\n}\n" + ); + test!( + comma_style_value, + "a {\n font: Open-Sans, sans-serif;\n}\n" + ); test!( style_interpolation_start, "a {\n #{c}olor: red;\n}\n", @@ -845,7 +939,6 @@ mod test_css { "$a: foo;\na {\n co#{$a}lor: red;\n}\n", "a {\n cofoolor: red;\n}\n" ); - test!( style_val_interpolation_start, "a {\n color: #{r}ed;\n}\n", @@ -872,3 +965,39 @@ mod test_css { "a {\n color: red;\n}\n" ); } + +#[cfg(test)] +mod css_misc { + use super::*; + test!( + combines_hyphens, + "a {\n foo: bar - baz;\n}\n", + "a {\n foo: bar-baz;\n}\n" + ); + test!(does_not_combine_hyphens, "a {\n foo: bar -baz;\n}\n"); + test!( + ident_starts_with_hyphen, + "a {\n foo: -webkit-bar-baz;\n}\n" + ); + test!(ident_with_num, "el1 {\n a: b;\n}\n"); + test!(keyword_important, "a {\n height: 1 !important;\n}\n"); + test!( + keyword_important_uppercase, + "a {\n height: 1 !IMPORTANT;\n}\n", + "a {\n height: 1 !important;\n}\n" + ); + test!( + keyword_important_not_at_end, + "a {\n height: !important 1;\n}\n" + ); +} + +#[cfg(test)] +mod css_mixins { + use super::*; + test!( + basic_mixin, + "@mixin a {\n color: red;\n}\n\nb {\n @include a;\n}\n", + "b {\n color: red;\n}\n" + ); +} diff --git a/src/mixin.rs b/src/mixin.rs index d0b1b0a..a740b61 100644 --- a/src/mixin.rs +++ b/src/mixin.rs @@ -19,10 +19,11 @@ impl Mixin { let mut toks = self.body.iter().peekable(); let mut styles = Vec::new(); let mut value = Vec::new(); + dbg!(&self.body); while let Some(tok) = &toks.peek() { - dbg!(&tok.kind); match &tok.kind { - TokenKind::Symbol(Symbol::SemiColon) => { + TokenKind::Symbol(Symbol::SemiColon) + | TokenKind::Symbol(Symbol::CloseCurlyBrace) => { toks.next(); if let Ok(s) = Style::from_tokens(&value, &self.scope) { styles.push(s); @@ -34,7 +35,7 @@ impl Mixin { TokenKind::Variable(ref name) => { toks.next(); if let TokenKind::Symbol(Symbol::Colon) = - toks.peek().expect("expected something after variable").kind + toks.peek().expect("expected something after variable").kind { toks.next(); devour_whitespace(&mut toks);