blob: c04fb08f6c2c478a4fb9ed6babe03dc6028981b2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.css.lib;
import javax.swing.text.BadLocationException;
import org.netbeans.modules.css.lib.api.*;
import org.netbeans.modules.parsing.spi.ParseException;
/**
*
* @author marekfukala
*/
public class Css3ParserScssTest extends CssTestBase {
public Css3ParserScssTest(String testName) {
super(testName);
}
@Override
protected void setUp() throws Exception {
super.setUp();
setScssSource();
}
@Override
protected void tearDown() throws Exception {
setPlainSource();
}
public void testAllANTLRRulesHaveNodeTypes() {
for (String rule : Css3Parser.ruleNames) {
if (!rule.startsWith("synpred") && !rule.toLowerCase().endsWith("predicate")) {
assertNotNull(NodeType.valueOf(rule));
}
}
}
public void testDisabledScssSupport() {
try {
ExtCss3Parser.isScssSource_unit_tests = false;
String source = "$color: #4D926F;\n"
+ "\n"
+ "#header {\n"
+ " color: $color;\n"
+ "}\n"
+ "h2 {\n"
+ " color: $color;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
//there must be some css parsing errors as the less support is disabled
assertTrue(result.getDiagnostics().size() > 0);
} finally {
ExtCss3Parser.isScssSource_unit_tests = true;
}
}
public void testVariable() {
String source = "$color: #4D926F;\n"
+ "\n"
+ "#header {\n"
+ " color: $color;\n"
+ "}\n"
+ "h2 {\n"
+ " color: $color;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testVariable2() {
String source = "#header {\n"
+ " border: 2px $color solid;\n"
+ "}\n";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testVariableAsPropertyName() {
String source = ".class {\n"
+ " $var: 2;\n"
+ " three: $var;\n"
+ " $var: 3;\n"
+ " }";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testFunction() {
String source
= "#header {\n"
+ " color: ($base-color * 3);\n"
+ " border-left: $the-border;\n"
+ " border-right: ($the-border * 2);\n"
+ "}\n";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testFunction2() {
String source
= "#footer {\n"
+ " border-color: desaturate($red, 10%);\n"
+ " color: ($base-color + #003300);\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testMixinDeclaration() {
String source
= "@mixin rounded-corners ($radius: 5px) {\n"
+ " -webkit-border-radius: $radius;\n"
+ " -moz-border-radius: $radius;\n"
+ " -ms-border-radius: $radius;\n"
+ " -o-border-radius: $radius;\n"
+ " border-radius: $radius;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testMixinDeclaration2() {
String source
= "@mixin box-shadow ($x: 0, $y: 0, $blur: 1px, $color: #000) {\n"
+ " box-shadow: $arguments;\n"
+ " -moz-box-shadow: $arguments;\n"
+ " -webkit-box-shadow: $arguments;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testMixinDeclarationWithoutParams() {
String source
= "@mixin box-shadow {\n"
+ " box-shadow: $arguments;\n"
+ " -moz-box-shadow: $arguments;\n"
+ " -webkit-box-shadow: $arguments;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
//
// public void testMixinDeclarationAdvancedArguments() {
// String source =
// ".mixin1 (...) {}"
// + ".mixin2 () {}"
// + ".mixin3 (@a: 1) {}"
// + ".mixin4 (@a: 1, ...) {}"
// + ".mixin5 (@a, ...) {}";
// ;
//
// public void testGuardedMixins() {
// String source =
// ".mixin (@a) when (@a > 10), (@a = -10) {\n"
// + " background-color: black;\n"
// + "}";
// ;
//
// CssParserResult result = TestUtil.parse(source);
//
//// NodeUtil.dumpTree(result.getParseTree());
// assertResultOK(result);
// }
//
// public void testGuardedMixins2() {
// String source =
// ".truth (@a) when (@a) { }\n"
// + ".truth (@a) when (@a = true) { }\n"
// + ".mixin (@a) when (@media = mobile) { } \n";
// ;
//
// CssParserResult result = TestUtil.parse(source);
//
//// NodeUtil.dumpTree(result.getParseTree());
// assertResultOK(result);
// }
//
// public void testGuardedMixinIsFunction() {
// String source =
// ".mixin (@a, @b: 0) when (isnumber(@b)) { }\n";
// ;
//
// CssParserResult result = TestUtil.parse(source);
//
// NodeUtil.dumpTree(result.getParseTree());
// assertResultOK(result);
// }
//
// public void testGuardedMixinNotOperator() {
// String source =
// ".mixin (@b) when not (@b > 0) { }\n";
// ;
//
// CssParserResult result = TestUtil.parse(source);
//
//// NodeUtil.dumpTree(result.getParseTree());
// assertResultOK(result);
// }
//
public void testMixinCall() {
String source
= ".class {\n"
+ " @include mixin($switch, #888);\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testMixinCall2() {
String source
= "#menu a {\n"
+ " color: #111;\n"
+ " @include bordered;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testFunctions() {
String source = ".class {\n"
+ " width: percentage(0.5);\n"
+ " color: saturate($base, 5%);\n"
+ " background-color: spin(lighten($base, 25%), 8);\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testFunctions2() {
String source = "#navbar {\n"
+ " $navbar-width: 800px;\n"
+ " $items: 5;\n"
+ " $navbar-color: #ce4dd6;\n"
+ "\n"
+ " width: $navbar-width;\n"
+ " border-bottom: 2px solid $navbar-color;\n"
+ "\n"
+ " li {\n"
+ " float: left;\n"
+ " width: $navbar-width/$items - 10px;\n"
+ "\n"
+ " background-color:\n"
+ " lighten($navbar-color, 20%);\n"
+ " &:hover {\n"
+ " background-color:\n"
+ " lighten($navbar-color, 10%);\n"
+ " }\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testRulesNesting() {
String source = "#header {\n"
+ " color: black;\n"
+ " @mixin navigation {\n"
+ " font-size: 12px;\n"
+ " }\n"
+ " font-size: 10px;\n"
+ " @mixin navigation($a) {\n"
+ " font-size: 12px;\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testAmpCombinatorInNestedRules() {
String source = "#header { color: black;\n"
+ " .navigation { font-size: 12px; }\n"
+ " .logo { width: 300px;\n"
+ " &:hover { text-decoration: none; }\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testAmpCombinatorInNestedRules2() {
String source = ".shape{\n"
+ " &:hover{ \n"
+ " background:$lightRed; \n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testNestedRules() {
String source = "#header{\n"
+ " /* #header styles */\n"
+ " h1{\n"
+ " /* #header h1 styles */\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testOperationsInVariableDeclaration() {
String source = "$darkBlue: $lightBlue - #555;";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testLessExpressionNotInParens() {
String source = "div {"
+ "width: $pageWidth * .75;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testMixinCallWithoutParams() {
String source = "#shape1{ @include mymixin; }";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testPropertyValueWithParenthesis() {
String source = "div {\n"
+ "width: ($u * $unit) - (($margin * 2) + $gpadding + $gborder);\n "
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testPropertyValue() {
String source = "div {\n"
+ "border-top: 1px solid $color1 - #222; "
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testInterpolationInClassSelector() {
String source
= ".rounded-#{$vert}-#{$horz} {\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testInterpolationInIdSelector() {
String source
= ".navb#{$navbar}ar {\n"
+ " $navbar-width: 800px;"
+ "}\n";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testInterpolationInPropertyName() {
String source
= ".rounded {\n"
+ " border-#{$vert}-#{$horz}-radius: $radius;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testInterpolationExpressionInSelectorWithWS() {
String source
= ".body.firefox #{$selector}:before {\n"
+ " content: \"Hi, Firefox users!\";\n"
+ " }";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testInterpolationExpressionInFunctionInTheExpression() {
String source
= ".body.firefox #{ie-hex-str($green)}:before {\n"
+ " content: \"Hi, Firefox users!\";\n"
+ " }";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testInterpolationExpressionInPropertyValue() {
String source
= "p {\n"
+ " $font-size: 12px;\n"
+ " $line-height: 30px;\n"
+ " font: #{$font-size}/#{$line-height};\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
//fails as the
//
//.body.firefox #{$selector}:before
//
//selector is parsed as property declaration - due to the colon presence - FIXME!!!
public void testInterpolationExpressionComplex() {
String source
= "@mixin firefox-message($selector) {\n"
+ " .body.firefox #{$selector}:before {\n"
+ " content: \"Hi, Firefox users!\";\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testMixinsWithArgumentsComplex() {
String source
= "/* style.scss */\n"
+ "\n"
+ "@mixin rounded($vert, $horz, $radius: 10px) {\n"
+ " border-#{$vert}-#{$horz}-radius: $radius;\n"
+ " -moz-border-radius-#{$vert}#{$horz}: $radius;\n"
+ " -webkit-border-#{$vert}-#{$horz}-radius: $radius;\n"
+ "}\n"
+ "\n"
+ "#navbar li { @include rounded(top, left); }\n"
+ "#footer { @include rounded(top, left, 5px); }\n"
+ "#sidebar { @include rounded(top, left, 8px); }";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
//like normal css import, but the ref. file doesn't need to have an extension,
//there are also some rules regarding the naming convention, but these
//are covered by semantic analysis, not parsing
public void testImport() {
String source
= "@import \"rounded\";\n";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testNestedProperties() {
String source
= ".funky {\n"
+ " font: {\n"
+ " family: fantasy;\n"
+ " size: 30em;\n"
+ " weight: bold;\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testNestedPropertiesWithValue() {
String source
= ".funky {\n"
+ " font: 2px/3px {\n"
+ " family: fantasy;\n"
+ " size: 30em;\n"
+ " weight: bold;\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testLineComment() {
String source
= ".funky {\n"
+ " //line comment\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testMixinCallInStylesheet() {
String source
= "@include firefox-message(\".header\");\n";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testDefaultVariable() {
String source
= "$content: \"Second content?\" !default;\n";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testMultipleImport() {
String source
= "@import \"rounded-corners\", \"text-shadow\";\n";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testInterpolationExpressionInImport() {
String source
= "@import url(\"http://fonts.googleapis.com/css?family=#{$family}\");\n";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
//the grammar defines the imports needs to be at the very beginning of the file,
//though this is not true in case of the preprocessor code
public void testSASSCodeMayPrecedeImport() {
String source = "$var: my;\n"
+ "@import url(\"#{$var}\");\n";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testNestedMediaQueries() {
String source = ".sidebar {\n"
+ " width: 300px;\n"
+ " @media screen and (orientation: landscape) {\n"
+ " .class {\n"
+ " width: 500px;\n"
+ " }\n"
+ "}\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testNestedMediaQueryInMediaQuery() {
String source = "@media screen {\n"
+ " .sidebar {\n"
+ " @media (orientation: landscape) {\n"
+ " // width: 500px;\n"
+ " }\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
//the media query can the property declarations directly.
public void testPropertiesDirectlyInMediaQuery() {
String source = "@media screen and (orientation: landscape) {\n"
+ " width: 500px;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testInterpolationExpressionInMediaQuery() {
String source = "@media #{$media} {\n"
+ " .sidebar {\n"
+ " width: 500px;\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testInterpolationExpressionWithParenMediaQuery() {
String source = "$media: screen;\n"
+ "$feature: -webkit-min-device-pixel-ratio;\n"
+ "$value: 1.5;\n"
+ "\n"
+ "@media #{$media} and (#{$feature}: #{$value}) {\n"
+ " .sidebar {\n"
+ " width: 500px;\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testExtend() {
String source = ".seriousError {\n"
+ " @extend .error;\n"
+ " border-width: 3px;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testExtendComplex() {
String source = ".hoverlink {\n"
+ " @extend a:hover;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testExtendOnlySelectors() {
String source = "#context a%extreme {\n"
+ " color: blue;\n"
+ " font-weight: bold;\n"
+ " font-size: 2em;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testExtendOnlySelectorCall() {
String source = ".notice {\n"
+ " @extend %extreme;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testDebug() {
String source = "@debug 10em + 12em;\n"
+ ".class {\n"
+ "@debug \"hello\";\n"
+ "}\n"
+ "@mixin mymixin {\n"
+ "@debug 20;"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testWarn() {
String source = "@warn 10em + 12em;\n"
+ ".class {\n"
+ "@warn \"hello\";\n"
+ "}\n"
+ "@mixin mymixin {\n"
+ "@warn 20;"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testIf() {
String source = "p {\n"
+ " @if 1 + 1 == 2 { border: 1px solid; }\n"
+ " @if 5 < 3 { border: 2px dotted; }\n"
+ " @if null { border: 3px double; }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testFor() {
String source = "@for $i from 1 through 3 {\n"
+ " .item-#{$i} { width: 2em * $i; }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testEach() {
String source = "@each $animal in puma, sea-slug, egret, salamander {\n"
+ " .#{$animal}-icon {\n"
+ " background-image: url('/images/#{$animal}.png');\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testWhile() {
String source = "$i: 6;\n"
+ "@while $i > 0 {\n"
+ " .item-#{$i} { width: 2em * $i; }\n"
+ " $i: $i - 2;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testDefineOwnFunction() {
String source = "@function grid-width($n) {\n"
+ " @return $n * $grid-width + ($n - 1) * $gutter-width;\n"
+ "}\n"
+ "\n"
+ "#sidebar { width: grid-width(5); }";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testMixinCallWithFunctionWithNoArgs() {
String source = ".ease-out-expo-animation {\n"
+ " @include transition-timing-function(ease-out-expo()); \n"
+ " color: best-color();\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testVariableDeclarationWithCommaSeparatedValues() {
String source = "$blueprint-font-family: Helvetica Neue, Arial, Helvetica, sans-serif;";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testAmpProblem() {
String source
= ".clazz {\n"
+ " &.position#{$i} {\n"
+ " left: ($i * -910px); \n"
+ "}\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
//commented out as the parser testing file contains a lot of unknown properties from the css point of view.
//TODO: enable testing mode where the semantic errors are not added to the parsing diagnostics.
//
// public void testMergedScssTests() throws ParseException, BadLocationException, IOException {
// CssParserResult result = TestUtil.parse(getTestFile("testfiles/scss/scss-tests-merged.scss"));
//// TestUtil.dumpResult(result);
// assertResult(result, 0);
// }
public void testLocalVariableDeclaration() {
String source
= "p {\n"
+ " $width: 1000px;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
//the "$width: 1000px;" is supposed to be parsed as variable declaration, not property declaration!
assertNull(NodeUtil.query(result.getParseTree(), "styleSheet/body/bodyItem/rule/declarations/declaration/propertyDeclaration"));
assertNotNull(NodeUtil.query(result.getParseTree(), "styleSheet/body/bodyItem/rule/declarations/declaration/cp_variable_declaration"));
}
public void testMixinCallWithWSBeforeFirstArgument() {
String source
= "@mixin a {\n"
+ " @include b( linear-gradient(\n"
+ " lighten($bg-color, 5%),\n"
+ " darken($bg-color, 5%)\n"
+ " )\n"
+ " );\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testUnexpectedANDInMedia() {
String source
= "@media screen and ($width-name : $target-width) {\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testIf_Else() {
String source
= "$type: monster;\n"
+ "p {\n"
+ " @if $type == ocean {\n"
+ " color: blue;\n"
+ " } @else if $type == matador {\n"
+ " color: red;\n"
+ " } @else if $type == monster {\n"
+ " color: green;\n"
+ " } @else {\n"
+ " color: black;\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
//only 'if' is allowed as the ident after @else keyword
source
= "p {\n"
+ " @if $type == ocean {\n"
+ " color: blue;\n"
+ " } @else Yf $type == matador {\n"
+ " color: red;\n"
+ " }\n"
+ "}";
result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertTrue(result.getDiagnostics().size() > 0);
}
public void testContentDirective() {
String source
= "@mixin apply-to-ie6-only {\n"
+ " * html {\n"
+ " @content;\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testContentDirectiveInMedia() {
String source
= "@mixin respond-to($media) {\n"
+ " @if $media == handhelds {\n"
+ " @media only screen and (max-width: $break-small) { @content; }\n"
+ " } @else if $media == medium-screens {\n"
+ " @media only screen and (min-width: $break-small + 1) and (max-width:\n"
+ "$break-large - 1) { @content; }\n"
+ " }\n"
+ " @else if $media == wide-screens {\n"
+ " @media only screen and (min-width: $break-large) { @content; }\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testMixinCallArgWithPropertyName() {
String source
= "@mixin border-radius($radius: 5px, $moz: true, $webkit: true, $ms: true) {\n"
+ "}\n"
+ "div{\n"
+ " @include border-radius($webkit:false);\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testMixinCallArgWithValueSeparatedByWS() {
String source
= "#id {\n"
+ " @include border-radius(5px, -moz -webkit);\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testPropertyValueSyntacticPredicateBoundary() {
//the scss_declaration_property_value_interpolation_expression synt. predicate
//was terminated just by colon so it seen the interpolation expression
//few lines below and caused bad parsing
String source
= "#test2 { \n"
+ " background-color: cyan\n"
+ "}\n"
+ "#test#{$i} { }";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testMultiplicityOperatorInPropertyValueFunction() {
String source
= ".c {\n"
+ " background-color: darken(orange, $i*5);\n"
+ "}\n"
+ "";
CssParserResult result = TestUtil.parse(source);
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
}
public void testIfControlExpression() {
assertParses(" @if $arg != null and $arg2 != transparent { }");
assertParses(" @if not $arg != null and $arg2 != transparent { }");
assertParses(" @if not $arg != null or not $arg2 != transparent { }");
assertParses(" @if true or not $arg2 != transparent { }");
}
public void testMixinWithFirstParamOnNewLine() {
assertParses("@mixin color(\n"
+ "$bgcolor: red,"
+ "$fgcolor: blue) {\n"
+ "}");
}
public void testFunctionInIfStatementExpression() {
assertParses("@function myfn($color) {\n"
+ " @if lightness($color) > 50 {\n"
+ " @return light;\n"
+ " } @else {\n"
+ " @return dark;\n"
+ " }\n"
+ "}");
}
public void testImportInDeclarations() {
assertParses(".clz { @import \"hello\"; }");
}
public void testCommaInSelectorInterpolationExpression() {
assertParses(".#{$prefix}sg,.#{$prefix}ag .#{$prefix}xx { }");
}
public void testIfCondition() {
assertParses(" @if ($mode == light) {}");
}
public void testSassFunctionWhereWithArgDefiningValue() {
assertParses("@function color-by-background($bg-color, $contrast: $default-text-contrast) {\n"
+ " @return color-offset($bg-color, $contrast, $tmpmode, $inverse: true);\n"
+ "}");
}
public void testWeirdControlBlockOperator() {
assertParses("@if $right =< 0 {}");
assertParses("@if $right <= 0 {}");
assertParses("@if $right >= 0 {}");
assertParses("@if $right => 0 {}");
}
public void testWSBetweenMixinCallArgAndComma() {
assertParses(".clz {\n"
+ " @include background-gradient(\n"
+ " $background-color ,\n"
+ " $background-direction\n"
+ ");\n"
+ "}");
}
public void testControlBlockExpression() {
assertParses("@if $arg != null and ($arg2 == val1 or $arg2 == val2) {}");
}
public void testControlBlockExpression2() {
assertParses("@if (not $arg or $arg2) and $arg3 != null {}");
}
public void testControlBlockExpression3() {
assertParses("@if ($arg or $arg2) and arg3 != null {}");
}
public void testControlBlockExpression4() {
assertParses("@if $arg != null and ($arg2 or arg3) {}");
}
public void testDashInSelectorInterpolationExpression() {
assertParses(".#{$v1}#{$v2}-post {}");
}
public void testFunctionReturnBooleanExpression() {
assertParses("@function even($number) {\n"
+ " @return ceil($number / 2) == ($number / 2);\n"
+ "}");
}
public void testStarInSelectorInterpolationExpression() {
assertParses(".#{$prefix}border-box * {}");
}
public void testGreaterSymbolInSelectorInterpolationExpression() {
assertParses(".#{$prefix}rtl > .#{$prefix}box-item {}");
}
public void testLRPARENInPropertyValueInterpolationExpression() {
assertParses(".clz { $rotation: rotate(#{$angle}deg); }");
assertParses(".clz { background-image: slicer-corner-sprite(btn-#{$ui}-over, 'btn/btn-#{$ui}-over-corners'); }");
}
public void testCPExpressionInPropertyValue() {
assertParses(".clz { background-position: 0 ($accordion-header-tool-size * -17); }");
}
public void testCPExpressionInPropertyValue2() {
assertParses(".clz { padding: $toolbar-vertical-spacing ($toolbar-horizontal-spacing / 2) $toolbar-vertical-spacing ($toolbar-horizontal-spacing / 2); }");
}
public void testCPExpressionInPropertyValue3() {
assertParses(".clz { $fieldset-collapse-tool-background-position-over: 0 (-$fieldset-collapse-tool-size) !default; }");
}
public void testFunctionInsideSASSInterpolationExpression() {
assertParses(".clz { padding-left: #{left($fieldset-header-padding) - 2}; }");
}
public void testSimplePropertyValue() {
assertParses(".clz { padding: 2cm 10px; }", false);
}
public void testPropertyValue2() {
assertParses(".clz { padding-left: "
+ "top($form-error-under-padding) "
+ "right($form-error-under-padding) "
+ "bottom($form-error-under-padding) "
+ "(left($form-error-under-padding) + $form-error-icon-width + $form-error-under-icon-spacing); "
+ "}");
}
public void testPropertyValue3() {
assertParses(".clz { background-position: 0 (0 - $form-checkbox-size); }");
}
public void testPropertyValue4() {
assertParses(".clz { background-position: (-$html-editor-toolbar-icon-size) 0; }");
assertParses(".clz { background-position: 0 (-$spinner-btn-height); }");
}
public void testPropertyValue5() {
assertParses(".clz { background-position: 0 (-$spinner-btn-height); }");
}
public void testPropertyValueUnaryOperatorBeforeBrace() {
assertParses(".clz { background-position: -($form-trigger-width * 3) (-$spinner-btn-height); }");
}
public void testCPVariableDeclaration() {
assertParses("$panel-frame-header-padding:\n"
+ " (top($panel-header-padding) - top($panel-frame-border-width))\n"
+ " (right($panel-header-padding) - right($panel-frame-border-width))\n"
+ " (bottom($panel-header-padding) - bottom($panel-frame-border-width))\n"
+ " (left($panel-header-padding) - left($panel-frame-border-width))\n"
+ " !default;");
}
public void testSASSInterpolationExpressionInCPVariableDeclaration() {
assertParses("$fieldset-header-font: #{$fieldset-header-font-size}/#{$fieldset-header-line-height} $fieldset-header-font-weight $fieldset-header-font-family !default;");
assertParses("$form-label-font: $form-label-font-weight #{$form-label-font-size}/#{$form-label-line-height} $form-label-font-family !default;");
assertParses("$grid-editor-font: normal #{$grid-row-cell-font-size}/#{$grid-editor-line-height} $font-family !default;");
assertParses("$grid-row-cell-font: normal #{$grid-row-cell-font-size}/#{$grid-row-cell-line-height} $font-family !default;");
}
public void testImportantKeywordInCPVariableDeclaration() {
assertParses("$grid-row-editor-border: $grid-row-editor-border-width solid $grid-row-editor-border-color !important !default;");
}
public void testCommaSeparatedPropertyValues() {
assertParses(".x { background-size: $majorsteps $majorsteps, $majorsteps $majorsteps, $minorsteps $minorsteps, $minorsteps $minorsteps; }");
}
public void testImportantSymbolJustAfterPropertyValue() throws ParseException, BadLocationException {
assertParses(".x { z-index: 1000000!important; }");
assertParses(".x { z-index: 1000000 !important; }");
}
public void testInclude() throws ParseException, BadLocationException {
assertParses(".x { @include x-slicer($panel-header-ui + '-top'); }");
}
public void testMSPropertyValueAndInterpolationExpression() throws ParseException, BadLocationException {
assertParses(".x { filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$ie-rotation}); }");
}
public void testLastItemInBlockDoesntNeedToBeTerminatedWithSemicolon() throws ParseException, BadLocationException {
assertParses(".x { $image-search-path: '.' !default }"); //doesn't work
assertParses(".x { $image-search-path: '.' !default; }"); //works
}
public void testUnaryOperatorWithIE() throws ParseException, BadLocationException {
assertParses(".x { margin-top: -#{top($fieldset-border-width)}; }");
}
public void testFunctionArgumentsCanBeBooleanExpression() throws ParseException, BadLocationException {
assertParses("$foo: if($direction == top or $direction == bottom, 0, 1);");
}
public void testFunction3() throws ParseException, BadLocationException {
assertParses(".clz { @include linear-gradient(#3875d7 20%, #2a62bc 90%); }");
}
public void testFont_FaceInMixin() throws ParseException, BadLocationException {
assertParses("@mixin font-face($name){\n"
+ " @font-face {\n"
+ " font-family: $name;\n"
+ " }\n"
+ "}");
}
public void testCommaInCPExpression() throws ParseException, BadLocationException {
assertParses(".highlighted {\n"
+ " @include linear-gradient((#3875d7 20%, #2a62bc 90%));\n"
+ " color: #fff;\n"
+ "}");
}
public void testSassInclude() throws ParseException, BadLocationException {
assertParses(".clz { @include extjs-button-ui(\n"
+ " $ui: 'default-small',\n"
+ "\n"
+ " $border-radius: $button-small-border-radius,\n"
+ " $border-width: $button-small-border-width); }");
}
public void testSassInclude2() throws ParseException, BadLocationException {
assertParses(".clz { @include extjs-toolbar-ui(\n"
+ " 'default',\n"
+ " $background-color: $toolbar-background-color,\n"
+ " $background-gradient: $toolbar-background-gradient,\n"
+ " $border-color: $toolbar-border-color\n"
+ "); "
+ "}");
}
public void testNestedRules2() throws ParseException, BadLocationException {
assertParses("x { y {} z {} }");
assertParses("x { y {} }");
}
public void testNestedIfs() throws ParseException, BadLocationException {
assertParses("x { @if true {} }");
assertParses("x { @if $a==10 {} }");
assertParses("x { @if true {} @if false {} }");
}
public void testNestedRuleNotParsedAsDeclaration() {
String cssCode = "x {\n"
+ " a, a:hover {\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(cssCode);
Node tree = result.getParseTree();
// NodeUtil.dumpTree(tree);
Node node = NodeUtil.query(tree, "styleSheet/body/bodyItem/rule/declarations/declaration/rule");
assertNotNull(node);
assertEquals(NodeType.rule, node.type());
assertResultOK(result);
}
public void testMixinCallWithBlock() throws ParseException, BadLocationException {
assertParses("@include respond_to ( handhelds ) { \n"
+ " font-size: 1em;\n"
+ "} ");
assertParses("h1 {"
+ " @include respond_to ( handhelds ) { \n"
+ " font-size: 1em;\n"
+ " }\n"
+ "}");
}
public void testParseCommentAtTheFileEnd() throws ParseException, BadLocationException {
assertParses("div {}\n"
+ "/*comment*/");
assertParses("//comment1\n"
+ "div {}\n"
+ "//comment2");
}
public void testMixinDeclarationWithVarargs() throws ParseException, BadLocationException {
assertParses("@mixin box-shadow($shadows...) {}\n");
}
public void testMixinCallWithVarargs() throws ParseException, BadLocationException {
assertParses("@include colors($values...);");
}
//https://netbeans.org/bugzilla/show_bug.cgi?id=227484#c21
public void testMixinCallInMedia() throws ParseException, BadLocationException {
assertParses("@media screen{\n"
+ " @include test2;\n"
+ "}");
}
//https://netbeans.org/bugzilla/show_bug.cgi?id=227484#c19
public void testAmpInSelector() throws ParseException, BadLocationException {
assertParses("&.primary, input[type=\"submit\"] & { }\n");
//assertParses("&.primary, input[type=\"submit\"]& { }\n"); //this is not possible in scss
assertParses("&.primary, & { }\n");
}
public void testIncompleteSelectors() throws ParseException, BadLocationException {
assertParses(".pills {\n"
+ " @include clearfix;\n"
+ " > li {\n"
+ " float: left;\n"
+ " > a {\n"
+ " display: block;\n"
+ " }\n"
+ " }\n"
+ "}");
}
//https://netbeans.org/bugzilla/show_bug.cgi?id=233038#c2
public void testCPExpressionInMediaQuery() throws ParseException, BadLocationException {
assertParses("@media only tv and (resolution: 120 * 3 + \"dpi\"){\n"
+ "\n"
+ "}");
}
public void testMixinBodyPropertyRecovery() throws ParseException, BadLocationException {
CssParserResult result = TestUtil.parse("@mixin mymixin() { color: }");
Node node = NodeUtil.query(result.getParseTree(),
"styleSheet/body/bodyItem/cp_mixin_declaration/cp_mixin_block/declarations/declaration/propertyDeclaration/property");
assertNotNull(node);
}
public void testPercentageInExpression() throws ParseException, BadLocationException {
CssParserResult result = TestUtil.parse("$size: 20;\n"
+ ".clz {\n"
+ " font: %/20;\n"
+ "}");
// NodeUtil.dumpTree(result.getParseTree());
assertResultOK(result);
//original sample
assertParses("@mixin base-type($weight, $line-height, $font-size, $font-family...) {\n"
+ " @if $serif-boolean {\n"
+ " font: $weight #{$font-size}%/#{$line-height} $font-family;\n"
+ " }@else {\n"
+ " font: $weight #{$font-size}%/#{$line-height} $font-family-sans;\n"
+ " }\n"
+ "}");
}
public void testSelectorWithInterpolationExpressionInMediaBody() throws ParseException, BadLocationException {
assertParses("@media only screen and (min-resolution: 1000) {\n"
+ "\n"
+ " #{$selector}:before {\n"
+ " content: $hiResIcon;\n"
+ " }\n"
+ " }");
}
public void testInterpolationExpressionWithBrackets() {
assertParses(".#{$item}-important { background-color: green; }");
assertParses(".important[href] { }\n");
assertParses(".#{$item}important[href] { }\n");
assertParses("@each $item in label, badge {\n"
+ " .#{$item}-important { background-color: green; }\n"
+ " .#{$item}-important[href] { background-color: blue; }\n"
+ " }");
}
public void testIssue237010() {
assertParses("$textColorError: \"blue\";\n"
+ "$allowTagSelectors: true;\n"
+ "@if $allowTagSelectors != true {\n"
+ " .oj-text-input {\n"
+ " @include oj-normalize-text-input;\n"
+ " }\n"
+ " .oj-text-input[type='search'] {\n"
+ " @include oj-normalize-search-input;\n"
+ " }\n"
+ "}\n"
+ "$currSelectors: if($allowTagSelectors,\n"
+ " // here: \n"
+ " \".oj-date-input.oj-invalid, \n"
+ " input[type='url'].oj-invalid\", \n"
+ " // class selectors: \n"
+ " \".oj-text-input.oj-invalid,\n"
+ " .oj-textarea.oj-invalid\");\n"
+ "#{$currSelectors} {\n"
+ " border: 2px solid $textColorError; \n"
+ "}");
}
public void testIssue236388() {
assertParses("@media only screen and (min-width: 768px) {\n"
+ " @import \"_grid.less\";\n"
+ " @import \"_768up.less\";\n"
+ "}");
}
public void testIssue236706() {
assertParses("@mixin web-font($fonts, $variants: (), $subsets: (), $text: '', $effects: (), $secure: false) {}");
}
//new SASS 3.3 stuff
//http://thesassway.com/news/sass-3-3-released
public void testSassMap() {
assertParses("$colors: (\n"
+ " header: #b06,\n"
+ " footer: $another_var,\n"
+ ")");
assertParses("$susy: (\n"
+ " columns: 8,\n"
+ " gutters: 1/10\n"
+ ");");
}
public void testSassMapInBlock() {
assertParses("div { $colors: (\n"
+ " header: #b06,\n"
+ " footer: $another_var,\n"
+ ") }");
assertParses(".clz {\n $susy: (\n"
+ " columns: 8,\n"
+ " gutters: 1/10\n"
+ "); }");
}
public void testSassMapComplex() {
//bit more complex example
assertParses("$var: red;\n"
+ "\n"
+ "$map: ( cool: 'pink');\n"
+ "\n"
+ "div {\n"
+ "\n"
+ " $colors: (\n"
+ " header: $var,\n"
+ " text: #334,\n"
+ " color: map-get($map, cool),\n"
+ " );\n"
+ "\n"
+ " .pink {\n"
+ " color: map-get($colors, color);\n"
+ " }\n"
+ "\n"
+ "}\n");
}
public void testParentSelectorSuffixes() {
assertParses("// Ampersand in SassScript:\n"
+ ".button {\n"
+ " &-primary { background: orange; }\n"
+ " &-secondary { background: blue; }\n"
+ "}\n");
}
public void testAtRoot() {
assertParses(".message {\n"
+ " @at-root {\n"
+ " .info { color: blue; }\n"
+ " .error { color: red; }\n"
+ " }\n"
+ "}\n");
assertParses(".message {\n"
+ " @at-root .info { color: blue; }\n"
+ " @at-root .error { color: red; }\n"
+ "}\n");
}
public void testIfInFn() {
assertParses("@function my-function($args...) {\n"
+ " // Assign the first argument to $param-1\n"
+ " $param-1: nth($args, 1);\n"
+ "\n"
+ " // If a second argument was passed assign it to $param-2,\n"
+ " // otherwise assign an empty list:\n"
+ " $param-2: if(length($args) > 1, nth($args, 2), ());\n"
+ "}\n");
}
public void testBwLoop() {
assertParses("@for $i from 5 through 1 {\n"
+ ".selector#{$i} { content: $i; }"
+ "}\n");
}
//can't parse an expression inside the interpolation expression
public void _testInterpolationExpression_BUG1() {
assertParses(".span:nth-child(#{6-$i}) { content: $i; }");
}
//can't parse an interpolation expression as fn argument
public void _testInterpolationExpression_BUG2() {
assertParses(".span:nth-child(#{$i}) { content: $i; }");
}
public void testForEachMultiAssignments() {
assertParses("$animals: (puma, black, default),\n"
+ " (sea-slug, blue, pointer),\n"
+ " (egret, white, move);\n"
+ "\n"
+ "@each $animal, $color, $cursor in $animals {\n"
+ " .#{$animal}-icon {\n"
+ " background-image: url('/images/#{$animal}.png');\n"
+ " border: 2px solid $color;\n"
+ " cursor: $cursor;\n"
+ " }\n"
+ "}\n");
}
public void testMixin() {
String source = "@mixin simple($selectorPrefix){}";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testScssVar() {
String source = ".test {background-image: $var;}";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testInterpolationInSelector() {
String source = ".#{$selectorPrefix}-odd-cols-#{$i} > .oj-row > .oj-col:nth-child(even) {}";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
source = ".table-odd-cols-#{$i} > .oj-row > .oj-col:nth-child(even) {}";
result = TestUtil.parse(source);
assertResultOK(result);
source = ".table-odd-cols-#{$i}-test:nth-child(even) {}";
result = TestUtil.parse(source);
assertResultOK(result);
}
public void testMapWithStrings() {
String source = "$map: (\n"
+ " '1': 'one',\n"
+ ");";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testMapDeclarationWithDefault() {
String source = "$modules: () !default;";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testIfWithoutSpace() {
String source = "@if($allowTagSelectors)\n"
+ " {\n"
+ " #{$tagSelectors} {\n"
+ " color: red;\n"
+ " }\n"
+ " }";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testElseIfTogether() {
String source = "@mixin icon($name, $character: null, $font-family: 'Pictos') {\n"
+ " @if $character != null {\n"
+ " content: \"#{$character}\";\n"
+ " } @elseif $raw_character != null {\n"
+ " content: \"#{$raw_character}\";\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testFunctionParametersOnNewLines() {
String source = "@function matte-gradient (\n"
+ " $bg-color: $base-color,\n"
+ " $direction: top,\n"
+ " $contrast: 1\n"
+ ") {\n"
+ " @return linear-gradient(red);\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testAdditionalCommaInTheEndOfSelector() {
String source = ".ui-convex,\n"
+ ".ui-convex-hover,\n"
+ "{\n"
+ " width: 10em;\n"
+ " height: 2em;\n"
+ " \n"
+ " margin: 1em auto;\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testQuoteEscapingInString() {
String source = "@function icon-character-for-name($name) {\n"
+ " // http://pictos.cc/font/\n"
+ "\n"
+ " // Row 1\n"
+ " @if ($name == \"anchor\") { @return \"a\"; }\n"
+ " @else if ($name == \"quote\") { @return \"\\\"\"; }\n"
+ " @else if ($name == \"volume_mute\") { @return \"<\"; }}";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testEachWithMapPairs() {
String source = "@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {\n"
+ " #{$header} {\n"
+ " font-size: $size;\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testParenSelectorAsPropertyValue() {
String source = ".foo .bar, .baz { $selector: & }";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testMultiDimensionalMaps() {
String source = "$type-scale: (\n"
+ " tiny: (\n"
+ " font-size: 10.24px,\n"
+ " base-lines: 0.5\n"
+ " ),\n"
+ " small: (\n"
+ " font-size: 12.8px,\n"
+ " base-lines: 0.75\n"
+ " )\n"
+ ");\n"
+ "";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testErrorWithSemi() {
String source = "@mixin adjust-location($x, $y) {\n"
+ " @if unitless($x) {\n"
+ " @error \"$x may not be unitless, was #{$x}.\";\n"
+ " }\n"
+ " position: relative; left: $x; top: $y;\n"
+ "}\n"
+ "";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testAtRootDeclaration() {
String source = "@media print {\n"
+ " .page {\n"
+ " width: 8in;\n"
+ " @at-root (without: media) {\n"
+ " color: red;\n"
+ " }\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
}
public void testKeyframesInSass() {
String source = "@mixin keyframes($name)\n"
+ "{\n"
+ " @-webkit-keyframes $name\n"
+ " {\n"
+ " @content;\n"
+ " }\n"
+ " @keyframes $name\n"
+ " {\n"
+ " @content;\n"
+ " }\n"
+ "}";
CssParserResult result = TestUtil.parse(source);
assertResultOK(result);
source = "@mixin keyframes($name) {\n"
+ " @-webkit-keyframes #{$name} {\n"
+ " @content; \n"
+ " }}";
result = TestUtil.parse(source);
assertResultOK(result);
source = "@include keyframes(slide-down) {\n"
+ " 0% { opacity: 1; }\n"
+ " 90% { opacity: 0; }\n"
+ "}";
result = TestUtil.parse(source);
assertResultOK(result);
}
public void testSassNestingGreater() {
assertParses("div {\n"
+ " margin: 0;\n"
+ " > {\n"
+ " label {\n"
+ " float: left;\n"
+ " }\n"
+ " input {\n"
+ " width: 70%; \n"
+ " }\n"
+ " }\n"
+ "}");
}
public void testPseudoClassBeforeAmpersand() {
assertParses(" li {\n"
+ " a:hover, &.selected {\n"
+ " display: block;\n"
+ " }\n"
+ " }");
}
public void testDotInterpolationMinus() {
assertParses("$fa-css-prefix : test;\n"
+ ".#{$fa-css-prefix}-2x { font-size: 2em; }");
}
public void testAmpColonInterpolation() {
assertParses("a {\n"
+ " &:#{$state}{\n"
+ " color: black\n"
+ " }\n"
+ "}");
}
public void testMathExpWithUnits() {
assertParses("$fa-li-width: (30em / 14) !default;");
}
public void testExtendPlaceHolderWithInterpolation() {
assertParses("%at-contactformelement-skin-default {\n"
+ " margin-top: 6rem;\n"
+ "}\n"
+ "\n"
+ "@mixin contactformelement($selector, $skin: default) {\n"
+ " #{$selector} {\n"
+ " @extend %at-contactformelement-skin-#{$skin} !optional;\n"
+ " }\n"
+ "}");
}
public void testSpacesInSassInterpolation() {
assertParses(".test {\n"
+ " &.#{ $active_class } > a {\n"
+ " background: $active-bg;\n"
+ " }\n"
+ "}");
}
public void testMathExpressionInPropertyValue() {
assertParses("@mixin dropdown-container($content:list, $triangle:true, $max-width:$f-dropdown-max-width) {\n"
+ " &:before {\n"
+ " @include css-triangle($f-dropdown-triangle-size, $f-dropdown-triangle-color, #{$opposite-direction});\n"
+ " position: absolute;\n"
+ " top: $f-dropdown-triangle-side-offset;\n"
+ " #{$default-float}: -($f-dropdown-triangle-size * 2);\n"
+ " z-index: 89;\n"
+ " }\n"
+ "}");
}
public void testPropertyDeclarationWithExpression() {
assertParses("@media only screen and (min-width: $media-xs)\n"
+ "{\n"
+ " width: calc(100% - #{$left-column-width});\n"
+ "}");
}
public void testURLinScss() {
assertParses("@function oj-image-url($path){\n"
+ " @return url($imageDir + $path);\n"
+ "}");
assertParses(".xxx {\n"
+ " content: url($imagesDir + \"functional/func_back_24_ena.png\"); \n"
+ "}");
assertParses("@function composeURL($a, $b)\n"
+ "{\n"
+ " @return url($a + $b);\n"
+ "}");
assertParses("@each $ord in 1, 2, 3, 4 {\n"
+ " \n"
+ " body._#{$ord} #page {\n"
+ " background: $page-bg url(#{$scssDir}/images/bg#{$ord}-squares-blue.png);\n"
+ " }\n"
+ " \n"
+ "}");
assertParses("li {\n"
+ " background: transparent url(@{img_path}list-bullet.png) no-repeat 0 0;\n"
+ " padding-left: 14px;\n"
+ " margin-bottom: 5px;\n"
+ "}");
}
public void testPseudoWithWhitespaceOnEnd() {
assertParses("#test\n"
+ "{\n"
+ " &:not( .active )\n"
+ " {\n"
+ " background-color: #E1E1E1;\n"
+ " }\n"
+ "}");
}
public void testFunctionQuoteInMap() {
assertParses("$a: (quote(bgcolor): black)");
}
public void testSassMapWithNumbers() {
assertParses("$twoToTheN: (0: 1, 1: 2, 2: 4, 3: 8, 4: 16, 5: 32);");
}
public void testStringEscapesInInterpolation() {
assertParses("@function oj-prepend-slash($char)\n"
+ "{\n"
+ " @return #{\"\\\"\\\\\"}#{$char + \"\\\"\"};\n"
+ "}");
}
public void testEachWithMultipleLists() {
assertParses("@each $className, $iconFile\n"
+ "in\n"
+ "(my_class, my_file_name_base),\n"
+ "{}");
assertParses("@each $animal, $color, $cursor in (puma, black, default),\n"
+ " (sea-slug, blue, pointer),\n"
+ " (egret, white, move) {\n"
+ " .#{$animal}-icon {\n"
+ " background-image: url('/images/#{$animal}.png');\n"
+ " border: 2px solid $color;\n"
+ " cursor: $cursor;\n"
+ " }\n"
+ "}");
}
public void testMapAnyDatatypeasKey() {
assertParses("$font-formats: 'woff' 'ttf'; // Define what webfont formats need importing\n"
+ "$font-path: '../fonts/'; // Set the a path to your fonts directory\n"
+ "\n"
+ "$fonts: (\n"
+ " 'heading': ( // give your font a semantic name for reference\n"
+ " 'name': 'maven', // optionally set a different font name\n"
+ " 'stack': ('helvetica', 'arial', sans-serif), // define the stack\n"
+ " 'normal': 'maven/maven_pro_regular-webfont', // point to any webfont files\n"
+ " 'bold': 'maven/maven_pro_bold-webfont',\n"
+ " ),\n"
+ "\n"
+ " 'body': (\n"
+ " 'name': 'exo',\n"
+ " 'stack': ('helvetica', 'arial', sans-serif),\n"
+ " 'normal': 'exo/exo2-regular-webfont',\n"
+ " 'italic': 'exo/exo2-italic-webfont',\n"
+ " 'bold': 'exo/exo2-bold-webfont',\n"
+ " 'bold' 'italic': 'exo/exo2-bolditalic-webfont',\n"
+ " ),\n"
+ "\n"
+ " 'alias': 'body', // create aliases when useful\n"
+ ");");
}
public void testMediaWithInterpolation() {
assertParses("$information-phone: \"(max-width : 320px)\";\n"
+ "@media screen and (#{$information-phone}) {\n"
+ " background: red;\n"
+ "}\n"
+ "@media screen and #{$information-phone} {\n"
+ " background: red;\n"
+ "}");
}
}