increase code coverage
This commit is contained in:
parent
6cd208f41d
commit
743ad7a340
@ -263,7 +263,7 @@ impl Environment {
|
|||||||
for name in (*self.scopes.global_variables()).borrow().keys() {
|
for name in (*self.scopes.global_variables()).borrow().keys() {
|
||||||
if (*module).borrow().var_exists(*name) {
|
if (*module).borrow().var_exists(*name) {
|
||||||
return Err((
|
return Err((
|
||||||
format!("This module and the new module both define a variable named \"{}\".", name = name)
|
format!("This module and the new module both define a variable named \"{name}\".", name = name)
|
||||||
, span).into());
|
, span).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ impl<'a, 'c, P: StylesheetParser<'a>> ValueParser<'a, 'c, P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if value_parser.inside_bracketed_list {
|
if value_parser.inside_bracketed_list {
|
||||||
let start = parser.toks().cursor();
|
let bracket_start = parser.toks().cursor();
|
||||||
|
|
||||||
parser.expect_char('[')?;
|
parser.expect_char('[')?;
|
||||||
parser.whitespace()?;
|
parser.whitespace()?;
|
||||||
@ -71,14 +71,12 @@ impl<'a, 'c, P: StylesheetParser<'a>> ValueParser<'a, 'c, P> {
|
|||||||
separator: ListSeparator::Undecided,
|
separator: ListSeparator::Undecided,
|
||||||
brackets: Brackets::Bracketed,
|
brackets: Brackets::Bracketed,
|
||||||
})
|
})
|
||||||
.span(parser.toks_mut().span_from(start)));
|
.span(parser.toks_mut().span_from(bracket_start)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(start)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
value_parser.start = parser.toks().cursor();
|
||||||
|
|
||||||
value_parser.single_expression = Some(value_parser.parse_single_expression(parser)?);
|
value_parser.single_expression = Some(value_parser.parse_single_expression(parser)?);
|
||||||
|
|
||||||
let mut value = value_parser.parse_value(parser)?;
|
let mut value = value_parser.parse_value(parser)?;
|
||||||
@ -392,6 +390,7 @@ impl<'a, 'c, P: StylesheetParser<'a>> ValueParser<'a, 'c, P> {
|
|||||||
self.reset_state(parser)?;
|
self.reset_state(parser)?;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// todo: does this branch ever get hit
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.single_expression.is_none() {
|
if self.single_expression.is_none() {
|
||||||
@ -400,7 +399,7 @@ impl<'a, 'c, P: StylesheetParser<'a>> ValueParser<'a, 'c, P> {
|
|||||||
|
|
||||||
self.resolve_space_expressions(parser)?;
|
self.resolve_space_expressions(parser)?;
|
||||||
|
|
||||||
// [resolveSpaceExpressions can modify [singleExpression_], but it
|
// [resolveSpaceExpressions] can modify [singleExpression_], but it
|
||||||
// can't set it to null`.
|
// can't set it to null`.
|
||||||
self.comma_expressions
|
self.comma_expressions
|
||||||
.get_or_insert_with(Default::default)
|
.get_or_insert_with(Default::default)
|
||||||
@ -1368,62 +1367,6 @@ impl<'a, 'c, P: StylesheetParser<'a>> ValueParser<'a, 'c, P> {
|
|||||||
.span(span))
|
.span(span))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_parse_url_contents(
|
|
||||||
parser: &mut P,
|
|
||||||
name: Option<String>,
|
|
||||||
) -> SassResult<Option<Interpolation>> {
|
|
||||||
let start = parser.toks().cursor();
|
|
||||||
|
|
||||||
if !parser.scan_char('(') {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
parser.whitespace_without_comments();
|
|
||||||
|
|
||||||
// Match Ruby Sass's behavior: parse a raw URL() if possible, and if not
|
|
||||||
// backtrack and re-parse as a function expression.
|
|
||||||
let mut buffer = Interpolation::new();
|
|
||||||
buffer.add_string(name.unwrap_or_else(|| "url".to_owned()));
|
|
||||||
buffer.add_char('(');
|
|
||||||
|
|
||||||
while let Some(next) = parser.toks().peek() {
|
|
||||||
match next.kind {
|
|
||||||
'\\' => {
|
|
||||||
buffer.add_string(parser.parse_escape(false)?);
|
|
||||||
}
|
|
||||||
'!' | '%' | '&' | '*'..='~' | '\u{80}'..=char::MAX => {
|
|
||||||
parser.toks_mut().next();
|
|
||||||
buffer.add_char(next.kind);
|
|
||||||
}
|
|
||||||
'#' => {
|
|
||||||
if matches!(parser.toks().peek_n(1), Some(Token { kind: '{', .. })) {
|
|
||||||
buffer.add_interpolation(parser.parse_single_interpolation()?);
|
|
||||||
} else {
|
|
||||||
parser.toks_mut().next();
|
|
||||||
buffer.add_char(next.kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
')' => {
|
|
||||||
parser.toks_mut().next();
|
|
||||||
buffer.add_char(next.kind);
|
|
||||||
|
|
||||||
return Ok(Some(buffer));
|
|
||||||
}
|
|
||||||
' ' | '\t' | '\n' | '\r' => {
|
|
||||||
parser.whitespace_without_comments();
|
|
||||||
|
|
||||||
if !parser.toks().next_char_is(')') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parser.toks_mut().set_cursor(start);
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn try_parse_special_function(
|
pub(crate) fn try_parse_special_function(
|
||||||
parser: &mut P,
|
parser: &mut P,
|
||||||
name: &str,
|
name: &str,
|
||||||
@ -1466,15 +1409,13 @@ impl<'a, 'c, P: StylesheetParser<'a>> ValueParser<'a, 'c, P> {
|
|||||||
buffer.add_char('(');
|
buffer.add_char('(');
|
||||||
}
|
}
|
||||||
"url" => {
|
"url" => {
|
||||||
return Ok(
|
return Ok(parser.try_url_contents(None)?.map(|contents| {
|
||||||
ValueParser::try_parse_url_contents(parser, None)?.map(|contents| {
|
AstExpr::String(
|
||||||
AstExpr::String(
|
StringExpr(contents, QuoteKind::None),
|
||||||
StringExpr(contents, QuoteKind::None),
|
parser.toks_mut().span_from(start),
|
||||||
parser.toks_mut().span_from(start),
|
)
|
||||||
)
|
.span(parser.toks_mut().span_from(start))
|
||||||
.span(parser.toks_mut().span_from(start))
|
}))
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
_ => return Ok(None),
|
_ => return Ok(None),
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,6 @@ pub(crate) fn as_hex(c: char) -> u32 {
|
|||||||
'0'..='9' => c as u32 - '0' as u32,
|
'0'..='9' => c as u32 - '0' as u32,
|
||||||
'A'..='F' => 10 + c as u32 - 'A' as u32,
|
'A'..='F' => 10 + c as u32 - 'A' as u32,
|
||||||
'a'..='f' => 10 + c as u32 - 'a' as u32,
|
'a'..='f' => 10 + c as u32 - 'a' as u32,
|
||||||
_ => panic!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,7 +285,7 @@ impl<V: fmt::Debug + Clone> MapView for MergedMapView<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panic!("New entries may not be added to MergedMapView")
|
unreachable!("New entries may not be added to MergedMapView")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keys(&self) -> Vec<Identifier> {
|
fn keys(&self) -> Vec<Identifier> {
|
||||||
|
@ -55,26 +55,8 @@ impl PartialEq for Value {
|
|||||||
Value::String(s2, ..) => s1 == s2,
|
Value::String(s2, ..) => s1 == s2,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
Value::Dimension(SassNumber {
|
Value::Dimension(n1) => match other {
|
||||||
num: n,
|
Value::Dimension(n2) => n1 == n2,
|
||||||
unit,
|
|
||||||
as_slash: _,
|
|
||||||
}) => match other {
|
|
||||||
Value::Dimension(SassNumber {
|
|
||||||
num: n2,
|
|
||||||
unit: unit2,
|
|
||||||
as_slash: _,
|
|
||||||
}) => {
|
|
||||||
if !unit.comparable(unit2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*unit2 == Unit::None || *unit == Unit::None) && unit != unit2 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*n == n2.convert(unit2, unit)
|
|
||||||
}
|
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
Value::List(list1, sep1, brackets1) => match other {
|
Value::List(list1, sep1, brackets1) => match other {
|
||||||
|
@ -189,10 +189,20 @@ impl SassNumber {
|
|||||||
|
|
||||||
impl PartialEq for SassNumber {
|
impl PartialEq for SassNumber {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.num == other.num && self.unit == other.unit
|
if !self.unit.comparable(&other.unit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (other.unit == Unit::None || self.unit == Unit::None) && self.unit != other.unit {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.num == other.num.convert(&other.unit, &self.unit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Eq for SassNumber {}
|
||||||
|
|
||||||
impl Add<SassNumber> for SassNumber {
|
impl Add<SassNumber> for SassNumber {
|
||||||
type Output = SassNumber;
|
type Output = SassNumber;
|
||||||
fn add(self, rhs: SassNumber) -> Self::Output {
|
fn add(self, rhs: SassNumber) -> Self::Output {
|
||||||
@ -285,5 +295,3 @@ impl Div<SassNumber> for SassNumber {
|
|||||||
self.multiply_units(self.num.0 / rhs.num.0, rhs.unit.invert())
|
self.multiply_units(self.num.0 / rhs.num.0, rhs.unit.invert())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for SassNumber {}
|
|
||||||
|
@ -262,6 +262,15 @@ test!(
|
|||||||
}",
|
}",
|
||||||
"@unknown {\n .bar {\n a: b;\n }\n}\n"
|
"@unknown {\n .bar {\n a: b;\n }\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
query_begins_with_interpolation,
|
||||||
|
"a {
|
||||||
|
@at-root (#{wi}th: rule) {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}",
|
||||||
|
"a {\n color: red;\n}\n"
|
||||||
|
);
|
||||||
error!(
|
error!(
|
||||||
missing_closing_curly_brace,
|
missing_closing_curly_brace,
|
||||||
"@at-root {", "Error: expected \"}\"."
|
"@at-root {", "Error: expected \"}\"."
|
||||||
|
@ -635,3 +635,26 @@ error!(
|
|||||||
single_arg_saturate_expects_number,
|
single_arg_saturate_expects_number,
|
||||||
"a {\n color: saturate(red);\n}\n", "Error: $amount: red is not a number."
|
"a {\n color: saturate(red);\n}\n", "Error: $amount: red is not a number."
|
||||||
);
|
);
|
||||||
|
error!(
|
||||||
|
hex_color_starts_with_number_non_hex_digit_at_position_2,
|
||||||
|
"a {\n color: #0zz;\n}\n", "Error: Expected hex digit."
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
hex_color_starts_with_number_non_hex_digit_at_position_3,
|
||||||
|
"a {\n color: #00z;\n}\n", "Error: Expected hex digit."
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
hex_color_starts_with_number_non_hex_digit_at_position_4,
|
||||||
|
"a {\n color: #000z;\n}\n",
|
||||||
|
"a {\n color: #000 z;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
#[ignore = "we don't emit 4 character hex colors correctly"]
|
||||||
|
hex_color_starts_with_number_non_hex_digit_at_position_5,
|
||||||
|
"a {\n color: #0000z;\n}\n",
|
||||||
|
"a {\n color: rgba(0, 0, 0, 0) z;\n}\n"
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
hex_color_starts_with_number_non_hex_digit_at_position_6,
|
||||||
|
"a {\n color: #00000z;\n}\n", "Error: Expected hex digit."
|
||||||
|
);
|
||||||
|
@ -170,3 +170,4 @@ test!(
|
|||||||
"a {/**/}",
|
"a {/**/}",
|
||||||
"a { /**/ }\n"
|
"a { /**/ }\n"
|
||||||
);
|
);
|
||||||
|
test!(silent_comment_as_child, "a {\n// silent\n}\n", "");
|
||||||
|
@ -267,3 +267,10 @@ test!(
|
|||||||
}",
|
}",
|
||||||
"a {\n color: true;\n}\n"
|
"a {\n color: true;\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
calculation_equality_converts_units,
|
||||||
|
"a {
|
||||||
|
color: calc(1in + 1rem) == calc(2.54cm + 1rem);
|
||||||
|
}",
|
||||||
|
"a {\n color: true;\n}\n"
|
||||||
|
);
|
||||||
|
@ -273,3 +273,7 @@ error!(
|
|||||||
nothing_after_dot_in_value_preceded_by_minus_sign,
|
nothing_after_dot_in_value_preceded_by_minus_sign,
|
||||||
"a { color: -.", "Error: Expected digit."
|
"a { color: -.", "Error: Expected digit."
|
||||||
);
|
);
|
||||||
|
error!(
|
||||||
|
nothing_after_bang_in_space_separated_list,
|
||||||
|
"a { color: a !", r#"Error: Expected "important"."#
|
||||||
|
);
|
||||||
|
@ -409,6 +409,13 @@ test!(
|
|||||||
}",
|
}",
|
||||||
"a {\n color: before;\n}\n"
|
"a {\n color: before;\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
can_parse_module_variable_declaration,
|
||||||
|
"@function foo() {
|
||||||
|
foo.$bar: red;
|
||||||
|
}",
|
||||||
|
""
|
||||||
|
);
|
||||||
error!(
|
error!(
|
||||||
function_no_return,
|
function_no_return,
|
||||||
"@function foo() {}
|
"@function foo() {}
|
||||||
|
@ -523,6 +523,72 @@ test!(
|
|||||||
);
|
);
|
||||||
error!(unclosed_single_quote, r#"@import '"#, "Error: Expected '.");
|
error!(unclosed_single_quote, r#"@import '"#, "Error: Expected '.");
|
||||||
error!(unclosed_double_quote, r#"@import ""#, "Error: Expected \".");
|
error!(unclosed_double_quote, r#"@import ""#, "Error: Expected \".");
|
||||||
|
error!(
|
||||||
|
dynamic_disallowed_inside_if,
|
||||||
|
r#"@if true {
|
||||||
|
@import "foo";
|
||||||
|
}"#,
|
||||||
|
"Error: This at-rule is not allowed here."
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
dynamic_disallowed_inside_while,
|
||||||
|
r#"@while true {
|
||||||
|
@import "foo";
|
||||||
|
}"#,
|
||||||
|
"Error: This at-rule is not allowed here."
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
dynamic_disallowed_inside_for,
|
||||||
|
r#"@for $i from 0 through 1 {
|
||||||
|
@import "foo";
|
||||||
|
}"#,
|
||||||
|
"Error: This at-rule is not allowed here."
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
dynamic_disallowed_inside_each,
|
||||||
|
r#"@each $i in a {
|
||||||
|
@import "foo";
|
||||||
|
}"#,
|
||||||
|
"Error: This at-rule is not allowed here."
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
static_allowed_inside_if,
|
||||||
|
r#"@if true {
|
||||||
|
@import "foo.css";
|
||||||
|
}"#,
|
||||||
|
"@import \"foo.css\";\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
static_allowed_inside_while,
|
||||||
|
r#"
|
||||||
|
$a: 0;
|
||||||
|
@while $a == 0 {
|
||||||
|
@import "foo.css";
|
||||||
|
$a: 1;
|
||||||
|
}"#,
|
||||||
|
"@import \"foo.css\";\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
static_allowed_inside_for,
|
||||||
|
r#"@for $i from 0 to 1 {
|
||||||
|
@import "foo.css";
|
||||||
|
}"#,
|
||||||
|
"@import \"foo.css\";\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
static_allowed_inside_each,
|
||||||
|
r#"@each $i in a {
|
||||||
|
@import "foo.css";
|
||||||
|
}"#,
|
||||||
|
"@import \"foo.css\";\n"
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
dynamic_disallowed_inside_mixin,
|
||||||
|
r#"@mixin foo {
|
||||||
|
@import "foo";
|
||||||
|
}"#,
|
||||||
|
"Error: This at-rule is not allowed here."
|
||||||
|
);
|
||||||
|
|
||||||
// todo: edge case tests for plain css imports moved to top
|
// todo: edge case tests for plain css imports moved to top
|
||||||
// todo: test for calling paths, e.g. `grass b\index.scss`
|
// todo: test for calling paths, e.g. `grass b\index.scss`
|
||||||
|
@ -412,6 +412,26 @@ test!(
|
|||||||
"a {\n color: [null];\n}\n",
|
"a {\n color: [null];\n}\n",
|
||||||
"a {\n color: [];\n}\n"
|
"a {\n color: [];\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
space_separated_bracketed_list_in_parens,
|
||||||
|
"a {\n color: ([a b]);\n}\n",
|
||||||
|
"a {\n color: [a b];\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
does_not_eval_division_inside_space_separated_bracketed_list_in_parens,
|
||||||
|
"a {\n color: ([1/2 1/2]);\n}\n",
|
||||||
|
"a {\n color: [1/2 1/2];\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
comma_separated_bracketed_list_in_parens,
|
||||||
|
"a {\n color: ([a, b]);\n}\n",
|
||||||
|
"a {\n color: [a, b];\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
does_not_eval_division_inside_comma_separated_bracketed_list_in_parens,
|
||||||
|
"a {\n color: ([1/2, 1/2]);\n}\n",
|
||||||
|
"a {\n color: [1/2, 1/2];\n}\n"
|
||||||
|
);
|
||||||
test!(
|
test!(
|
||||||
comma_separated_list_has_element_beginning_with_capital_A,
|
comma_separated_list_has_element_beginning_with_capital_A,
|
||||||
"a {\n color: a, A, \"Noto Color Emoji\";\n}\n",
|
"a {\n color: a, A, \"Noto Color Emoji\";\n}\n",
|
||||||
|
25
tests/map.rs
25
tests/map.rs
@ -280,6 +280,27 @@ test!(
|
|||||||
"a {\n color: (a: b)==(a: c);\n}\n",
|
"a {\n color: (a: b)==(a: c);\n}\n",
|
||||||
"a {\n color: false;\n}\n"
|
"a {\n color: false;\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
important_as_key,
|
||||||
|
"a {\n color: inspect((a: b, !important: c));\n}\n",
|
||||||
|
"a {\n color: (a: b, !important: c);\n}\n"
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
bang_identifier_not_important_as_key,
|
||||||
|
"a {\n color: inspect((a: b, !a: c));\n}\n", r#"Error: expected ")"."#
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
bang_identifier_not_important_but_starts_with_i_as_key,
|
||||||
|
"a {\n color: inspect((a: b, !i: c));\n}\n", r#"Error: Expected "important"."#
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
bang_identifier_not_important_ascii_whitespace_as_key,
|
||||||
|
"a {\n color: inspect((a: b, ! : c));\n}\n", r#"Error: Expected "important"."#
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
bang_identifier_not_important_loud_comment_as_key,
|
||||||
|
"a {\n color: inspect((a: b, !/**/: c));\n}\n", r#"Error: expected ")"."#
|
||||||
|
);
|
||||||
test!(
|
test!(
|
||||||
empty_with_single_line_comments,
|
empty_with_single_line_comments,
|
||||||
"$foo: (\n \n // :/a.b\n \n );
|
"$foo: (\n \n // :/a.b\n \n );
|
||||||
@ -314,3 +335,7 @@ error!(
|
|||||||
denies_comma_separated_list_without_parens_as_key,
|
denies_comma_separated_list_without_parens_as_key,
|
||||||
"$map: (a: 1, b, c, d: e);", "Error: expected \":\"."
|
"$map: (a: 1, b, c, d: e);", "Error: expected \":\"."
|
||||||
);
|
);
|
||||||
|
error!(
|
||||||
|
nothing_after_first_comma,
|
||||||
|
"$map: (a: b,", "Error: expected \")\"."
|
||||||
|
);
|
||||||
|
@ -570,6 +570,17 @@ test!(
|
|||||||
}"#,
|
}"#,
|
||||||
"@media (min-width: \\0 ) {\n a {\n color: red;\n }\n}\n"
|
"@media (min-width: \\0 ) {\n a {\n color: red;\n }\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
simple_unmergeable,
|
||||||
|
"a {
|
||||||
|
@media a {
|
||||||
|
@media b {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}",
|
||||||
|
""
|
||||||
|
);
|
||||||
error!(
|
error!(
|
||||||
media_query_has_quoted_closing_paren,
|
media_query_has_quoted_closing_paren,
|
||||||
r#"@media ('a)'w) {
|
r#"@media ('a)'w) {
|
||||||
|
@ -35,6 +35,32 @@ test!(
|
|||||||
"a {\n color: 1 or 2;\n}\n",
|
"a {\n color: 1 or 2;\n}\n",
|
||||||
grass::Options::default().input_syntax(InputSyntax::Css)
|
grass::Options::default().input_syntax(InputSyntax::Css)
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
simple_calculation,
|
||||||
|
"a {
|
||||||
|
color: calc(1 + 1);
|
||||||
|
}",
|
||||||
|
"a {\n color: 2;\n}\n",
|
||||||
|
grass::Options::default().input_syntax(InputSyntax::Css)
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
simple_url_import,
|
||||||
|
r#"@import url("foo");"#,
|
||||||
|
"@import url(\"foo\");\n",
|
||||||
|
grass::Options::default().input_syntax(InputSyntax::Css)
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
import_no_file_extension,
|
||||||
|
r#"@import "foo";"#,
|
||||||
|
"@import \"foo\";\n",
|
||||||
|
grass::Options::default().input_syntax(InputSyntax::Css)
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
import_with_condition,
|
||||||
|
r#"@import "foo" screen and (foo: bar);"#,
|
||||||
|
"@import \"foo\" screen and (foo: bar);\n",
|
||||||
|
grass::Options::default().input_syntax(InputSyntax::Css)
|
||||||
|
);
|
||||||
test!(
|
test!(
|
||||||
does_not_evaluate_not,
|
does_not_evaluate_not,
|
||||||
"a {
|
"a {
|
||||||
@ -155,6 +181,14 @@ error!(
|
|||||||
"Error: Operators aren't allowed in plain CSS.",
|
"Error: Operators aren't allowed in plain CSS.",
|
||||||
grass::Options::default().input_syntax(InputSyntax::Css)
|
grass::Options::default().input_syntax(InputSyntax::Css)
|
||||||
);
|
);
|
||||||
|
error!(
|
||||||
|
disallows_interpolation,
|
||||||
|
"a {
|
||||||
|
color: a#{b}c;
|
||||||
|
}",
|
||||||
|
"Error: Interpolation isn't allowed in plain CSS.",
|
||||||
|
grass::Options::default().input_syntax(InputSyntax::Css)
|
||||||
|
);
|
||||||
test!(
|
test!(
|
||||||
allows_rgb_function,
|
allows_rgb_function,
|
||||||
"a {
|
"a {
|
||||||
@ -163,3 +197,13 @@ test!(
|
|||||||
"a {\n color: rgb(true, a, b);\n}\n",
|
"a {\n color: rgb(true, a, b);\n}\n",
|
||||||
grass::Options::default().input_syntax(InputSyntax::Css)
|
grass::Options::default().input_syntax(InputSyntax::Css)
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
simple_supports,
|
||||||
|
"@supports (foo) {
|
||||||
|
a {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}",
|
||||||
|
"@supports (foo) {\n a {\n color: red;\n }\n}\n",
|
||||||
|
grass::Options::default().input_syntax(InputSyntax::Css)
|
||||||
|
);
|
||||||
|
@ -81,6 +81,18 @@ test!(
|
|||||||
"/* loud */\n",
|
"/* loud */\n",
|
||||||
grass::Options::default().input_syntax(InputSyntax::Sass)
|
grass::Options::default().input_syntax(InputSyntax::Sass)
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
special_mixin_and_include_characters,
|
||||||
|
r#"
|
||||||
|
=foo
|
||||||
|
color: red
|
||||||
|
|
||||||
|
a
|
||||||
|
+foo
|
||||||
|
"#,
|
||||||
|
"a {\n color: red;\n}\n",
|
||||||
|
grass::Options::default().input_syntax(InputSyntax::Sass)
|
||||||
|
);
|
||||||
error!(
|
error!(
|
||||||
multiline_comment_in_value_position,
|
multiline_comment_in_value_position,
|
||||||
r#"
|
r#"
|
||||||
@ -90,3 +102,15 @@ loud */ red
|
|||||||
"Error: expected */.",
|
"Error: expected */.",
|
||||||
grass::Options::default().input_syntax(InputSyntax::Sass)
|
grass::Options::default().input_syntax(InputSyntax::Sass)
|
||||||
);
|
);
|
||||||
|
error!(
|
||||||
|
document_starts_with_spaces,
|
||||||
|
r#" "#,
|
||||||
|
"Error: Indenting at the beginning of the document is illegal.",
|
||||||
|
grass::Options::default().input_syntax(InputSyntax::Sass)
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
document_starts_with_tab,
|
||||||
|
"\t",
|
||||||
|
"Error: Indenting at the beginning of the document is illegal.",
|
||||||
|
grass::Options::default().input_syntax(InputSyntax::Sass)
|
||||||
|
);
|
||||||
|
@ -927,6 +927,10 @@ error!(
|
|||||||
denies_optional_in_selector,
|
denies_optional_in_selector,
|
||||||
"a !optional {}", "Error: expected \"{\"."
|
"a !optional {}", "Error: expected \"{\"."
|
||||||
);
|
);
|
||||||
|
error!(
|
||||||
|
child_selector_starts_with_forward_slash,
|
||||||
|
"a { /b { } }", "Error: expected selector."
|
||||||
|
);
|
||||||
|
|
||||||
// todo:
|
// todo:
|
||||||
// [attr=url] {
|
// [attr=url] {
|
||||||
|
@ -276,6 +276,30 @@ test!(
|
|||||||
"a {\n color: calc(1dpi + 1dppx);\n}\n",
|
"a {\n color: calc(1dpi + 1dppx);\n}\n",
|
||||||
"a {\n color: 97dpi;\n}\n"
|
"a {\n color: 97dpi;\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
ternary_inside_calc,
|
||||||
|
"a {\n color: calc(if(true, 1, unit(foo)));\n}\n",
|
||||||
|
"a {\n color: 1;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
retains_parens_around_var_in_calc,
|
||||||
|
"a {\n color: calc((var(--a)) + 1rem);\n}\n",
|
||||||
|
"a {\n color: calc((var(--a)) + 1rem);\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
removes_superfluous_parens_around_function_call_in_calc,
|
||||||
|
"a {\n color: calc((foo(--a)) + 1rem);\n}\n",
|
||||||
|
"a {\n color: calc(foo(--a) + 1rem);\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
calculation_inside_calc,
|
||||||
|
"a {\n color: calc(calc(1px + 1rem) * calc(2px - 2in));\n}\n",
|
||||||
|
"a {\n color: calc((1px + 1rem) * -190px);\n}\n"
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
escaped_close_paren_inside_calc,
|
||||||
|
"a {\n color: calc(\\));\n}\n", r#"Error: Expected "(" or "."."#
|
||||||
|
);
|
||||||
error!(
|
error!(
|
||||||
nothing_after_last_arg,
|
nothing_after_last_arg,
|
||||||
"a { color: calc(1 + 1", r#"Error: expected "+", "-", "*", "/", or ")"."#
|
"a { color: calc(1 + 1", r#"Error: expected "+", "-", "*", "/", or ")"."#
|
||||||
|
@ -21,6 +21,31 @@ test!(
|
|||||||
"a {\n color: u+27a;\n}\n",
|
"a {\n color: u+27a;\n}\n",
|
||||||
"a {\n color: u+27a;\n}\n"
|
"a {\n color: u+27a;\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
second_element_in_list,
|
||||||
|
"a {\n color: a u+55;\n}\n",
|
||||||
|
"a {\n color: a u+55;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
escaped_lowercase_u,
|
||||||
|
"a {\n color: \\75+55;\n}\n",
|
||||||
|
"a {\n color: u55;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
escaped_uppercase_u,
|
||||||
|
"a {\n color: \\55+55;\n}\n",
|
||||||
|
"a {\n color: U55;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
escaped_lowercase_u_with_space_after_escape,
|
||||||
|
"a {\n color: \\75 +55;\n}\n",
|
||||||
|
"a {\n color: u55;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
escaped_uppercase_u_with_space_after_escape,
|
||||||
|
"a {\n color: \\55 +55;\n}\n",
|
||||||
|
"a {\n color: U55;\n}\n"
|
||||||
|
);
|
||||||
error!(
|
error!(
|
||||||
interpolated_range,
|
interpolated_range,
|
||||||
"a {\n color: U+2A#{70}C;\n}\n", "Error: Expected end of identifier."
|
"a {\n color: U+2A#{70}C;\n}\n", "Error: Expected end of identifier."
|
||||||
@ -37,6 +62,19 @@ error!(
|
|||||||
length_of_6_with_question_mark,
|
length_of_6_with_question_mark,
|
||||||
"a {\n color: U+123456?;\n}\n", "Error: Expected at most 6 digits."
|
"a {\n color: U+123456?;\n}\n", "Error: Expected at most 6 digits."
|
||||||
);
|
);
|
||||||
|
error!(
|
||||||
// todo: escaped u at start \75 and \55
|
nothing_after_plus_lowercase,
|
||||||
// with and without space
|
"a {\n color: u+;\n}\n", r#"Error: Expected hex digit or "?"."#
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
nothing_after_plus_uppercase,
|
||||||
|
"a {\n color: U+;\n}\n", r#"Error: Expected hex digit or "?"."#
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
second_part_of_range_is_empty,
|
||||||
|
"a {\n color: u+55-;\n}\n", r#"Error: Expected hex digit."#
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
second_part_of_range_is_more_than_6_chars,
|
||||||
|
"a {\n color: u+55-1234567;\n}\n", r#"Error: Expected at most 6 digits."#
|
||||||
|
);
|
||||||
|
@ -171,6 +171,11 @@ test!(
|
|||||||
"a {\n color: url(#);\n}\n",
|
"a {\n color: url(#);\n}\n",
|
||||||
"a {\n color: url(#);\n}\n"
|
"a {\n color: url(#);\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
escaped_close_paren,
|
||||||
|
"a {\n color: url(\\));\n}\n",
|
||||||
|
"a {\n color: url(\\));\n}\n"
|
||||||
|
);
|
||||||
error!(
|
error!(
|
||||||
url_nothing_after_forward_slash_in_interpolation,
|
url_nothing_after_forward_slash_in_interpolation,
|
||||||
"a { color: url(#{/", "Error: Expected expression."
|
"a { color: url(#{/", "Error: Expected expression."
|
||||||
|
Loading…
x
Reference in New Issue
Block a user