diff --git a/.gitignore b/.gitignore
index 1500b0d1..60cdb15b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,6 @@
*.dummy
*-test
Makefile
+target/
+doc/
+.*.swp
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..56d1eced
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,12 @@
+env:
+ global:
+ - LD_LIBRARY_PATH: /usr/local/lib
+install:
+ - curl https://static.rust-lang.org/rustup.sh | sudo sh
+script:
+ - rustc --version
+ - cargo --version
+ - cargo build
+notifications:
+ email:
+ - damien.schoof+github@gmail.com
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 00000000..d9916e7f
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "cssparser"
+version = "0.0.0"
+
+authors = ["Your Name This page is 100% Awesome.
diff --git a/test/index.js b/test/index.js
new file mode 100644
index 00000000..33e79637
--- /dev/null
+++ b/test/index.js
@@ -0,0 +1,45 @@
+var lessTest = require("./less-test"),
+ lessTester = lessTest(),
+ path = require("path"),
+ stylize = require('../lib/less/lessc_helper').stylize;
+
+function getErrorPathReplacementFunction(dir) {
+ return function(input) {
+ return input.replace(
+ "{path}", path.join(process.cwd(), "/test/less/" + dir + "/"))
+ .replace("{pathrel}", path.join("test", "less", dir + "/"))
+ .replace("{pathhref}", "")
+ .replace("{404status}", "")
+ .replace(/\r\n/g, '\n');
+ };
+}
+
+console.log("\n" + stylize("Less", 'underline') + "\n");
+lessTester.runTestSet({strictMath: true, relativeUrls: true, silent: true});
+lessTester.runTestSet({strictMath: true, strictUnits: true}, "errors/",
+ lessTester.testErrors, null, getErrorPathReplacementFunction("errors"));
+lessTester.runTestSet({strictMath: true, strictUnits: true, javascriptEnabled: false}, "no-js-errors/",
+ lessTester.testErrors, null, getErrorPathReplacementFunction("no-js-errors"));
+lessTester.runTestSet({strictMath: true, dumpLineNumbers: 'comments'}, "debug/", null,
+ function(name) { return name + '-comments'; });
+lessTester.runTestSet({strictMath: true, dumpLineNumbers: 'mediaquery'}, "debug/", null,
+ function(name) { return name + '-mediaquery'; });
+lessTester.runTestSet({strictMath: true, dumpLineNumbers: 'all'}, "debug/", null,
+ function(name) { return name + '-all'; });
+lessTester.runTestSet({strictMath: true, relativeUrls: false, rootpath: "folder (1)/"}, "static-urls/");
+lessTester.runTestSet({strictMath: true, compress: true}, "compression/");
+lessTester.runTestSet({}, "legacy/");
+lessTester.runTestSet({strictMath: true, strictUnits: true, sourceMap: true, globalVars: true }, "sourcemaps/",
+ lessTester.testSourcemap, null, null,
+ function(filename, type) {
+ if (type === "vars") {
+ return path.join('test/less/', filename) + '.json';
+ }
+ return path.join('test/sourcemaps', filename) + '.json';
+ });
+lessTester.runTestSet({globalVars: true, banner: "/**\n * Test\n */\n"}, "globalVars/",
+ null, null, null, function(name) { return path.join('test/less/', name) + '.json'; });
+lessTester.runTestSet({modifyVars: true}, "modifyVars/",
+ null, null, null, function(name) { return path.join('test/less/', name) + '.json'; });
+lessTester.runTestSet({urlArgs: '424242'}, "url-args/");
+lessTester.testNoOptions();
diff --git a/test/less-test.js b/test/less-test.js
new file mode 100644
index 00000000..0c1bf4a0
--- /dev/null
+++ b/test/less-test.js
@@ -0,0 +1,259 @@
+/*jshint latedef: nofunc */
+
+module.exports = function() {
+ var path = require('path'),
+ fs = require('fs'),
+ sys = require('util');
+
+ var less = require('../lib/less');
+ var stylize = require('../lib/less/lessc_helper').stylize;
+
+ var globals = Object.keys(global);
+
+ var oneTestOnly = process.argv[2];
+
+ var isVerbose = process.env.npm_config_loglevel === 'verbose';
+
+ var totalTests = 0,
+ failedTests = 0,
+ passedTests = 0;
+
+
+ less.tree.functions.add = function (a, b) {
+ return new(less.tree.Dimension)(a.value + b.value);
+ };
+ less.tree.functions.increment = function (a) {
+ return new(less.tree.Dimension)(a.value + 1);
+ };
+ less.tree.functions._color = function (str) {
+ if (str.value === "evil red") { return new(less.tree.Color)("600"); }
+ };
+
+ function testSourcemap(name, err, compiledLess, doReplacements, sourcemap) {
+ fs.readFile(path.join('test/', name) + '.json', 'utf8', function (e, expectedSourcemap) {
+ sys.print("- " + name + ": ");
+ if (sourcemap === expectedSourcemap) {
+ ok('OK');
+ } else if (err) {
+ fail("ERROR: " + (err && err.message));
+ if (isVerbose) {
+ console.error();
+ console.error(err.stack);
+ }
+ } else {
+ difference("FAIL", expectedSourcemap, sourcemap);
+ }
+ });
+ }
+
+ function testErrors(name, err, compiledLess, doReplacements) {
+ fs.readFile(path.join('test/less/', name) + '.txt', 'utf8', function (e, expectedErr) {
+ sys.print("- " + name + ": ");
+ expectedErr = doReplacements(expectedErr, 'test/less/errors/');
+ if (!err) {
+ if (compiledLess) {
+ fail("No Error", 'red');
+ } else {
+ fail("No Error, No Output");
+ }
+ } else {
+ var errMessage = less.formatError(err);
+ if (errMessage === expectedErr) {
+ ok('OK');
+ } else {
+ difference("FAIL", expectedErr, errMessage);
+ }
+ }
+ });
+ }
+
+ function globalReplacements(input, directory) {
+ var p = path.join(process.cwd(), directory),
+ pathimport = path.join(process.cwd(), directory + "import/"),
+ pathesc = p.replace(/[.:/\\]/g, function(a) { return '\\' + (a=='\\' ? '\/' : a); }),
+ pathimportesc = pathimport.replace(/[.:/\\]/g, function(a) { return '\\' + (a=='\\' ? '\/' : a); });
+
+ return input.replace(/\{path\}/g, p)
+ .replace(/\{pathesc\}/g, pathesc)
+ .replace(/\{pathimport\}/g, pathimport)
+ .replace(/\{pathimportesc\}/g, pathimportesc)
+ .replace(/\r\n/g, '\n');
+ }
+
+ function checkGlobalLeaks() {
+ return Object.keys(global).filter(function(v) {
+ return globals.indexOf(v) < 0;
+ });
+ }
+
+ function runTestSet(options, foldername, verifyFunction, nameModifier, doReplacements, getFilename) {
+ foldername = foldername || "";
+
+ if(!doReplacements) {
+ doReplacements = globalReplacements;
+ }
+
+ function getBasename(file) {
+ return foldername + path.basename(file, '.less');
+ }
+
+ fs.readdirSync(path.join('test/less/', foldername)).forEach(function (file) {
+ if (! /\.less/.test(file)) { return; }
+
+ var name = getBasename(file);
+
+ if (oneTestOnly && name !== oneTestOnly) {
+ return;
+ }
+
+ totalTests++;
+
+ if (options.sourceMap) {
+ var sourceMapOutput;
+ options.writeSourceMap = function(output) {
+ sourceMapOutput = output;
+ };
+ options.sourceMapOutputFilename = name + ".css";
+ options.sourceMapBasepath = path.join(process.cwd(), "test/less");
+ options.sourceMapRootpath = "testweb/";
+ }
+
+ options.getVars = function(file) {
+ return JSON.parse(fs.readFileSync(getFilename(getBasename(file), 'vars'), 'utf8'));
+ };
+
+ toCSS(options, path.join('test/less/', foldername + file), function (err, less) {
+
+ if (verifyFunction) {
+ return verifyFunction(name, err, less, doReplacements, sourceMapOutput);
+ }
+ var css_name = name;
+ if(nameModifier) { css_name = nameModifier(name); }
+ fs.readFile(path.join('test/css', css_name) + '.css', 'utf8', function (e, css) {
+ sys.print("- " + css_name + ": ");
+
+ css = css && doReplacements(css, 'test/less/' + foldername);
+ if (less === css) { ok('OK'); }
+ else if (err) {
+ fail("ERROR: " + (err && err.message));
+ if (isVerbose) {
+ console.error();
+ console.error(err.stack);
+ }
+ } else {
+ difference("FAIL", css, less);
+ }
+ });
+ });
+ });
+ }
+
+ function diff(left, right) {
+ require('diff').diffLines(left, right).forEach(function(item) {
+ if(item.added || item.removed) {
+ var text = item.value.replace("\n", String.fromCharCode(182) + "\n");
+ sys.print(stylize(text, item.added ? 'green' : 'red'));
+ } else {
+ sys.print(item.value);
+ }
+ });
+ console.log("");
+ }
+
+ function fail(msg) {
+ console.error(stylize(msg, 'red'));
+ failedTests++;
+ endTest();
+ }
+
+ function difference(msg, left, right) {
+ console.warn(stylize(msg, 'yellow'));
+ failedTests++;
+
+ diff(left, right);
+ endTest();
+ }
+
+ function ok(msg) {
+ console.log(stylize(msg, 'green'));
+ passedTests++;
+ endTest();
+ }
+
+ function endTest() {
+ var leaked = checkGlobalLeaks();
+ if (failedTests + passedTests === totalTests) {
+ console.log("");
+ if (failedTests > 0) {
+ console.error(failedTests + stylize(" Failed", "red") + ", " + passedTests + " passed");
+ } else {
+ console.log(stylize("All Passed ", "green") + passedTests + " run");
+ }
+ if (leaked.length > 0) {
+ console.log("");
+ console.warn(stylize("Global leak detected: ", "red") + leaked.join(', '));
+ }
+
+ if (leaked.length || failedTests) {
+ //process.exit(1);
+ process.on('exit', function() { process.reallyExit(1) });
+ }
+ }
+ }
+
+ function toCSS(options, path, callback) {
+ var css;
+ options = options || {};
+ fs.readFile(path, 'utf8', function (e, str) {
+ if (e) { return callback(e); }
+
+ options.paths = [require('path').dirname(path)];
+ options.filename = require('path').resolve(process.cwd(), path);
+ options.optimization = options.optimization || 0;
+
+ var parser = new(less.Parser)(options);
+ var additionalData = {};
+ if (options.globalVars) {
+ additionalData.globalVars = options.getVars(path);
+ } else if (options.modifyVars) {
+ additionalData.modifyVars = options.getVars(path);
+ }
+ if (options.banner) {
+ additionalData.banner = options.banner;
+ }
+ parser.parse(str, function (err, tree) {
+ if (err) {
+ callback(err);
+ } else {
+ try {
+ css = tree.toCSS(options);
+ var css2 = tree.toCSS(options); // integration test that 2nd call gets same output
+ if (css2 !== css) { throw new Error("css not equal to 2nd call"); }
+ callback(null, css);
+ } catch (e) {
+ callback(e);
+ }
+ }
+ }, additionalData);
+ });
+ }
+
+ function testNoOptions() {
+ totalTests++;
+ try {
+ sys.print("- Integration - creating parser without options: ");
+ new(less.Parser)();
+ } catch(e) {
+ fail(stylize("FAIL\n", "red"));
+ return;
+ }
+ ok(stylize("OK\n", "green"));
+ }
+
+ return {
+ runTestSet: runTestSet,
+ testErrors: testErrors,
+ testSourcemap: testSourcemap,
+ testNoOptions: testNoOptions
+ };
+};
diff --git a/test/less/charsets.less b/test/less/charsets.less
new file mode 100644
index 00000000..550d40e9
--- /dev/null
+++ b/test/less/charsets.less
@@ -0,0 +1,3 @@
+@charset "UTF-8";
+
+@import "import/import-charset-test";
\ No newline at end of file
diff --git a/test/less/colors.less b/test/less/colors.less
new file mode 100644
index 00000000..7abda4e5
--- /dev/null
+++ b/test/less/colors.less
@@ -0,0 +1,98 @@
+#yelow {
+ #short {
+ color: #fea;
+ }
+ #long {
+ color: #ffeeaa;
+ }
+ #rgba {
+ color: rgba(255, 238, 170, 0.1);
+ }
+ #argb {
+ color: argb(rgba(255, 238, 170, 0.1));
+ }
+}
+
+#blue {
+ #short {
+ color: #00f;
+ }
+ #long {
+ color: #0000ff;
+ }
+ #rgba {
+ color: rgba(0, 0, 255, 0.1);
+ }
+ #argb {
+ color: argb(rgba(0, 0, 255, 0.1));
+ }
+}
+
+#alpha #hsla {
+ color: hsla(11, 20%, 20%, 0.6);
+}
+
+#overflow {
+ .a { color: (#111111 - #444444); } // #000000
+ .b { color: (#eee + #fff); } // #ffffff
+ .c { color: (#aaa * 3); } // #ffffff
+ .d { color: (#00ee00 + #009900); } // #00ff00
+ .e { color: rgba(-99.9, 31.4159, 321, 0.42); }
+}
+
+#grey {
+ color: rgb(200, 200, 200);
+}
+
+#333333 {
+ color: rgb(20%, 20%, 20%);
+}
+
+#808080 {
+ color: hsl(50, 0%, 50%);
+}
+
+#00ff00 {
+ color: hsl(120, 100%, 50%);
+}
+
+.lightenblue {
+ color: lighten(blue, 10%);
+}
+
+.darkenblue {
+ color: darken(blue, 10%);
+}
+
+.unknowncolors {
+ color: blue2;
+ border: 2px solid superred;
+}
+
+.transparent {
+ color: transparent;
+ background-color: rgba(0, 0, 0, 0);
+}
+#alpha {
+ @colorvar: rgba(150, 200, 150, 0.7);
+ #fromvar {
+ opacity: alpha(@colorvar);
+ }
+ #short {
+ opacity: alpha(#aaa);
+ }
+ #long {
+ opacity: alpha(#bababa);
+ }
+ #rgba {
+ opacity: alpha(rgba(50, 120, 95, 0.2));
+ }
+ #hsl {
+ opacity: alpha(hsl(120, 100%, 50%));
+ }
+}
+
+#percentage {
+ color: red(rgb(100%, 0, 0));
+ border-color: rgba(100%, 0, 0, 50%);
+}
diff --git a/test/less/comments.less b/test/less/comments.less
new file mode 100644
index 00000000..7859911e
--- /dev/null
+++ b/test/less/comments.less
@@ -0,0 +1,83 @@
+/******************\
+* *
+* Comment Header *
+* *
+\******************/
+
+/*
+
+ Comment
+
+*/
+
+/*
+ * Comment Test
+ *
+ * - cloudhead (http://cloudhead.net)
+ *
+ */
+
+////////////////
+@var: "content";
+////////////////
+
+/* Colors
+ * ------
+ * #EDF8FC (background blue)
+ * #166C89 (darkest blue)
+ *
+ * Text:
+ * #333 (standard text) // A comment within a comment!
+ * #1F9EC9 (standard link)
+ *
+ */
+
+/* @group Variables
+------------------- */
+#comments /* boo *//* boo again*/,
+//.commented_out1
+//.commented_out2
+//.commented_out3
+.comments //end of comments1
+//end of comments2
+{
+ /**/ // An empty comment
+ color: red; /* A C-style comment */ /* A C-style comment */
+ background-color: orange; // A little comment
+ font-size: 12px;
+
+ /* lost comment */ content: @var;
+
+ border: 1px solid black;
+
+ // padding & margin //
+ padding: 0; // }{ '"
+ margin: 2em;
+} //
+
+/* commented out
+ #more-comments {
+ color: grey;
+ }
+*/
+
+.selector /* .with */, .lots, /* of */ .comments {
+ color: grey, /* blue */ orange;
+ -webkit-border-radius: 2px /* webkit only */;
+ -moz-border-radius: (2px * 4) /* moz only with operation */;
+}
+
+.mixin_def_with_colors(@a: white, // in
+ @b: 1px //put in @b - causes problems! --->
+ ) // the
+ when (@a = white) {
+ .test {
+ color: @b;
+ }
+}
+.mixin_def_with_colors();
+
+#last { color: blue }
+//
+
+/* *//* { *//* *//* *//* */#div { color:#A33; }/* } */
diff --git a/test/less/compression/compression.less b/test/less/compression/compression.less
new file mode 100644
index 00000000..c196336a
--- /dev/null
+++ b/test/less/compression/compression.less
@@ -0,0 +1,36 @@
+#colours {
+ color1: #fea;
+ color2: #ffeeaa;
+ color3: rgba(255, 238, 170, 0.1);
+ @color1: #fea;
+ string: "@{color1}";
+ /* comments are stripped */
+ // both types!
+ /*! but not this type
+ Note preserved whitespace
+ */
+}
+dimensions {
+ val: 0.1px;
+ val: 0em;
+ val: 4cm;
+ val: 0.2;
+ val: 5;
+ angles-must-have-unit: 0deg;
+ durations-must-have-unit: 0s;
+ length-doesnt-have-unit: 0px;
+ width: auto\9;
+}
+@page {
+ marks: none;
+@top-left-corner {
+ vertical-align: top;
+}
+@top-left {
+ vertical-align: top;
+}
+}
+.shadow ^ .dom,
+body ^^ .shadow {
+ display: done;
+}
diff --git a/test/less/css-3.less b/test/less/css-3.less
new file mode 100644
index 00000000..c054dc48
--- /dev/null
+++ b/test/less/css-3.less
@@ -0,0 +1,133 @@
+.comma-delimited {
+ text-shadow: -1px -1px 1px red, 6px 5px 5px yellow;
+ -moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset,
+ 0pt 4px 6px rgba(255, 255, 255, 0.4) inset;
+ -webkit-transform: rotate(-0.0000000001deg);
+}
+@font-face {
+ font-family: Headline;
+ unicode-range: U+??????, U+0???, U+0-7F, U+A5;
+}
+.other {
+ -moz-transform: translate(0, 11em) rotate(-90deg);
+ transform: rotateX(45deg);
+}
+.item[data-cra_zy-attr1b-ut3=bold] {
+ font-weight: bold;
+}
+p:not([class*="lead"]) {
+ color: black;
+}
+
+input[type="text"].class#id[attr=32]:not(1) {
+ color: white;
+}
+
+div#id.class[a=1][b=2].class:not(1) {
+ color: white;
+}
+
+ul.comma > li:not(:only-child)::after {
+ color: white;
+}
+
+ol.comma > li:nth-last-child(2)::after {
+ color: white;
+}
+
+li:nth-child(4n+1),
+li:nth-child(-5n),
+li:nth-child(-n+2) {
+ color: white;
+}
+
+a[href^="http://"] {
+ color: black;
+}
+
+a[href$="http://"] {
+ color: black;
+}
+
+form[data-disabled] {
+ color: black;
+}
+
+p::before {
+ color: black;
+}
+
+#issue322 {
+ -webkit-animation: anim2 7s infinite ease-in-out;
+}
+
+@-webkit-keyframes frames {
+ 0% { border: 1px }
+ 5.5% { border: 2px }
+ 100% { border: 3px }
+}
+
+@keyframes fontbulger1 {
+ to {
+ font-size: 15px;
+ }
+ from,to {
+ font-size: 12px;
+ }
+ 0%,100% {
+ font-size: 12px;
+ }
+}
+
+.units {
+ font: 1.2rem/2rem;
+ font: 8vw/9vw;
+ font: 10vh/12vh;
+ font: 12vm/15vm;
+ font: 12vmin/15vmin;
+ font: 1.2ch/1.5ch;
+}
+
+@supports ( box-shadow: 2px 2px 2px black ) or
+ ( -moz-box-shadow: 2px 2px 2px black ) {
+ .outline {
+ box-shadow: 2px 2px 2px black;
+ -moz-box-shadow: 2px 2px 2px black;
+ }
+}
+
+@-x-document url-prefix(""github.com"") {
+ h1 {
+ color: red;
+ }
+}
+
+@viewport {
+ font-size: 10px;
+}
+@namespace foo url(http://www.example.com);
+
+foo|h1 { color: blue; }
+foo|* { color: yellow; }
+|h1 { color: red; }
+*|h1 { color: green; }
+h1 { color: green; }
+.upper-test {
+ UpperCaseProperties: allowed;
+}
+@host {
+ div {
+ display: block;
+ }
+}
+::distributed(input::placeholder) {
+ color: #b3b3b3;
+}
+.shadow ^ .dom,
+body ^^ .shadow {
+ display: done;
+}
+
+#issue2066 {
+ background: url('/images/icon-team.svg') 0 0 / contain;
+}
diff --git a/test/less/css-escapes.less b/test/less/css-escapes.less
new file mode 100644
index 00000000..6a4b2830
--- /dev/null
+++ b/test/less/css-escapes.less
@@ -0,0 +1,33 @@
+@ugly: fuchsia;
+
+.escape\|random\|char {
+ color: red;
+}
+
+.mixin\!tUp {
+ font-weight: bold;
+}
+
+// class="404"
+.\34 04 {
+ background: red;
+
+ strong {
+ color: @ugly;
+ .mixin\!tUp;
+ }
+}
+
+.trailingTest\+ {
+ color: red;
+}
+
+/* This hideous test of hideousness checks for the selector "blockquote" with various permutations of hex escapes */
+\62\6c\6f \63 \6B \0071 \000075o\74 e {
+ color: silver;
+}
+
+[ng\:cloak],
+ng\:form {
+ display: none;
+}
diff --git a/test/less/css-guards.less b/test/less/css-guards.less
new file mode 100644
index 00000000..85ec8d29
--- /dev/null
+++ b/test/less/css-guards.less
@@ -0,0 +1,102 @@
+
+.light when (lightness(@a) > 50%) {
+ color: green;
+}
+.dark when (lightness(@a) < 50%) {
+ color: orange;
+}
+@a: #ddd;
+
+.see-the {
+ @a: #444; // this mirrors what mixins do - they evaluate the guards at the point of definition
+ .light();
+ .dark();
+}
+
+.hide-the {
+ .light();
+ .dark();
+}
+
+.multiple-conditions-1 when (@b = 1), (@c = 2), (@d = 3) {
+ color: red;
+}
+
+.multiple-conditions-2 when (@b = 1), (@c = 2), (@d = 2) {
+ color: blue;
+}
+
+@b: 2;
+@c: 3;
+@d: 3;
+
+.inheritance when (@b = 2) {
+ .test {
+ color: black;
+ }
+ &:hover {
+ color: pink;
+ }
+ .hideme when (@b = 1) {
+ color: green;
+ }
+ & when (@b = 1) {
+ hideme: green;
+ }
+}
+
+.hideme when (@b = 1) {
+ .test {
+ color: black;
+ }
+ &:hover {
+ color: pink;
+ }
+ .hideme when (@b = 1) {
+ color: green;
+ }
+}
+
+& when (@b = 1) {
+ .hideme {
+ color: red;
+ }
+}
+
+.mixin-with-guard-inside(@colWidth) {
+ // selector with guard (applies also to & when() ...)
+ .clsWithGuard when (@colWidth <= 0) {
+ dispaly: none;
+ }
+}
+
+.mixin-with-guard-inside(0px);
+
+.dont-split-me-up {
+ width: 1px;
+ & when (@c = 3) {
+ color: red;
+ }
+ & when (@c = 3) {
+ height: 1px;
+ }
+ + & when (@c = 3) { // creates invalid css but tests that we don't fold it in
+ sibling: true;
+ }
+}
+
+.scope-check when (@c = 3) {
+ @k: 1px;
+ & when (@c = 3) {
+ @k: 2px;
+ sub-prop: @k;
+ }
+ prop: @k;
+}
+.scope-check-2 {
+ .scope-check();
+ @k:4px;
+}
+.errors-if-called when (@c = never) {
+ .mixin-doesnt-exist();
+}
\ No newline at end of file
diff --git a/test/less/css.less b/test/less/css.less
new file mode 100644
index 00000000..766bdd4d
--- /dev/null
+++ b/test/less/css.less
@@ -0,0 +1,108 @@
+@charset "utf-8";
+div { color: black; }
+div { width: 99%; }
+
+* {
+ min-width: 45em;
+}
+
+h1, h2 > a > p, h3 {
+ color: none;
+}
+
+div.class {
+ color: blue;
+}
+
+div#id {
+ color: green;
+}
+
+.class#id {
+ color: purple;
+}
+
+.one.two.three {
+ color: grey;
+}
+
+@media print {
+ * {
+ font-size: 3em;
+ }
+}
+
+@media screen {
+ * {
+ font-size: 10px;
+ }
+}
+
+@font-face {
+ font-family: 'Garamond Pro';
+}
+
+a:hover, a:link {
+ color: #999;
+}
+
+p, p:first-child {
+ text-transform: none;
+}
+
+q:lang(no) {
+ quotes: none;
+}
+
+p + h1 {
+ font-size: +2.2em;
+}
+
+#shorthands {
+ border: 1px solid #000;
+ font: 12px/16px Arial;
+ font: 100%/16px Arial;
+ margin: 1px 0;
+ padding: 0 auto;
+}
+
+#more-shorthands {
+ margin: 0;
+ padding: 1px 0 2px 0;
+ font: normal small/20px 'Trebuchet MS', Verdana, sans-serif;
+ font: 0/0 a;
+ border-radius: 5px / 10px;
+}
+
+.misc {
+ -moz-border-radius: 2px;
+ display: -moz-inline-stack;
+ width: .1em;
+ background-color: #009998;
+ background: -webkit-gradient(linear, left top, left bottom, from(red), to(blue));
+ margin: ;
+ .nested-multiple {
+ multiple-semi-colons: yes;;;;;;
+ };
+ filter: alpha(opacity=100);
+ width: auto\9;
+}
+
+#important {
+ color: red !important;
+ width: 100%!important;
+ height: 20px ! important;
+}
+
+.def-font(@name) {
+ @font-face {
+ font-family: @name
+ }
+}
+
+.def-font(font-a);
+.def-font(font-b);
+
+.æøå {
+ margin: 0;
+}
diff --git a/test/less/debug/import/test.less b/test/less/debug/import/test.less
new file mode 100644
index 00000000..795082f5
--- /dev/null
+++ b/test/less/debug/import/test.less
@@ -0,0 +1,25 @@
+@charset "ISO-8859-1";
+
+.mixin_import1() {
+ @media all {
+ .tst {
+ color: black;
+ @media screen {
+ color: red;
+ .tst3 {
+ color: white;
+ }
+ }
+ }
+ }
+}
+
+.mixin_import2() {
+ .tst2 {
+ color: white;
+ }
+}
+
+.tst3 {
+ color: grey;
+}
\ No newline at end of file
diff --git a/test/less/debug/linenumbers.less b/test/less/debug/linenumbers.less
new file mode 100644
index 00000000..3bcaed01
--- /dev/null
+++ b/test/less/debug/linenumbers.less
@@ -0,0 +1,33 @@
+@charset "UTF-8";
+
+@import "import/test.less";
+
+.start() {
+ .test2 {
+ color: red;
+ }
+}
+
+.mix() {
+ color: black;
+}
+
+.test1 {
+ .mix();
+}
+
+.start();
+
+.mixin_import1();
+
+.mixin_import2();
+
+@debug: 1;
+& when (@debug = 1) {
+ .test {
+ color: red;
+ & when (@debug = 1) {
+ width: 2;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/less/detached-rulesets.less b/test/less/detached-rulesets.less
new file mode 100644
index 00000000..6a98d890
--- /dev/null
+++ b/test/less/detached-rulesets.less
@@ -0,0 +1,103 @@
+@ruleset: {
+ color: black;
+ background: white;
+ };
+
+@a: 1px;
+.wrap-mixin(@ruleset) {
+ @a: hidden and if you see this in the output its a bug;
+ @b: visible;
+ @d: magic-frame; // same behaviour as mixin calls - falls back to this frame
+ .wrap-selector {
+ @c: visible;
+ @ruleset();
+ visible-one: @b;
+ visible-two: @c;
+ }
+};
+
+.wrap-mixin({
+ color: black;
+ one: @a;
+ @b: hidden and if you see this in the output its a bug;
+ @c: hidden and if you see this in the output its a bug;
+ four: @d;
+});
+
+.wrap-mixin(@ruleset: {
+ color: red;
+});
+
+.wrap-mixin(@ruleset);
+
+.desktop-and-old-ie(@rules) {
+ @media screen and (min-width: 1200) { @rules(); }
+ html.lt-ie9 & { @rules(); }
+}
+
+header {
+ background: blue;
+
+ .desktop-and-old-ie({
+ background: red;
+ });
+}
+
+.wrap-mixin-calls-wrap(@ruleset) {
+ .wrap-mixin(@ruleset);
+};
+
+.wrap-mixin({
+ test: extra-wrap;
+ .wrap-mixin-calls-wrap({
+ test: wrapped-twice;
+ });
+});
+
+.wrap-mixin({
+ test-func: unit(90px);
+ test-arithmetic: unit((9+9), px);
+});
+// without mixins
+@ruleset-2: {
+ b: 1;
+};
+.without-mixins {
+ @ruleset-2();
+}
+@my-ruleset: {
+ .my-selector {
+ @media tv {
+ background-color: black;
+ }
+ }
+ };
+@media (orientation:portrait) {
+ @my-ruleset();
+ .wrap-media-mixin({
+ @media tv {
+ .triple-wrapped-mq {
+ triple: true;
+ }
+ }
+ });
+}
+.wrap-media-mixin(@ruleset) {
+ @media widescreen {
+ @media print {
+ @ruleset();
+ }
+ @ruleset();
+ }
+ @ruleset();
+}
+// unlocking mixins
+@my-mixins: {
+ .mixin() {
+ test: test;
+ }
+};
+@my-mixins();
+.a {
+ .mixin();
+}
\ No newline at end of file
diff --git a/test/less/empty.less b/test/less/empty.less
new file mode 100644
index 00000000..e69de29b
diff --git a/test/less/errors/add-mixed-units.less b/test/less/errors/add-mixed-units.less
new file mode 100644
index 00000000..9b708de9
--- /dev/null
+++ b/test/less/errors/add-mixed-units.less
@@ -0,0 +1,3 @@
+.a {
+ error: (1px + 3em);
+}
\ No newline at end of file
diff --git a/test/less/errors/add-mixed-units.txt b/test/less/errors/add-mixed-units.txt
new file mode 100644
index 00000000..9ea45438
--- /dev/null
+++ b/test/less/errors/add-mixed-units.txt
@@ -0,0 +1,4 @@
+SyntaxError: Incompatible units. Change the units or use the unit function. Bad units: 'px' and 'em'. in {path}add-mixed-units.less on line 2, column 3:
+1 .a {
+2 error: (1px + 3em);
+3 }
diff --git a/test/less/errors/add-mixed-units2.less b/test/less/errors/add-mixed-units2.less
new file mode 100644
index 00000000..26631160
--- /dev/null
+++ b/test/less/errors/add-mixed-units2.less
@@ -0,0 +1,3 @@
+.a {
+ error: ((1px * 2px) + (3em * 3px));
+}
\ No newline at end of file
diff --git a/test/less/errors/add-mixed-units2.txt b/test/less/errors/add-mixed-units2.txt
new file mode 100644
index 00000000..ca34304f
--- /dev/null
+++ b/test/less/errors/add-mixed-units2.txt
@@ -0,0 +1,4 @@
+SyntaxError: Incompatible units. Change the units or use the unit function. Bad units: 'px*px' and 'em*px'. in {path}add-mixed-units2.less on line 2, column 3:
+1 .a {
+2 error: ((1px * 2px) + (3em * 3px));
+3 }
diff --git a/test/less/errors/at-rules-undefined-var.less b/test/less/errors/at-rules-undefined-var.less
new file mode 100644
index 00000000..a1473805
--- /dev/null
+++ b/test/less/errors/at-rules-undefined-var.less
@@ -0,0 +1,4 @@
+
+@keyframes @name {
+ 50% {width: 20px;}
+}
diff --git a/test/less/errors/at-rules-undefined-var.txt b/test/less/errors/at-rules-undefined-var.txt
new file mode 100644
index 00000000..48ca57c4
--- /dev/null
+++ b/test/less/errors/at-rules-undefined-var.txt
@@ -0,0 +1,4 @@
+NameError: variable @name is undefined in {path}at-rules-undefined-var.less on line 2, column 12:
+1
+2 @keyframes @name {
+3 50% {width: 20px;}
diff --git a/test/less/errors/bad-variable-declaration1.less b/test/less/errors/bad-variable-declaration1.less
new file mode 100644
index 00000000..c2dc6ac0
--- /dev/null
+++ b/test/less/errors/bad-variable-declaration1.less
@@ -0,0 +1 @@
+@@demo: "hi";
\ No newline at end of file
diff --git a/test/less/errors/bad-variable-declaration1.txt b/test/less/errors/bad-variable-declaration1.txt
new file mode 100644
index 00000000..5ae9d4a4
--- /dev/null
+++ b/test/less/errors/bad-variable-declaration1.txt
@@ -0,0 +1,2 @@
+ParseError: Unrecognised input in {path}bad-variable-declaration1.less on line 1, column 1:
+1 @@demo: "hi";
diff --git a/test/less/errors/color-func-invalid-color.less b/test/less/errors/color-func-invalid-color.less
new file mode 100644
index 00000000..5a1edd01
--- /dev/null
+++ b/test/less/errors/color-func-invalid-color.less
@@ -0,0 +1,3 @@
+.test {
+ color: color("NOT A COLOR");
+}
\ No newline at end of file
diff --git a/test/less/errors/color-func-invalid-color.txt b/test/less/errors/color-func-invalid-color.txt
new file mode 100644
index 00000000..08990c30
--- /dev/null
+++ b/test/less/errors/color-func-invalid-color.txt
@@ -0,0 +1,4 @@
+ArgumentError: error evaluating function `color`: argument must be a color keyword or 3/6 digit hex e.g. #FFF in {path}color-func-invalid-color.less on line 2, column 10:
+1 .test {
+2 color: color("NOT A COLOR");
+3 }
diff --git a/test/less/errors/color-invalid-hex-code.less b/test/less/errors/color-invalid-hex-code.less
new file mode 100644
index 00000000..0e6c5deb
--- /dev/null
+++ b/test/less/errors/color-invalid-hex-code.less
@@ -0,0 +1,3 @@
+.a {
+ @wrongHEXColorCode: #DCALLB;
+}
\ No newline at end of file
diff --git a/test/less/errors/color-invalid-hex-code.txt b/test/less/errors/color-invalid-hex-code.txt
new file mode 100644
index 00000000..0f8a82ce
--- /dev/null
+++ b/test/less/errors/color-invalid-hex-code.txt
@@ -0,0 +1,4 @@
+SyntaxError: Invalid HEX color code in {path}color-invalid-hex-code.less on line 2, column 29:
+1 .a {
+2 @wrongHEXColorCode: #DCALLB;
+3 }
diff --git a/test/less/errors/color-invalid-hex-code2.less b/test/less/errors/color-invalid-hex-code2.less
new file mode 100644
index 00000000..cb9a9b76
--- /dev/null
+++ b/test/less/errors/color-invalid-hex-code2.less
@@ -0,0 +1,3 @@
+.a {
+ @wrongHEXColorCode: #fffblack;
+}
\ No newline at end of file
diff --git a/test/less/errors/color-invalid-hex-code2.txt b/test/less/errors/color-invalid-hex-code2.txt
new file mode 100644
index 00000000..dd3996b1
--- /dev/null
+++ b/test/less/errors/color-invalid-hex-code2.txt
@@ -0,0 +1,4 @@
+SyntaxError: Invalid HEX color code in {path}color-invalid-hex-code2.less on line 2, column 29:
+1 .a {
+2 @wrongHEXColorCode: #fffblack;
+3 }
diff --git a/test/less/errors/comment-in-selector.less b/test/less/errors/comment-in-selector.less
new file mode 100644
index 00000000..a7d26396
--- /dev/null
+++ b/test/less/errors/comment-in-selector.less
@@ -0,0 +1 @@
+#gaga /* Comment */ span { color: red }
\ No newline at end of file
diff --git a/test/less/errors/comment-in-selector.txt b/test/less/errors/comment-in-selector.txt
new file mode 100644
index 00000000..e48f878c
--- /dev/null
+++ b/test/less/errors/comment-in-selector.txt
@@ -0,0 +1,2 @@
+ParseError: Unrecognised input in {path}comment-in-selector.less on line 1, column 21:
+1 #gaga /* Comment */ span { color: red }
diff --git a/test/less/errors/css-guard-default-func.less b/test/less/errors/css-guard-default-func.less
new file mode 100644
index 00000000..db6639e1
--- /dev/null
+++ b/test/less/errors/css-guard-default-func.less
@@ -0,0 +1,4 @@
+
+selector when (default()) {
+ color: red;
+}
diff --git a/test/less/errors/css-guard-default-func.txt b/test/less/errors/css-guard-default-func.txt
new file mode 100644
index 00000000..ea670295
--- /dev/null
+++ b/test/less/errors/css-guard-default-func.txt
@@ -0,0 +1,4 @@
+SyntaxError: error evaluating function `default`: it is currently only allowed in parametric mixin guards, in {path}css-guard-default-func.less on line 2, column 16:
+1
+2 selector when (default()) {
+3 color: red;
diff --git a/test/less/errors/detached-ruleset-1.less b/test/less/errors/detached-ruleset-1.less
new file mode 100644
index 00000000..ac5b8db0
--- /dev/null
+++ b/test/less/errors/detached-ruleset-1.less
@@ -0,0 +1,6 @@
+@a: {
+ b: 1;
+};
+.a {
+ a: @a;
+}
\ No newline at end of file
diff --git a/test/less/errors/detached-ruleset-1.txt b/test/less/errors/detached-ruleset-1.txt
new file mode 100644
index 00000000..7407741c
--- /dev/null
+++ b/test/less/errors/detached-ruleset-1.txt
@@ -0,0 +1,4 @@
+SyntaxError: Rulesets cannot be evaluated on a property. in {path}detached-ruleset-1.less on line 5, column 3:
+4 .a {
+5 a: @a;
+6 }
diff --git a/test/less/errors/detached-ruleset-2.less b/test/less/errors/detached-ruleset-2.less
new file mode 100644
index 00000000..51a7af6b
--- /dev/null
+++ b/test/less/errors/detached-ruleset-2.less
@@ -0,0 +1,6 @@
+@a: {
+ b: 1;
+};
+.a {
+ a: @a();
+}
\ No newline at end of file
diff --git a/test/less/errors/detached-ruleset-2.txt b/test/less/errors/detached-ruleset-2.txt
new file mode 100644
index 00000000..f18e0935
--- /dev/null
+++ b/test/less/errors/detached-ruleset-2.txt
@@ -0,0 +1,4 @@
+ParseError: Unrecognised input in {path}detached-ruleset-2.less on line 5, column 3:
+4 .a {
+5 a: @a();
+6 }
diff --git a/test/less/errors/detached-ruleset-3.less b/test/less/errors/detached-ruleset-3.less
new file mode 100644
index 00000000..c50119d9
--- /dev/null
+++ b/test/less/errors/detached-ruleset-3.less
@@ -0,0 +1,4 @@
+@a: {
+ b: 1;
+};
+@a();
\ No newline at end of file
diff --git a/test/less/errors/detached-ruleset-3.txt b/test/less/errors/detached-ruleset-3.txt
new file mode 100644
index 00000000..15d281fa
--- /dev/null
+++ b/test/less/errors/detached-ruleset-3.txt
@@ -0,0 +1,4 @@
+SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}detached-ruleset-3.less on line 2, column 3:
+1 @a: {
+2 b: 1;
+3 };
diff --git a/test/less/errors/detached-ruleset-4.less b/test/less/errors/detached-ruleset-4.less
new file mode 100644
index 00000000..14ac314b
--- /dev/null
+++ b/test/less/errors/detached-ruleset-4.less
@@ -0,0 +1,5 @@
+.mixin-definition(@a: {
+ b: 1;
+}) {
+ @a();
+}
\ No newline at end of file
diff --git a/test/less/errors/detached-ruleset-4.txt b/test/less/errors/detached-ruleset-4.txt
new file mode 100644
index 00000000..d6d6526d
--- /dev/null
+++ b/test/less/errors/detached-ruleset-4.txt
@@ -0,0 +1,3 @@
+ParseError: Unrecognised input in {path}detached-ruleset-4.less on line 1, column 18:
+1 .mixin-definition(@a: {
+2 b: 1;
diff --git a/test/less/errors/detached-ruleset-5.less b/test/less/errors/detached-ruleset-5.less
new file mode 100644
index 00000000..174ebf35
--- /dev/null
+++ b/test/less/errors/detached-ruleset-5.less
@@ -0,0 +1,4 @@
+.mixin-definition(@b) {
+ @a();
+}
+.mixin-definition({color: red;});
\ No newline at end of file
diff --git a/test/less/errors/detached-ruleset-5.txt b/test/less/errors/detached-ruleset-5.txt
new file mode 100644
index 00000000..56189795
--- /dev/null
+++ b/test/less/errors/detached-ruleset-5.txt
@@ -0,0 +1,3 @@
+SyntaxError: variable @a is undefined in {path}detached-ruleset-5.less on line 4, column 1:
+3 }
+4 .mixin-definition({color: red;});
diff --git a/test/less/errors/detached-ruleset-6.less b/test/less/errors/detached-ruleset-6.less
new file mode 100644
index 00000000..121099f7
--- /dev/null
+++ b/test/less/errors/detached-ruleset-6.less
@@ -0,0 +1,5 @@
+.a {
+ b: {
+ color: red;
+ };
+}
\ No newline at end of file
diff --git a/test/less/errors/detached-ruleset-6.txt b/test/less/errors/detached-ruleset-6.txt
new file mode 100644
index 00000000..07840445
--- /dev/null
+++ b/test/less/errors/detached-ruleset-6.txt
@@ -0,0 +1,4 @@
+ParseError: Unrecognised input in {path}detached-ruleset-6.less on line 2, column 3:
+1 .a {
+2 b: {
+3 color: red;
diff --git a/test/less/errors/divide-mixed-units.less b/test/less/errors/divide-mixed-units.less
new file mode 100644
index 00000000..d228b7c4
--- /dev/null
+++ b/test/less/errors/divide-mixed-units.less
@@ -0,0 +1,3 @@
+.a {
+ error: (1px / 3em);
+}
\ No newline at end of file
diff --git a/test/less/errors/divide-mixed-units.txt b/test/less/errors/divide-mixed-units.txt
new file mode 100644
index 00000000..c189d2aa
--- /dev/null
+++ b/test/less/errors/divide-mixed-units.txt
@@ -0,0 +1,4 @@
+SyntaxError: Multiple units in dimension. Correct the units or use the unit function. Bad unit: px/em in {path}divide-mixed-units.less on line 2, column 3:
+1 .a {
+2 error: (1px / 3em);
+3 }
diff --git a/test/less/errors/extend-no-selector.less b/test/less/errors/extend-no-selector.less
new file mode 100644
index 00000000..84689ef3
--- /dev/null
+++ b/test/less/errors/extend-no-selector.less
@@ -0,0 +1,3 @@
+:extend(.a all) {
+ property: red;
+}
\ No newline at end of file
diff --git a/test/less/errors/extend-no-selector.txt b/test/less/errors/extend-no-selector.txt
new file mode 100644
index 00000000..bd2e3cd7
--- /dev/null
+++ b/test/less/errors/extend-no-selector.txt
@@ -0,0 +1,3 @@
+SyntaxError: Extend must be used to extend a selector, it cannot be used on its own in {path}extend-no-selector.less on line 1, column 17:
+1 :extend(.a all) {
+2 property: red;
diff --git a/test/less/errors/extend-not-at-end.less b/test/less/errors/extend-not-at-end.less
new file mode 100644
index 00000000..90ee512c
--- /dev/null
+++ b/test/less/errors/extend-not-at-end.less
@@ -0,0 +1,3 @@
+.a:extend(.b all).c {
+ property: red;
+}
\ No newline at end of file
diff --git a/test/less/errors/extend-not-at-end.txt b/test/less/errors/extend-not-at-end.txt
new file mode 100644
index 00000000..32ebedfc
--- /dev/null
+++ b/test/less/errors/extend-not-at-end.txt
@@ -0,0 +1,3 @@
+SyntaxError: Extend can only be used at the end of selector in {path}extend-not-at-end.less on line 1, column 21:
+1 .a:extend(.b all).c {
+2 property: red;
diff --git a/test/less/errors/import-missing.less b/test/less/errors/import-missing.less
new file mode 100644
index 00000000..5ce8e4d9
--- /dev/null
+++ b/test/less/errors/import-missing.less
@@ -0,0 +1,6 @@
+.a {
+ color: green;
+ // tests line number for import reference is correct
+}
+
+@import "file-does-not-exist.less";
\ No newline at end of file
diff --git a/test/less/errors/import-missing.txt b/test/less/errors/import-missing.txt
new file mode 100644
index 00000000..488d154a
--- /dev/null
+++ b/test/less/errors/import-missing.txt
@@ -0,0 +1,3 @@
+FileError: '{pathhref}file-does-not-exist.less' wasn't found{404status} in {path}import-missing.less on line 6, column 1:
+5
+6 @import "file-does-not-exist.less";
diff --git a/test/less/errors/import-no-semi.less b/test/less/errors/import-no-semi.less
new file mode 100644
index 00000000..bf2c7f65
--- /dev/null
+++ b/test/less/errors/import-no-semi.less
@@ -0,0 +1 @@
+@import "this-statement-is-invalid.less"
\ No newline at end of file
diff --git a/test/less/errors/import-no-semi.txt b/test/less/errors/import-no-semi.txt
new file mode 100644
index 00000000..8b3f795c
--- /dev/null
+++ b/test/less/errors/import-no-semi.txt
@@ -0,0 +1,2 @@
+ParseError: Unrecognised input in {path}import-no-semi.less on line 1, column 1:
+1 @import "this-statement-is-invalid.less"
diff --git a/test/less/errors/import-subfolder1.less b/test/less/errors/import-subfolder1.less
new file mode 100644
index 00000000..4280673b
--- /dev/null
+++ b/test/less/errors/import-subfolder1.less
@@ -0,0 +1 @@
+@import "imports/import-subfolder1.less";
\ No newline at end of file
diff --git a/test/less/errors/import-subfolder1.txt b/test/less/errors/import-subfolder1.txt
new file mode 100644
index 00000000..97629276
--- /dev/null
+++ b/test/less/errors/import-subfolder1.txt
@@ -0,0 +1,3 @@
+NameError: .mixin-not-defined is undefined in {path}mixin-not-defined.less on line 11, column 1:
+10
+11 .mixin-not-defined();
diff --git a/test/less/errors/import-subfolder2.less b/test/less/errors/import-subfolder2.less
new file mode 100644
index 00000000..a6b9b9ce
--- /dev/null
+++ b/test/less/errors/import-subfolder2.less
@@ -0,0 +1 @@
+@import "imports/import-subfolder2.less";
\ No newline at end of file
diff --git a/test/less/errors/import-subfolder2.txt b/test/less/errors/import-subfolder2.txt
new file mode 100644
index 00000000..b5b1a69b
--- /dev/null
+++ b/test/less/errors/import-subfolder2.txt
@@ -0,0 +1,4 @@
+ParseError: missing opening `{` in {path}parse-error-curly-bracket.less on line 4, column 1:
+3 }
+4 }
+5
diff --git a/test/less/errors/imports/import-subfolder1.less b/test/less/errors/imports/import-subfolder1.less
new file mode 100644
index 00000000..24ec0532
--- /dev/null
+++ b/test/less/errors/imports/import-subfolder1.less
@@ -0,0 +1 @@
+@import "subfolder/mixin-not-defined.less";
\ No newline at end of file
diff --git a/test/less/errors/imports/import-subfolder2.less b/test/less/errors/imports/import-subfolder2.less
new file mode 100644
index 00000000..6058ad14
--- /dev/null
+++ b/test/less/errors/imports/import-subfolder2.less
@@ -0,0 +1 @@
+@import "subfolder/parse-error-curly-bracket.less";
\ No newline at end of file
diff --git a/test/less/errors/imports/import-test.less b/test/less/errors/imports/import-test.less
new file mode 100644
index 00000000..a91ae054
--- /dev/null
+++ b/test/less/errors/imports/import-test.less
@@ -0,0 +1,4 @@
+.someclass
+{
+ font-weight: bold;
+}
\ No newline at end of file
diff --git a/test/less/errors/imports/subfolder/mixin-not-defined.less b/test/less/errors/imports/subfolder/mixin-not-defined.less
new file mode 100644
index 00000000..2bb2d091
--- /dev/null
+++ b/test/less/errors/imports/subfolder/mixin-not-defined.less
@@ -0,0 +1 @@
+@import "../../mixin-not-defined.less";
\ No newline at end of file
diff --git a/test/less/errors/imports/subfolder/parse-error-curly-bracket.less b/test/less/errors/imports/subfolder/parse-error-curly-bracket.less
new file mode 100644
index 00000000..f37fa9d0
--- /dev/null
+++ b/test/less/errors/imports/subfolder/parse-error-curly-bracket.less
@@ -0,0 +1 @@
+@import "../../parse-error-curly-bracket.less";
\ No newline at end of file
diff --git a/test/less/errors/javascript-error.less b/test/less/errors/javascript-error.less
new file mode 100644
index 00000000..9332a37d
--- /dev/null
+++ b/test/less/errors/javascript-error.less
@@ -0,0 +1,3 @@
+.scope {
+ var: `this.foo.toJS`;
+}
diff --git a/test/less/errors/javascript-error.txt b/test/less/errors/javascript-error.txt
new file mode 100644
index 00000000..c4da9508
--- /dev/null
+++ b/test/less/errors/javascript-error.txt
@@ -0,0 +1,4 @@
+SyntaxError: JavaScript evaluation error: 'TypeError: Cannot read property 'toJS' of undefined' in {path}javascript-error.less on line 2, column 25:
+1 .scope {
+2 var: `this.foo.toJS`;
+3 }
diff --git a/test/less/errors/javascript-undefined-var.less b/test/less/errors/javascript-undefined-var.less
new file mode 100644
index 00000000..7cd580c4
--- /dev/null
+++ b/test/less/errors/javascript-undefined-var.less
@@ -0,0 +1,3 @@
+.scope {
+ @a: `@{b}`;
+}
diff --git a/test/less/errors/javascript-undefined-var.txt b/test/less/errors/javascript-undefined-var.txt
new file mode 100644
index 00000000..b363aff9
--- /dev/null
+++ b/test/less/errors/javascript-undefined-var.txt
@@ -0,0 +1,4 @@
+NameError: variable @b is undefined in {path}javascript-undefined-var.less on line 2, column 15:
+1 .scope {
+2 @a: `@{b}`;
+3 }
diff --git a/test/less/errors/mixed-mixin-definition-args-1.less b/test/less/errors/mixed-mixin-definition-args-1.less
new file mode 100644
index 00000000..9b0e23af
--- /dev/null
+++ b/test/less/errors/mixed-mixin-definition-args-1.less
@@ -0,0 +1,6 @@
+.mixin(@a : 4, @b : 3, @c: 2) {
+ will: fail;
+}
+.mixin-test {
+ .mixin(@a: 5; @b: 6, @c: 7);
+}
\ No newline at end of file
diff --git a/test/less/errors/mixed-mixin-definition-args-1.txt b/test/less/errors/mixed-mixin-definition-args-1.txt
new file mode 100644
index 00000000..a07f5e9d
--- /dev/null
+++ b/test/less/errors/mixed-mixin-definition-args-1.txt
@@ -0,0 +1,4 @@
+SyntaxError: Cannot mix ; and , as delimiter types in {path}mixed-mixin-definition-args-1.less on line 5, column 30:
+4 .mixin-test {
+5 .mixin(@a: 5; @b: 6, @c: 7);
+6 }
diff --git a/test/less/errors/mixed-mixin-definition-args-2.less b/test/less/errors/mixed-mixin-definition-args-2.less
new file mode 100644
index 00000000..c9709427
--- /dev/null
+++ b/test/less/errors/mixed-mixin-definition-args-2.less
@@ -0,0 +1,6 @@
+.mixin(@a : 4, @b : 3, @c: 2) {
+ will: fail;
+}
+.mixin-test {
+ .mixin(@a: 5, @b: 6; @c: 7);
+}
diff --git a/test/less/errors/mixed-mixin-definition-args-2.txt b/test/less/errors/mixed-mixin-definition-args-2.txt
new file mode 100644
index 00000000..fa00183b
--- /dev/null
+++ b/test/less/errors/mixed-mixin-definition-args-2.txt
@@ -0,0 +1,4 @@
+SyntaxError: Cannot mix ; and , as delimiter types in {path}mixed-mixin-definition-args-2.less on line 5, column 26:
+4 .mixin-test {
+5 .mixin(@a: 5, @b: 6; @c: 7);
+6 }
diff --git a/test/less/errors/mixin-not-defined.less b/test/less/errors/mixin-not-defined.less
new file mode 100644
index 00000000..e2dad5ce
--- /dev/null
+++ b/test/less/errors/mixin-not-defined.less
@@ -0,0 +1,11 @@
+
+.error-is-further-on() {
+}
+
+.pad-here-to-reproduce-error-in() {
+}
+
+.the-import-subfolder-test() {
+}
+
+.mixin-not-defined();
\ No newline at end of file
diff --git a/test/less/errors/mixin-not-defined.txt b/test/less/errors/mixin-not-defined.txt
new file mode 100644
index 00000000..97629276
--- /dev/null
+++ b/test/less/errors/mixin-not-defined.txt
@@ -0,0 +1,3 @@
+NameError: .mixin-not-defined is undefined in {path}mixin-not-defined.less on line 11, column 1:
+10
+11 .mixin-not-defined();
diff --git a/test/less/errors/mixin-not-matched.less b/test/less/errors/mixin-not-matched.less
new file mode 100644
index 00000000..be0d6b1a
--- /dev/null
+++ b/test/less/errors/mixin-not-matched.less
@@ -0,0 +1,6 @@
+@saxofon:trumpete;
+
+.mixin(saxofon) {
+}
+
+.mixin(@saxofon);
\ No newline at end of file
diff --git a/test/less/errors/mixin-not-matched.txt b/test/less/errors/mixin-not-matched.txt
new file mode 100644
index 00000000..57df9772
--- /dev/null
+++ b/test/less/errors/mixin-not-matched.txt
@@ -0,0 +1,3 @@
+RuntimeError: No matching definition was found for `.mixin(trumpete)` in {path}mixin-not-matched.less on line 6, column 1:
+5
+6 .mixin(@saxofon);
diff --git a/test/less/errors/mixin-not-matched2.less b/test/less/errors/mixin-not-matched2.less
new file mode 100644
index 00000000..14f44bf3
--- /dev/null
+++ b/test/less/errors/mixin-not-matched2.less
@@ -0,0 +1,6 @@
+@saxofon:trumpete;
+
+.mixin(@a, @b) {
+}
+
+.mixin(@a: @saxofon);
\ No newline at end of file
diff --git a/test/less/errors/mixin-not-matched2.txt b/test/less/errors/mixin-not-matched2.txt
new file mode 100644
index 00000000..dceedaf0
--- /dev/null
+++ b/test/less/errors/mixin-not-matched2.txt
@@ -0,0 +1,3 @@
+RuntimeError: No matching definition was found for `.mixin(@a:trumpete)` in {path}mixin-not-matched2.less on line 6, column 1:
+5
+6 .mixin(@a: @saxofon);
diff --git a/test/less/errors/mixin-not-visible-in-scope-1.less b/test/less/errors/mixin-not-visible-in-scope-1.less
new file mode 100644
index 00000000..2842613e
--- /dev/null
+++ b/test/less/errors/mixin-not-visible-in-scope-1.less
@@ -0,0 +1,9 @@
+.something {
+ & {
+ .a {value: a}
+ }
+
+ & {
+ .b {.a} // was Err. before 1.6.2
+ }
+}
\ No newline at end of file
diff --git a/test/less/errors/mixin-not-visible-in-scope-1.txt b/test/less/errors/mixin-not-visible-in-scope-1.txt
new file mode 100644
index 00000000..15e64dc2
--- /dev/null
+++ b/test/less/errors/mixin-not-visible-in-scope-1.txt
@@ -0,0 +1,4 @@
+NameError: .a is undefined in {path}mixin-not-visible-in-scope-1.less on line 7, column 13:
+6 & {
+7 .b {.a} // was Err. before 1.6.2
+8 }
diff --git a/test/less/errors/mixins-guards-default-func-1.less b/test/less/errors/mixins-guards-default-func-1.less
new file mode 100644
index 00000000..dc90b86b
--- /dev/null
+++ b/test/less/errors/mixins-guards-default-func-1.less
@@ -0,0 +1,9 @@
+
+guard-default-func-conflict {
+ .m(@x, 1) {}
+ .m(@x, 2) when (default()) {}
+ .m(@x, 2) when (default()) {}
+
+ .m(1, 1);
+ .m(1, 2);
+}
diff --git a/test/less/errors/mixins-guards-default-func-1.txt b/test/less/errors/mixins-guards-default-func-1.txt
new file mode 100644
index 00000000..d123c21c
--- /dev/null
+++ b/test/less/errors/mixins-guards-default-func-1.txt
@@ -0,0 +1,4 @@
+RuntimeError: Ambiguous use of `default()` found when matching for `.m(1, 2)` in {path}mixins-guards-default-func-1.less on line 8, column 5:
+7 .m(1, 1);
+8 .m(1, 2);
+9 }
diff --git a/test/less/errors/mixins-guards-default-func-2.less b/test/less/errors/mixins-guards-default-func-2.less
new file mode 100644
index 00000000..079b5737
--- /dev/null
+++ b/test/less/errors/mixins-guards-default-func-2.less
@@ -0,0 +1,9 @@
+
+guard-default-func-conflict {
+ .m(1) {}
+ .m(@x) when not(default()) {}
+ .m(@x) when (@x = 3) and (default()) {}
+
+ .m(2);
+ .m(3);
+}
diff --git a/test/less/errors/mixins-guards-default-func-2.txt b/test/less/errors/mixins-guards-default-func-2.txt
new file mode 100644
index 00000000..7f7d7cce
--- /dev/null
+++ b/test/less/errors/mixins-guards-default-func-2.txt
@@ -0,0 +1,4 @@
+RuntimeError: Ambiguous use of `default()` found when matching for `.m(3)` in {path}mixins-guards-default-func-2.less on line 8, column 5:
+7 .m(2);
+8 .m(3);
+9 }
diff --git a/test/less/errors/mixins-guards-default-func-3.less b/test/less/errors/mixins-guards-default-func-3.less
new file mode 100644
index 00000000..ec357fa1
--- /dev/null
+++ b/test/less/errors/mixins-guards-default-func-3.less
@@ -0,0 +1,9 @@
+
+guard-default-func-conflict {
+ .m(1) {}
+ .m(@x) when not(default()) {}
+ .m(@x) when not(default()) {}
+
+ .m(1);
+ .m(2);
+}
diff --git a/test/less/errors/mixins-guards-default-func-3.txt b/test/less/errors/mixins-guards-default-func-3.txt
new file mode 100644
index 00000000..2a2728cc
--- /dev/null
+++ b/test/less/errors/mixins-guards-default-func-3.txt
@@ -0,0 +1,4 @@
+RuntimeError: Ambiguous use of `default()` found when matching for `.m(2)` in {path}mixins-guards-default-func-3.less on line 8, column 5:
+7 .m(1);
+8 .m(2);
+9 }
diff --git a/test/less/errors/multiple-guards-on-css-selectors.less b/test/less/errors/multiple-guards-on-css-selectors.less
new file mode 100644
index 00000000..4eabb60a
--- /dev/null
+++ b/test/less/errors/multiple-guards-on-css-selectors.less
@@ -0,0 +1,4 @@
+@ie8: true;
+.a when (@ie8 = true),
+.b {
+}
\ No newline at end of file
diff --git a/test/less/errors/multiple-guards-on-css-selectors.txt b/test/less/errors/multiple-guards-on-css-selectors.txt
new file mode 100644
index 00000000..3d23e26b
--- /dev/null
+++ b/test/less/errors/multiple-guards-on-css-selectors.txt
@@ -0,0 +1,4 @@
+SyntaxError: Guards are only currently allowed on a single selector. in {path}multiple-guards-on-css-selectors.less on line 3, column 1:
+2 .a when (@ie8 = true),
+3 .b {
+4 }
diff --git a/test/less/errors/multiple-guards-on-css-selectors2.less b/test/less/errors/multiple-guards-on-css-selectors2.less
new file mode 100644
index 00000000..4b1bc6ff
--- /dev/null
+++ b/test/less/errors/multiple-guards-on-css-selectors2.less
@@ -0,0 +1,4 @@
+@ie8: true;
+.a,
+.b when (@ie8 = true) {
+}
\ No newline at end of file
diff --git a/test/less/errors/multiple-guards-on-css-selectors2.txt b/test/less/errors/multiple-guards-on-css-selectors2.txt
new file mode 100644
index 00000000..d0e5a52b
--- /dev/null
+++ b/test/less/errors/multiple-guards-on-css-selectors2.txt
@@ -0,0 +1,4 @@
+SyntaxError: Guards are only currently allowed on a single selector. in {path}multiple-guards-on-css-selectors2.less on line 3, column 23:
+2 .a,
+3 .b when (@ie8 = true) {
+4 }
diff --git a/test/less/errors/multiply-mixed-units.less b/test/less/errors/multiply-mixed-units.less
new file mode 100644
index 00000000..ff983a85
--- /dev/null
+++ b/test/less/errors/multiply-mixed-units.less
@@ -0,0 +1,7 @@
+/* Test */
+#blah {
+ // blah
+}
+.a {
+ error: (1px * 1em);
+}
\ No newline at end of file
diff --git a/test/less/errors/multiply-mixed-units.txt b/test/less/errors/multiply-mixed-units.txt
new file mode 100644
index 00000000..9ed834f1
--- /dev/null
+++ b/test/less/errors/multiply-mixed-units.txt
@@ -0,0 +1,4 @@
+SyntaxError: Multiple units in dimension. Correct the units or use the unit function. Bad unit: em*px in {path}multiply-mixed-units.less on line 6, column 3:
+5 .a {
+6 error: (1px * 1em);
+7 }
diff --git a/test/less/errors/parens-error-1.less b/test/less/errors/parens-error-1.less
new file mode 100644
index 00000000..7c8ec10e
--- /dev/null
+++ b/test/less/errors/parens-error-1.less
@@ -0,0 +1,3 @@
+.a {
+ something: (12 (13 + 5 -23) + 5);
+}
\ No newline at end of file
diff --git a/test/less/errors/parens-error-1.txt b/test/less/errors/parens-error-1.txt
new file mode 100644
index 00000000..6fc40ac0
--- /dev/null
+++ b/test/less/errors/parens-error-1.txt
@@ -0,0 +1,4 @@
+SyntaxError: expected ')' got '(' in {path}parens-error-1.less on line 2, column 18:
+1 .a {
+2 something: (12 (13 + 5 -23) + 5);
+3 }
diff --git a/test/less/errors/parens-error-2.less b/test/less/errors/parens-error-2.less
new file mode 100644
index 00000000..4a392b8e
--- /dev/null
+++ b/test/less/errors/parens-error-2.less
@@ -0,0 +1,3 @@
+.a {
+ something: (12 * (13 + 5 -23));
+}
\ No newline at end of file
diff --git a/test/less/errors/parens-error-2.txt b/test/less/errors/parens-error-2.txt
new file mode 100644
index 00000000..cee5c52d
--- /dev/null
+++ b/test/less/errors/parens-error-2.txt
@@ -0,0 +1,4 @@
+SyntaxError: expected ')' got '-' in {path}parens-error-2.less on line 2, column 28:
+1 .a {
+2 something: (12 * (13 + 5 -23));
+3 }
diff --git a/test/less/errors/parens-error-3.less b/test/less/errors/parens-error-3.less
new file mode 100644
index 00000000..9e6d5405
--- /dev/null
+++ b/test/less/errors/parens-error-3.less
@@ -0,0 +1,3 @@
+.a {
+ something: (12 + (13 + 10 -23));
+}
\ No newline at end of file
diff --git a/test/less/errors/parens-error-3.txt b/test/less/errors/parens-error-3.txt
new file mode 100644
index 00000000..3280ef04
--- /dev/null
+++ b/test/less/errors/parens-error-3.txt
@@ -0,0 +1,4 @@
+SyntaxError: expected ')' got '-' in {path}parens-error-3.less on line 2, column 29:
+1 .a {
+2 something: (12 + (13 + 10 -23));
+3 }
diff --git a/test/less/errors/parse-error-curly-bracket.less b/test/less/errors/parse-error-curly-bracket.less
new file mode 100644
index 00000000..f78ceb70
--- /dev/null
+++ b/test/less/errors/parse-error-curly-bracket.less
@@ -0,0 +1,4 @@
+body {
+ background-color: #fff;
+ }
+}
diff --git a/test/less/errors/parse-error-curly-bracket.txt b/test/less/errors/parse-error-curly-bracket.txt
new file mode 100644
index 00000000..b5b1a69b
--- /dev/null
+++ b/test/less/errors/parse-error-curly-bracket.txt
@@ -0,0 +1,4 @@
+ParseError: missing opening `{` in {path}parse-error-curly-bracket.less on line 4, column 1:
+3 }
+4 }
+5
diff --git a/test/less/errors/parse-error-extra-parens.less b/test/less/errors/parse-error-extra-parens.less
new file mode 100644
index 00000000..46d023a9
--- /dev/null
+++ b/test/less/errors/parse-error-extra-parens.less
@@ -0,0 +1,5 @@
+@media (extra: bracket)) {
+ body {
+ background-color: #fff;
+ }
+}
diff --git a/test/less/errors/parse-error-extra-parens.txt b/test/less/errors/parse-error-extra-parens.txt
new file mode 100644
index 00000000..5c1aaef2
--- /dev/null
+++ b/test/less/errors/parse-error-extra-parens.txt
@@ -0,0 +1,3 @@
+ParseError: missing opening `(` in {path}parse-error-extra-parens.less on line 1, column 24:
+1 @media (extra: bracket)) {
+2 body {
diff --git a/test/less/errors/parse-error-missing-bracket.less b/test/less/errors/parse-error-missing-bracket.less
new file mode 100644
index 00000000..144a6edf
--- /dev/null
+++ b/test/less/errors/parse-error-missing-bracket.less
@@ -0,0 +1,2 @@
+body {
+ background-color: #fff;
diff --git a/test/less/errors/parse-error-missing-bracket.txt b/test/less/errors/parse-error-missing-bracket.txt
new file mode 100644
index 00000000..7db2716e
--- /dev/null
+++ b/test/less/errors/parse-error-missing-bracket.txt
@@ -0,0 +1,3 @@
+ParseError: missing closing `}` in {path}parse-error-missing-bracket.less on line 1, column 6:
+1 body {
+2 background-color: #fff;
diff --git a/test/less/errors/parse-error-missing-parens.less b/test/less/errors/parse-error-missing-parens.less
new file mode 100644
index 00000000..55d25791
--- /dev/null
+++ b/test/less/errors/parse-error-missing-parens.less
@@ -0,0 +1,5 @@
+@media (missing: bracket {
+ body {
+ background-color: #fff;
+ }
+}
diff --git a/test/less/errors/parse-error-missing-parens.txt b/test/less/errors/parse-error-missing-parens.txt
new file mode 100644
index 00000000..a7a67067
--- /dev/null
+++ b/test/less/errors/parse-error-missing-parens.txt
@@ -0,0 +1,3 @@
+ParseError: missing closing `)` in {path}parse-error-missing-parens.less on line 1, column 8:
+1 @media (missing: bracket {
+2 body {
diff --git a/test/less/errors/parse-error-with-import.less b/test/less/errors/parse-error-with-import.less
new file mode 100644
index 00000000..6be3de85
--- /dev/null
+++ b/test/less/errors/parse-error-with-import.less
@@ -0,0 +1,13 @@
+@import 'import/import-test.less';
+
+body
+{
+ font-family: arial, sans-serif;
+}
+
+nonsense;
+
+.clickable
+{
+ cursor: pointer;
+}
\ No newline at end of file
diff --git a/test/less/errors/parse-error-with-import.txt b/test/less/errors/parse-error-with-import.txt
new file mode 100644
index 00000000..07732c92
--- /dev/null
+++ b/test/less/errors/parse-error-with-import.txt
@@ -0,0 +1,4 @@
+ParseError: Unrecognised input in {path}parse-error-with-import.less on line 8, column 9:
+7
+8 nonsense;
+9
diff --git a/test/less/errors/percentage-missing-space.less b/test/less/errors/percentage-missing-space.less
new file mode 100644
index 00000000..247f7733
--- /dev/null
+++ b/test/less/errors/percentage-missing-space.less
@@ -0,0 +1,3 @@
+.a {
+ error: calc(1 %);
+}
\ No newline at end of file
diff --git a/test/less/errors/percentage-missing-space.txt b/test/less/errors/percentage-missing-space.txt
new file mode 100644
index 00000000..776d8d5d
--- /dev/null
+++ b/test/less/errors/percentage-missing-space.txt
@@ -0,0 +1,4 @@
+SyntaxError: Invalid % without number in {path}percentage-missing-space.less on line 2, column 3:
+1 .a {
+2 error: calc(1 %);
+3 }
diff --git a/test/less/errors/property-asterisk-only-name.less b/test/less/errors/property-asterisk-only-name.less
new file mode 100644
index 00000000..c6a9990c
--- /dev/null
+++ b/test/less/errors/property-asterisk-only-name.less
@@ -0,0 +1,3 @@
+a {
+ * : 1;
+}
\ No newline at end of file
diff --git a/test/less/errors/property-asterisk-only-name.txt b/test/less/errors/property-asterisk-only-name.txt
new file mode 100644
index 00000000..6adc6c69
--- /dev/null
+++ b/test/less/errors/property-asterisk-only-name.txt
@@ -0,0 +1,4 @@
+ParseError: Unrecognised input in {path}property-asterisk-only-name.less on line 2, column 5:
+1 a {
+2 * : 1;
+3 }
diff --git a/test/less/errors/property-ie5-hack.less b/test/less/errors/property-ie5-hack.less
new file mode 100644
index 00000000..51bf6e39
--- /dev/null
+++ b/test/less/errors/property-ie5-hack.less
@@ -0,0 +1,3 @@
+.test {
+ display/*/: block; /*sorry for IE5*/
+}
\ No newline at end of file
diff --git a/test/less/errors/property-ie5-hack.txt b/test/less/errors/property-ie5-hack.txt
new file mode 100644
index 00000000..e42ef90e
--- /dev/null
+++ b/test/less/errors/property-ie5-hack.txt
@@ -0,0 +1,4 @@
+ParseError: Unrecognised input in {path}property-ie5-hack.less on line 2, column 3:
+1 .test {
+2 display/*/: block; /*sorry for IE5*/
+3 }
diff --git a/test/less/errors/property-in-root.less b/test/less/errors/property-in-root.less
new file mode 100644
index 00000000..8fed4be3
--- /dev/null
+++ b/test/less/errors/property-in-root.less
@@ -0,0 +1,4 @@
+.a() {
+ prop:1;
+}
+.a();
\ No newline at end of file
diff --git a/test/less/errors/property-in-root.txt b/test/less/errors/property-in-root.txt
new file mode 100644
index 00000000..04b27766
--- /dev/null
+++ b/test/less/errors/property-in-root.txt
@@ -0,0 +1,4 @@
+SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}property-in-root.less on line 2, column 3:
+1 .a() {
+2 prop:1;
+3 }
diff --git a/test/less/errors/property-in-root2.less b/test/less/errors/property-in-root2.less
new file mode 100644
index 00000000..ce8656d1
--- /dev/null
+++ b/test/less/errors/property-in-root2.less
@@ -0,0 +1 @@
+@import "property-in-root";
\ No newline at end of file
diff --git a/test/less/errors/property-in-root2.txt b/test/less/errors/property-in-root2.txt
new file mode 100644
index 00000000..04b27766
--- /dev/null
+++ b/test/less/errors/property-in-root2.txt
@@ -0,0 +1,4 @@
+SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}property-in-root.less on line 2, column 3:
+1 .a() {
+2 prop:1;
+3 }
diff --git a/test/less/errors/property-in-root3.less b/test/less/errors/property-in-root3.less
new file mode 100644
index 00000000..056c2f72
--- /dev/null
+++ b/test/less/errors/property-in-root3.less
@@ -0,0 +1,4 @@
+prop:1;
+.a {
+ prop:1;
+}
\ No newline at end of file
diff --git a/test/less/errors/property-in-root3.txt b/test/less/errors/property-in-root3.txt
new file mode 100644
index 00000000..68ef9454
--- /dev/null
+++ b/test/less/errors/property-in-root3.txt
@@ -0,0 +1,3 @@
+SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}property-in-root3.less on line 1, column 1:
+1 prop:1;
+2 .a {
diff --git a/test/less/errors/property-interp-not-defined.less b/test/less/errors/property-interp-not-defined.less
new file mode 100644
index 00000000..544fd5f9
--- /dev/null
+++ b/test/less/errors/property-interp-not-defined.less
@@ -0,0 +1 @@
+a {outline-@{color}: green}
\ No newline at end of file
diff --git a/test/less/errors/property-interp-not-defined.txt b/test/less/errors/property-interp-not-defined.txt
new file mode 100644
index 00000000..2537f9ea
--- /dev/null
+++ b/test/less/errors/property-interp-not-defined.txt
@@ -0,0 +1,2 @@
+NameError: variable @color is undefined in {path}property-interp-not-defined.less on line 1, column 12:
+1 a {outline-@{color}: green}
diff --git a/test/less/errors/recursive-variable.less b/test/less/errors/recursive-variable.less
new file mode 100644
index 00000000..c1ca75f1
--- /dev/null
+++ b/test/less/errors/recursive-variable.less
@@ -0,0 +1 @@
+@bodyColor: darken(@bodyColor, 30%);
\ No newline at end of file
diff --git a/test/less/errors/recursive-variable.txt b/test/less/errors/recursive-variable.txt
new file mode 100644
index 00000000..eb616e7d
--- /dev/null
+++ b/test/less/errors/recursive-variable.txt
@@ -0,0 +1,2 @@
+NameError: Recursive variable definition for @bodyColor in {path}recursive-variable.less on line 1, column 20:
+1 @bodyColor: darken(@bodyColor, 30%);
diff --git a/test/less/errors/svg-gradient1.less b/test/less/errors/svg-gradient1.less
new file mode 100644
index 00000000..c069ff72
--- /dev/null
+++ b/test/less/errors/svg-gradient1.less
@@ -0,0 +1,3 @@
+.a {
+ a: svg-gradient(horizontal, black, white);
+}
\ No newline at end of file
diff --git a/test/less/errors/svg-gradient1.txt b/test/less/errors/svg-gradient1.txt
new file mode 100644
index 00000000..ec662fe6
--- /dev/null
+++ b/test/less/errors/svg-gradient1.txt
@@ -0,0 +1,4 @@
+ArgumentError: error evaluating function `svg-gradient`: svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center' in {path}svg-gradient1.less on line 2, column 6:
+1 .a {
+2 a: svg-gradient(horizontal, black, white);
+3 }
diff --git a/test/less/errors/svg-gradient2.less b/test/less/errors/svg-gradient2.less
new file mode 100644
index 00000000..ff14ef11
--- /dev/null
+++ b/test/less/errors/svg-gradient2.less
@@ -0,0 +1,3 @@
+.a {
+ a: svg-gradient(to bottom, black, orange, 45%, white);
+}
\ No newline at end of file
diff --git a/test/less/errors/svg-gradient2.txt b/test/less/errors/svg-gradient2.txt
new file mode 100644
index 00000000..7004115f
--- /dev/null
+++ b/test/less/errors/svg-gradient2.txt
@@ -0,0 +1,4 @@
+ArgumentError: error evaluating function `svg-gradient`: svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position] in {path}svg-gradient2.less on line 2, column 6:
+1 .a {
+2 a: svg-gradient(to bottom, black, orange, 45%, white);
+3 }
diff --git a/test/less/errors/svg-gradient3.less b/test/less/errors/svg-gradient3.less
new file mode 100644
index 00000000..8f185246
--- /dev/null
+++ b/test/less/errors/svg-gradient3.less
@@ -0,0 +1,3 @@
+.a {
+ a: svg-gradient(black, orange);
+}
\ No newline at end of file
diff --git a/test/less/errors/svg-gradient3.txt b/test/less/errors/svg-gradient3.txt
new file mode 100644
index 00000000..eb0b483e
--- /dev/null
+++ b/test/less/errors/svg-gradient3.txt
@@ -0,0 +1,4 @@
+ArgumentError: error evaluating function `svg-gradient`: svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position] in {path}svg-gradient3.less on line 2, column 6:
+1 .a {
+2 a: svg-gradient(black, orange);
+3 }
diff --git a/test/less/errors/unit-function.less b/test/less/errors/unit-function.less
new file mode 100644
index 00000000..119e9818
--- /dev/null
+++ b/test/less/errors/unit-function.less
@@ -0,0 +1,3 @@
+.a {
+ font-size: unit(80/16,rem);
+}
\ No newline at end of file
diff --git a/test/less/errors/unit-function.txt b/test/less/errors/unit-function.txt
new file mode 100644
index 00000000..baf90f42
--- /dev/null
+++ b/test/less/errors/unit-function.txt
@@ -0,0 +1,4 @@
+ArgumentError: error evaluating function `unit`: the first argument to unit must be a number. Have you forgotten parenthesis? in {path}unit-function.less on line 2, column 14:
+1 .a {
+2 font-size: unit(80/16,rem);
+3 }
diff --git a/test/less/extend-chaining.less b/test/less/extend-chaining.less
new file mode 100644
index 00000000..aad221ea
--- /dev/null
+++ b/test/less/extend-chaining.less
@@ -0,0 +1,91 @@
+//very simple chaining
+.a {
+ color: black;
+}
+.b:extend(.a) {}
+.c:extend(.b) {}
+
+//very simple chaining, ordering not important
+
+.d:extend(.e) {}
+.e:extend(.f) {}
+.f {
+ color: black;
+}
+
+//extend with all
+
+.g.h {
+ color: black;
+}
+.i.j:extend(.g all) {
+ color: white;
+}
+.k:extend(.i all) {}
+
+//extend multi-chaining
+
+.l {
+ color: black;
+}
+.m:extend(.l){}
+.n:extend(.m){}
+.o:extend(.n){}
+.p:extend(.o){}
+.q:extend(.p){}
+.r:extend(.q){}
+.s:extend(.r){}
+.t:extend(.s){}
+
+// self referencing is ignored
+
+.u {color: black;}
+.v.u.v:extend(.u all){}
+
+// circular reference because the new extend product will match the existing extend
+
+.w:extend(.w) {color: black;}
+.v.w.v:extend(.w all){}
+
+// classic circular references
+
+.x:extend(.z) {
+ color: x;
+}
+.y:extend(.x) {
+ color: y;
+}
+.z:extend(.y) {
+ color: z;
+}
+
+//very simple chaining, but with the extend inside the ruleset
+.va {
+ color: black;
+}
+.vb {
+ &:extend(.va);
+ color: white;
+}
+.vc {
+ &:extend(.vb);
+}
+
+// media queries - dont extend outside, do extend inside
+
+@media tv {
+ .ma:extend(.a,.b,.c,.d,.e,.f,.g,.h,.i,.j,.k,.l,.m,.n,.o,.p,.q,.r,.s,.t,.u,.v,.w,.x,.y,.z,.md) {
+ color: black;
+ }
+ .md {
+ color: white;
+ }
+ @media plasma {
+ .me, .mf {
+ &:extend(.mb,.md);
+ background: red;
+ }
+ }
+}
+.mb:extend(.ma) {};
+.mc:extend(.mb) {};
\ No newline at end of file
diff --git a/test/less/extend-clearfix.less b/test/less/extend-clearfix.less
new file mode 100644
index 00000000..82445dfa
--- /dev/null
+++ b/test/less/extend-clearfix.less
@@ -0,0 +1,19 @@
+.clearfix {
+ *zoom: 1;
+ &:after {
+ content: '';
+ display: block;
+ clear: both;
+ height: 0;
+ }
+}
+
+.foo {
+ &:extend(.clearfix all);
+ color: red;
+}
+
+.bar {
+ &:extend(.clearfix all);
+ color: blue;
+}
diff --git a/test/less/extend-exact.less b/test/less/extend-exact.less
new file mode 100644
index 00000000..41dc4130
--- /dev/null
+++ b/test/less/extend-exact.less
@@ -0,0 +1,46 @@
+.replace.replace,
+.c.replace + .replace {
+ .replace,
+ .c {
+ prop: copy-paste-replace;
+ }
+}
+.rep_ace:extend(.replace.replace .replace) {}
+
+.a .b .c {
+ prop: not_effected;
+}
+
+.a {
+ prop: is_effected;
+ .b {
+ prop: not_effected;
+ }
+ .b.c {
+ prop: not_effected;
+ }
+}
+
+.c, .a {
+ .b, .a {
+ .a, .c {
+ prop: not_effected;
+ }
+ }
+}
+
+.effected {
+ &:extend(.a);
+ &:extend(.b);
+ &:extend(.c);
+}
+
+.e {
+ && {
+ prop: extend-double;
+ &:hover {
+ hover: not-extended;
+ }
+ }
+}
+.dbl:extend(.e.e) {}
diff --git a/test/less/extend-media.less b/test/less/extend-media.less
new file mode 100644
index 00000000..1b22c3fa
--- /dev/null
+++ b/test/less/extend-media.less
@@ -0,0 +1,24 @@
+.ext1 .ext2 {
+ background: black;
+}
+
+@media tv {
+ .ext1 .ext3 {
+ color: white;
+ }
+ .tv-lowres :extend(.ext1 all) {
+ background: blue;
+ }
+ @media hires {
+ .ext1 .ext4 {
+ color: green;
+ }
+ .tv-hires :extend(.ext1 all) {
+ background: red;
+ }
+ }
+}
+
+.all:extend(.ext1 all) {
+
+}
\ No newline at end of file
diff --git a/test/less/extend-nest.less b/test/less/extend-nest.less
new file mode 100644
index 00000000..9d4d27bb
--- /dev/null
+++ b/test/less/extend-nest.less
@@ -0,0 +1,65 @@
+.sidebar {
+ width: 300px;
+ background: red;
+
+ .box {
+ background: #FFF;
+ border: 1px solid #000;
+ margin: 10px 0;
+ }
+}
+
+.sidebar2 {
+ &:extend(.sidebar all);
+ background: blue;
+}
+
+.type1 {
+ .sidebar3 {
+ &:extend(.sidebar all);
+ background: green;
+ }
+}
+
+.type2 {
+ &.sidebar4 {
+ &:extend(.sidebar all);
+ background: red;
+ }
+}
+
+.button {
+ color: black;
+ &:hover {
+ color: white;
+ }
+}
+.submit {
+ &:extend(.button);
+ &:hover:extend(.button:hover) {}
+}
+
+.nomatch {
+ &:hover:extend(.button :hover) {}
+}
+
+.button2 {
+ :hover {
+ nested: white;
+ }
+}
+.button2 :hover {
+ notnested: black;
+}
+
+.nomatch :extend(.button2:hover) {}
+
+.amp-test-a,
+.amp-test-b {
+ .amp-test-c &.amp-test-d&.amp-test-e {
+ .amp-test-f&+&.amp-test-g:extend(.amp-test-h) {}
+ }
+}
+.amp-test-h {
+ test: extended by masses of selectors;
+}
\ No newline at end of file
diff --git a/test/less/extend-selector.less b/test/less/extend-selector.less
new file mode 100644
index 00000000..c7588ee0
--- /dev/null
+++ b/test/less/extend-selector.less
@@ -0,0 +1,99 @@
+.error {
+ border: 1px #f00;
+ background: #fdd;
+}
+.error.intrusion {
+ font-size: 1.3em;
+ font-weight: bold;
+}
+.intrusion .error {
+ display: none;
+}
+.badError:extend(.error all) {
+ border-width: 3px;
+}
+
+.foo .bar, .foo .baz {
+ display: none;
+}
+
+.ext1 .ext2
+ :extend(.foo all) {
+}
+
+.ext3:extend(.foo all),
+.ext4:extend(.foo all) {
+}
+
+div.ext5,
+.ext6 > .ext5 {
+ width: 100px;
+}
+
+.should-not-exist-in-output,
+.ext7:extend(.ext5 all) {
+}
+
+.ext {
+ test: 1;
+}
+// same as
+// .a .c:extend(.ext all)
+// .b .c:extend(.ext all)
+// .a .c .d
+// .b .c .d
+.a, .b {
+ test: 2;
+ .c:extend(.ext all) {
+ test: 3;
+ .d {
+ test: 4;
+ }
+ }
+}
+
+.replace.replace,
+.c.replace + .replace {
+ .replace,
+ .c {
+ prop: copy-paste-replace;
+ }
+}
+.rep_ace:extend(.replace all) {}
+
+.attributes {
+ [data="test"] {
+ extend: attributes;
+ }
+ .attribute-test {
+ &:extend([data="test"] all);
+ }
+ [data] {
+ extend: attributes2;
+ }
+ .attribute-test2 {
+ &:extend([data] all); //you could argue it should match [data="test"]... not for now though...
+ }
+ @attr-data: "test3";
+ [data=@{attr-data}] {
+ extend: attributes2;
+ }
+ .attribute-test {
+ &:extend([data="test3"] all);
+ }
+}
+
+.header {
+ .header-nav {
+ background: red;
+ &:before {
+ background: blue;
+ }
+ }
+}
+
+.footer {
+ .footer-nav {
+ &:extend( .header .header-nav all );
+ }
+}
\ No newline at end of file
diff --git a/test/less/extend.less b/test/less/extend.less
new file mode 100644
index 00000000..1db5d431
--- /dev/null
+++ b/test/less/extend.less
@@ -0,0 +1,81 @@
+.error {
+ border: 1px #f00;
+ background: #fdd;
+}
+.error.intrusion {
+ font-size: 1.3em;
+ font-weight: bold;
+}
+.intrusion .error {
+ display: none;
+}
+.badError {
+ &:extend(.error all);
+ border-width: 3px;
+}
+
+.foo .bar, .foo .baz {
+ display: none;
+}
+
+.ext1 .ext2 {
+ &:extend(.foo all);
+}
+
+.ext3,
+.ext4 {
+ &:extend(.foo all);
+ &:extend(.bar all);
+}
+
+div.ext5,
+.ext6 > .ext5 {
+ width: 100px;
+}
+
+.ext7 {
+ &:extend(.ext5 all);
+}
+
+.ext8.ext9 {
+ result: add-foo;
+}
+.ext8 .ext9,
+.ext8 + .ext9,
+.ext8 > .ext9 {
+ result: bar-matched;
+}
+.ext8.nomatch {
+ result: none;
+}
+.ext8 {
+ .ext9 {
+ result: match-nested-bar;
+ }
+}
+.ext8 {
+ &.ext9 {
+ result: match-nested-foo;
+ }
+}
+
+.fuu:extend(.ext8.ext9 all) {}
+.buu:extend(.ext8 .ext9 all) {}
+.zap:extend(.ext8 + .ext9 all) {}
+.zoo:extend(.ext8 > .ext9 all) {}
+
+.aa {
+ color: black;
+ .dd {
+ background: red;
+ }
+}
+.bb {
+ background: red;
+ .bb {
+ color: black;
+ }
+}
+.cc:extend(.aa,.bb) {}
+.ee:extend(.dd all,.bb) {}
+.ff:extend(.dd,.bb all) {}
\ No newline at end of file
diff --git a/test/less/extract-and-length.less b/test/less/extract-and-length.less
new file mode 100644
index 00000000..d81e118f
--- /dev/null
+++ b/test/less/extract-and-length.less
@@ -0,0 +1,133 @@
+
+// simple array/list:
+
+.multiunit {
+ @v: abc "abc" 1 1px 1% #123;
+ length: length(@v);
+ extract: extract(@v, 1) extract(@v, 2) extract(@v, 3) extract(@v, 4) extract(@v, 5) extract(@v, 6);
+}
+
+.incorrect-index {
+ @v1: a b c;
+ @v2: a, b, c;
+ v1: extract(@v1, 5);
+ v2: extract(@v2, -2);
+}
+
+.scalar {
+ @var: variable;
+ var-value: extract(@var, 1);
+ var-length: length(@var);
+ ill-index: extract(@var, 2);
+
+ name-value: extract(name, 1);
+ string-value: extract("string", 1);
+ number-value: extract(12345678, 1);
+ color-value: extract(blue, 1);
+ rgba-value: extract(rgba(80, 160, 240, 0.67), 1);
+ empty-value: extract(~'', 1);
+
+ name-length: length(name);
+ string-length: length("string");
+ number-length: length(12345678);
+ color-length: length(blue);
+ rgba-length: length(rgba(80, 160, 240, 0.67));
+ empty-length: length(~'');
+}
+
+.mixin-arguments {
+ .mixin-args(a b c d);
+ .mixin-args(a, b, c, d);
+ .mixin-args(1; 2; 3; 4);
+}
+
+.mixin-args(@value) {
+ &-1 {
+ length: length(@value);
+ extract: extract(@value, 3) ~"|" extract(@value, 2) ~"|" extract(@value, 1);
+ }
+}
+
+.mixin-args(...) {
+ &-2 {
+ length: length(@arguments);
+ extract: extract(@arguments, 3) ~"|" extract(@arguments, 2) ~"|" extract(@arguments, 1);
+ }
+}
+
+.mixin-args(@values...) {
+ &-3 {
+ length: length(@values);
+ extract: extract(@values, 3) ~"|" extract(@values, 2) ~"|" extract(@values, 1);
+ }
+}
+
+.mixin-args(@head, @tail...) {
+ &-4 {
+ length: length(@tail);
+ extract: extract(@tail, 2) ~"|" extract(@tail, 1);
+ }
+}
+
+// "multidimensional" array/list
+
+.md-space-comma {
+ @v: a b c, 1 2 3, "x" "y" "z";
+ length-1: length(@v);
+ extract-1: extract(@v, 2);
+ length-2: length(extract(@v, 2));
+ extract-2: extract(extract(@v, 2), 2);
+
+ &-as-args {.mixin-args(a b c, 1 2 3, "x" "y" "z")}
+}
+
+.md-cat-space-comma {
+ @a: a b c;
+ @b: 1 2 3;
+ @c: "x" "y" "z";
+ @v: @a, @b, @c;
+ length-1: length(@v);
+ extract-1: extract(@v, 2);
+ length-2: length(extract(@v, 2));
+ extract-2: extract(extract(@v, 2), 2);
+
+ &-as-args {.mixin-args(@a, @b, @c)}
+}
+
+.md-cat-comma-space {
+ @a: a, b, c;
+ @b: 1, 2, 3;
+ @c: "x", "y", "z";
+ @v: @a @b @c;
+ length-1: length(@v);
+ extract-1: extract(@v, 2);
+ length-2: length(extract(@v, 2));
+ extract-2: extract(extract(@v, 2), 2);
+
+ &-as-args {.mixin-args(@a @b @c)}
+}
+
+.md-3D {
+ @a: a b c d, 1 2 3 4;
+ @b: 5 6 7 8, e f g h;
+ .3D(@a, @b);
+
+ .3D(...) {
+
+ @v1: @arguments;
+ length-1: length(@v1);
+ extract-1: extract(@v1, 1);
+
+ @v2: extract(@v1, 2);
+ length-2: length(@v2);
+ extract-2: extract(@v2, 1);
+
+ @v3: extract(@v2, 1);
+ length-3: length(@v3);
+ extract-3: extract(@v3, 3);
+
+ @v4: extract(@v3, 4);
+ length-4: length(@v4);
+ extract-4: extract(@v4, 1);
+ }
+}
diff --git a/test/less/functions.less b/test/less/functions.less
new file mode 100644
index 00000000..4b4720d9
--- /dev/null
+++ b/test/less/functions.less
@@ -0,0 +1,173 @@
+#functions {
+ @var: 10;
+ @colors: #000, #fff;
+ color: _color("evil red"); // #660000
+ width: increment(15);
+ height: undefined("self");
+ border-width: add(2, 3);
+ variable: increment(@var);
+ background: linear-gradient(@colors);
+}
+
+#built-in {
+ @r: 32;
+ escaped: e("-Some::weird(#thing, y)");
+ lighten: lighten(#ff0000, 40%);
+ darken: darken(#ff0000, 40%);
+ saturate: saturate(#29332f, 20%);
+ desaturate: desaturate(#203c31, 20%);
+ greyscale: greyscale(#203c31);
+ hsl-clamp: hsl(380, 150%, 150%);
+ spin-p: spin(hsl(340, 50%, 50%), 40);
+ spin-n: spin(hsl(30, 50%, 50%), -40);
+ luma-white: luma(#fff);
+ luma-black: luma(#000);
+ luma-black-alpha: luma(rgba(0,0,0,0.5));
+ luma-red: luma(#ff0000);
+ luma-green: luma(#00ff00);
+ luma-blue: luma(#0000ff);
+ luma-yellow: luma(#ffff00);
+ luma-cyan: luma(#00ffff);
+ luma-differs-from-luminance: luma(#ff3600);
+ luminance-white: luma(#fff);
+ luminance-black: luma(#000);
+ luminance-black-alpha: luma(rgba(0,0,0,0.5));
+ luminance-red: luma(#ff0000);
+ luminance-differs-from-luma: luminance(#ff3600);
+ contrast-filter: contrast(30%);
+ saturate-filter: saturate(5%);
+ contrast-white: contrast(#fff);
+ contrast-black: contrast(#000);
+ contrast-red: contrast(#ff0000);
+ contrast-green: contrast(#00ff00);
+ contrast-blue: contrast(#0000ff);
+ contrast-yellow: contrast(#ffff00);
+ contrast-cyan: contrast(#00ffff);
+ contrast-light: contrast(#fff, #111111, #eeeeee);
+ contrast-dark: contrast(#000, #111111, #eeeeee);
+ contrast-wrongorder: contrast(#fff, #eeeeee, #111111, 0.5);
+ contrast-light-thresh: contrast(#fff, #111111, #eeeeee, 0.5);
+ contrast-dark-thresh: contrast(#000, #111111, #eeeeee, 0.5);
+ contrast-high-thresh: contrast(#555, #111111, #eeeeee, 0.6);
+ contrast-low-thresh: contrast(#555, #111111, #eeeeee, 0.09);
+ contrast-light-thresh-per: contrast(#fff, #111111, #eeeeee, 50%);
+ contrast-dark-thresh-per: contrast(#000, #111111, #eeeeee, 50%);
+ contrast-high-thresh-per: contrast(#555, #111111, #eeeeee, 60%);
+ contrast-low-thresh-per: contrast(#555, #111111, #eeeeee, 9%);
+ replace: replace("Hello, Mars.", "Mars\.", "World!");
+ replace-captured: replace("This is a string.", "(string)\.$", "new $1.");
+ replace-with-flags: replace("One + one = 4", "one", "2", "gi");
+ replace-single-quoted: replace('foo-1', "1", "2");
+ replace-escaped-string: replace(~"bar-1", "1", "2");
+ replace-keyword: replace(baz-1, "1", "2");
+ format: %("rgb(%d, %d, %d)", @r, 128, 64);
+ format-string: %("hello %s", "world");
+ format-multiple: %("hello %s %d", "earth", 2);
+ format-url-encode: %("red is %A", #ff0000);
+ format-single-quoted: %('hello %s', "single world");
+ format-escaped-string: %(~"hello %s", "escaped world");
+ eformat: e(%("rgb(%d, %d, %d)", @r, 128, 64));
+
+ unitless: unit(12px);
+ unit: unit((13px + 1px), em);
+ unitpercentage: unit(100, %);
+
+ get-unit: get-unit(10px);
+ get-unit-empty: get-unit(10);
+
+ hue: hue(hsl(98, 12%, 95%));
+ saturation: saturation(hsl(98, 12%, 95%));
+ lightness: lightness(hsl(98, 12%, 95%));
+ hsvhue: hsvhue(hsv(98, 12%, 95%));
+ hsvsaturation: hsvsaturation(hsv(98, 12%, 95%));
+ hsvvalue: hsvvalue(hsv(98, 12%, 95%));
+ red: red(#f00);
+ green: green(#0f0);
+ blue: blue(#00f);
+ rounded: round((@r/3));
+ rounded-two: round((@r/3), 2);
+ roundedpx: round((10px / 3));
+ roundedpx-three: round((10px / 3), 3);
+ rounded-percentage: round(10.2%);
+ ceil: ceil(10.1px);
+ floor: floor(12.9px);
+ sqrt: sqrt(25px);
+ pi: pi();
+ mod: mod(13m, 11cm); // could take into account units, doesn't at the moment
+ abs: abs(-4%);
+ tan: tan(42deg);
+ sin: sin(10deg);
+ cos: cos(12);
+ atan: atan(tan(0.1rad));
+ atan: convert(acos(cos(34deg)), deg);
+ atan: convert(acos(cos(50grad)), deg);
+ pow: pow(8px, 2);
+ pow: pow(4, 3);
+ pow: pow(3, 3em);
+ min: min(0);
+ min: min(6, 5);
+ min: min(1pt, 3pt);
+ min: min(1cm, 3mm);
+ max: max(1, 3);
+ max: max(3em, 1em, 2em, 5em);
+ percentage: percentage((10px / 50));
+ color: color("#ff0011");
+ tint: tint(#777777, 13);
+ tint-full: tint(#777777, 100);
+ tint-percent: tint(#777777, 13%);
+ tint-negative: tint(#777777, -13%);
+ shade: shade(#777777, 13);
+ shade-full: shade(#777777, 100);
+ shade-percent: shade(#777777, 13%);
+ shade-negative: shade(#777777, -13%);
+
+ fade-out: fadeOut(red, 5%); // support fadeOut and fadeout
+ fade-in: fadein(fadeout(red, 10%), 5%);
+
+ hsv: hsv(5, 50%, 30%);
+ hsva: hsva(3, 50%, 30%, 0.2);
+
+ mix: mix(#ff0000, #ffff00, 80);
+ mix-0: mix(#ff0000, #ffff00, 0);
+ mix-100: mix(#ff0000, #ffff00, 100);
+ mix-weightless: mix(#ff0000, #ffff00);
+ mixt: mix(#ff0000, transparent);
+
+ .is-a {
+ color: iscolor(#ddd);
+ color1: iscolor(red);
+ color2: iscolor(rgb(0, 0, 0));
+ color3: iscolor(transparent);
+ keyword: iskeyword(hello);
+ number: isnumber(32);
+ string: isstring("hello");
+ pixel: ispixel(32px);
+ percent: ispercentage(32%);
+ em: isem(32em);
+ cat: isunit(32cat, cat);
+ }
+}
+
+#alpha {
+ alpha: darken(hsla(25, 50%, 50%, 0.6), 10%);
+ alpha2: alpha(rgba(3, 4, 5, 0.5));
+ alpha3: alpha(transparent);
+}
+
+#blendmodes {
+ multiply: multiply(#f60000, #f60000);
+ screen: screen(#f60000, #0000f6);
+ overlay: overlay(#f60000, #0000f6);
+ softlight: softlight(#f60000, #ffffff);
+ hardlight: hardlight(#f60000, #0000f6);
+ difference: difference(#f60000, #0000f6);
+ exclusion: exclusion(#f60000, #0000f6);
+ average: average(#f60000, #0000f6);
+ negation: negation(#f60000, #313131);
+}
+
+#extract-and-length {
+ @anon: A B C 1 2 3;
+ extract: extract(@anon, 6) extract(@anon, 5) extract(@anon, 4) extract(@anon, 3) extract(@anon, 2) extract(@anon, 1);
+ length: length(@anon);
+}
diff --git a/test/less/globalVars/extended.json b/test/less/globalVars/extended.json
new file mode 100644
index 00000000..6bd2a484
--- /dev/null
+++ b/test/less/globalVars/extended.json
@@ -0,0 +1,5 @@
+{
+ "the-border": "1px",
+ "base-color": "#111",
+ "red": "#842210"
+}
\ No newline at end of file
diff --git a/test/less/globalVars/extended.less b/test/less/globalVars/extended.less
new file mode 100644
index 00000000..7a3bf291
--- /dev/null
+++ b/test/less/globalVars/extended.less
@@ -0,0 +1,10 @@
+#header {
+ color: (@base-color * 3);
+ border-left: @the-border;
+ border-right: (@the-border * 2);
+}
+#footer {
+ color: (@base-color + #003300);
+ border-color: @red;
+}
+@red: desaturate(red, 10%); // less file overrides passed in color <- note line comment on last line to check it is okay
\ No newline at end of file
diff --git a/test/less/globalVars/simple.json b/test/less/globalVars/simple.json
new file mode 100644
index 00000000..76a63c5a
--- /dev/null
+++ b/test/less/globalVars/simple.json
@@ -0,0 +1,3 @@
+{
+ "my-color": "red"
+}
\ No newline at end of file
diff --git a/test/less/globalVars/simple.less b/test/less/globalVars/simple.less
new file mode 100644
index 00000000..c3c5e3b8
--- /dev/null
+++ b/test/less/globalVars/simple.less
@@ -0,0 +1,3 @@
+.class {
+ color: @my-color;
+}
\ No newline at end of file
diff --git a/test/less/ie-filters.less b/test/less/ie-filters.less
new file mode 100644
index 00000000..3350b653
--- /dev/null
+++ b/test/less/ie-filters.less
@@ -0,0 +1,15 @@
+@fat: 0;
+@cloudhead: "#000000";
+
+.nav {
+ filter: progid:DXImageTransform.Microsoft.Alpha(opacity = 20);
+ filter: progid:DXImageTransform.Microsoft.Alpha(opacity=@fat);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#333333", endColorstr=@cloudhead, GradientType=@fat);
+}
+.evalTest(@arg) {
+ filter: progid:DXImageTransform.Microsoft.Alpha(opacity=@arg);
+}
+.evalTest1 {
+ .evalTest(30);
+ .evalTest(5);
+}
\ No newline at end of file
diff --git a/test/less/import-inline.less b/test/less/import-inline.less
new file mode 100644
index 00000000..95a11896
--- /dev/null
+++ b/test/less/import-inline.less
@@ -0,0 +1,2 @@
+@import (inline) url("import/import-test-d.css") (min-width:600px);
+@import (inline, css) url("import/invalid-css.less");
\ No newline at end of file
diff --git a/test/less/import-interpolation.less b/test/less/import-interpolation.less
new file mode 100644
index 00000000..21cfe086
--- /dev/null
+++ b/test/less/import-interpolation.less
@@ -0,0 +1,8 @@
+@my_theme: "test";
+
+@import "import/import-@{my_theme}-e.less";
+
+@import "import/import-@{in}@{terpolation}.less";
+
+@in: "in";
+@terpolation: "terpolation";
\ No newline at end of file
diff --git a/test/less/import-once.less b/test/less/import-once.less
new file mode 100644
index 00000000..0a4024a3
--- /dev/null
+++ b/test/less/import-once.less
@@ -0,0 +1,6 @@
+@import "import/import-once-test-c";
+@import "import/import-once-test-c";
+@import "import/import-once-test-c.less";
+@import "import/deeper/import-once-test-a";
+@import (multiple) "import/import-test-f.less";
+@import (multiple) "import/import-test-f.less";
\ No newline at end of file
diff --git a/test/less/import-reference.less b/test/less/import-reference.less
new file mode 100644
index 00000000..93160ab5
--- /dev/null
+++ b/test/less/import-reference.less
@@ -0,0 +1,21 @@
+@import (reference) url("import-once.less");
+@import (reference) url("css-3.less");
+@import (reference) url("media.less");
+@import (reference) url("import/import-reference.less");
+
+.b {
+ .z();
+}
+
+.zz();
+
+.visible:extend(.z all) {
+ extend: test;
+}
+
+.test-mediaq-import {
+ .mixin-with-mediaq(340px);
+}
+
+.class:extend(.class all) {
+}
\ No newline at end of file
diff --git a/test/less/import.less b/test/less/import.less
new file mode 100644
index 00000000..01689408
--- /dev/null
+++ b/test/less/import.less
@@ -0,0 +1,21 @@
+@import url(http://fonts.googleapis.com/css?family=Open+Sans);
+
+@import url(/absolute/something.css) screen and (color) and (max-width: 600px);
+
+@var: 100px;
+@import url("//ha.com/file.css") (min-width:@var);
+
+#import-test {
+ .mixin;
+ width: 10px;
+ height: (@a + 10%);
+}
+@import "import/import-test-e" screen and (max-width: 600px);
+
+@import url("import/import-test-a.less");
+
+@import (less, multiple) "import/import-test-d.css" screen and (max-width: 601px);
+
+@import (multiple) "import/import-test-e" screen and (max-width: 602px);
+
+@import (less, multiple) url("import/import-test-d.css") screen and (max-width: 603px);
\ No newline at end of file
diff --git a/test/less/import/deeper/import-once-test-a.less b/test/less/import/deeper/import-once-test-a.less
new file mode 100644
index 00000000..8a747fc0
--- /dev/null
+++ b/test/less/import/deeper/import-once-test-a.less
@@ -0,0 +1 @@
+@import "../import-once-test-c";
\ No newline at end of file
diff --git a/test/less/import/import-and-relative-paths-test.less b/test/less/import/import-and-relative-paths-test.less
new file mode 100644
index 00000000..d6256c6b
--- /dev/null
+++ b/test/less/import/import-and-relative-paths-test.less
@@ -0,0 +1,17 @@
+@import "../css/background.css";
+@import "import-test-d.css";
+
+@import "imports/logo";
+@import "imports/font";
+
+.unquoted-relative-path-bg() {
+ background-image: url(../../data/image.jpg);
+}
+.quoted-relative-path-border-image() {
+ border-image: url('../../data/image.jpg');
+}
+
+#imported-relative-path {
+ .unquoted-relative-path-bg;
+ .quoted-relative-path-border-image;
+}
\ No newline at end of file
diff --git a/test/less/import/import-charset-test.less b/test/less/import/import-charset-test.less
new file mode 100644
index 00000000..07a66e1a
--- /dev/null
+++ b/test/less/import/import-charset-test.less
@@ -0,0 +1 @@
+@charset "ISO-8859-1";
\ No newline at end of file
diff --git a/test/less/import/import-interpolation.less b/test/less/import/import-interpolation.less
new file mode 100644
index 00000000..aa49a702
--- /dev/null
+++ b/test/less/import/import-interpolation.less
@@ -0,0 +1 @@
+@import "import-@{in}@{terpolation}2.less";
\ No newline at end of file
diff --git a/test/less/import/import-interpolation2.less b/test/less/import/import-interpolation2.less
new file mode 100644
index 00000000..12bfb4e1
--- /dev/null
+++ b/test/less/import/import-interpolation2.less
@@ -0,0 +1,5 @@
+.a {
+ var: test;
+}
+
+@in: "redefined-does-nothing";
\ No newline at end of file
diff --git a/test/less/import/import-once-test-c.less b/test/less/import/import-once-test-c.less
new file mode 100644
index 00000000..686747a8
--- /dev/null
+++ b/test/less/import/import-once-test-c.less
@@ -0,0 +1,6 @@
+
+@c: red;
+
+#import {
+ color: @c;
+}
diff --git a/test/less/import/import-reference.less b/test/less/import/import-reference.less
new file mode 100644
index 00000000..c77f692e
--- /dev/null
+++ b/test/less/import/import-reference.less
@@ -0,0 +1,51 @@
+.z {
+ color: red;
+ .c {
+ color: green;
+ }
+}
+.only-with-visible,
+.z {
+ color: green;
+ &:hover {
+ color: green;
+ }
+ & {
+ color: green;
+ }
+ & + & {
+ color: green;
+ .sub {
+ color: green;
+ }
+ }
+}
+
+& {
+ .hidden {
+ hidden: true;
+ }
+}
+
+@media tv {
+ .hidden {
+ hidden: true;
+ }
+}
+
+/* comment is not output */
+
+.zz {
+ .y {
+ pulled-in: yes;
+ }
+ /* comment pulled in */
+}
+@max-size: 450px;
+.mixin-with-mediaq(@num) {
+ color: green;
+ test: @num;
+ @media (max-size: @max-size) {
+ color: red;
+ }
+}
\ No newline at end of file
diff --git a/test/less/import/import-test-a.less b/test/less/import/import-test-a.less
new file mode 100644
index 00000000..b3b3b8fc
--- /dev/null
+++ b/test/less/import/import-test-a.less
@@ -0,0 +1,3 @@
+@import "import-test-b.less";
+@a: 20%;
+@import "urls.less";
\ No newline at end of file
diff --git a/test/less/import/import-test-b.less b/test/less/import/import-test-b.less
new file mode 100644
index 00000000..ce2d35a8
--- /dev/null
+++ b/test/less/import/import-test-b.less
@@ -0,0 +1,8 @@
+@import "import-test-c";
+
+@b: 100%;
+
+.mixin {
+ height: 10px;
+ color: @c;
+}
diff --git a/test/less/import/import-test-c.less b/test/less/import/import-test-c.less
new file mode 100644
index 00000000..686747a8
--- /dev/null
+++ b/test/less/import/import-test-c.less
@@ -0,0 +1,6 @@
+
+@c: red;
+
+#import {
+ color: @c;
+}
diff --git a/test/less/import/import-test-d.css b/test/less/import/import-test-d.css
new file mode 100644
index 00000000..30575f01
--- /dev/null
+++ b/test/less/import/import-test-d.css
@@ -0,0 +1 @@
+#css { color: yellow; }
diff --git a/test/less/import/import-test-e.less b/test/less/import/import-test-e.less
new file mode 100644
index 00000000..98b84b0a
--- /dev/null
+++ b/test/less/import/import-test-e.less
@@ -0,0 +1,2 @@
+
+body { width: 100% }
diff --git a/test/less/import/import-test-f.less b/test/less/import/import-test-f.less
new file mode 100644
index 00000000..fad630f9
--- /dev/null
+++ b/test/less/import/import-test-f.less
@@ -0,0 +1,5 @@
+@import "import-test-e";
+
+.test-f {
+ height: 10px;
+}
diff --git a/test/less/import/imports/font.less b/test/less/import/imports/font.less
new file mode 100644
index 00000000..5abb7e76
--- /dev/null
+++ b/test/less/import/imports/font.less
@@ -0,0 +1,8 @@
+@font-face {
+ font-family: xecret;
+ src: url('../assets/xecret.ttf');
+}
+
+#secret {
+ font-family: xecret, sans-serif;
+}
diff --git a/test/less/import/imports/logo.less b/test/less/import/imports/logo.less
new file mode 100644
index 00000000..22893a23
--- /dev/null
+++ b/test/less/import/imports/logo.less
@@ -0,0 +1,5 @@
+#logo {
+ width: 100px;
+ height: 100px;
+ background: url('../assets/logo.png');
+}
diff --git a/test/less/import/invalid-css.less b/test/less/import/invalid-css.less
new file mode 100644
index 00000000..ed585d63
--- /dev/null
+++ b/test/less/import/invalid-css.less
@@ -0,0 +1 @@
+this isn't very valid CSS.
\ No newline at end of file
diff --git a/test/less/import/urls.less b/test/less/import/urls.less
new file mode 100644
index 00000000..bb48f77a
--- /dev/null
+++ b/test/less/import/urls.less
@@ -0,0 +1 @@
+// empty file showing that it loads from the relative path first
diff --git a/test/less/javascript.less b/test/less/javascript.less
new file mode 100644
index 00000000..a8e7eb37
--- /dev/null
+++ b/test/less/javascript.less
@@ -0,0 +1,38 @@
+.eval {
+ js: `42`;
+ js: `1 + 1`;
+ js: `"hello world"`;
+ js: `[1, 2, 3]`;
+ title: `typeof process.title`;
+ ternary: `(1 + 1 == 2 ? true : false)`;
+ multiline: `(function(){var x = 1 + 1;
+ return x})()`;
+}
+.scope {
+ @foo: 42;
+ var: `parseInt(this.foo.toJS())`;
+ escaped: ~`2 + 5 + 'px'`;
+}
+.vars {
+ @var: `4 + 4`;
+ width: @var;
+}
+.escape-interpol {
+ @world: "world";
+ width: ~`"hello" + " " + @{world}`;
+}
+.arrays {
+ @ary: 1, 2, 3;
+ @ary2: 1 2 3;
+ ary: `@{ary}.join(', ')`;
+ ary1: `@{ary2}.join(', ')`;
+}
+.transitions(...) {
+ @arg: ~`"@{arguments}".replace(/[\[\]]*/g, '')`;
+ 1: @arg; // rounded to integers
+ 2: ~`"@{arguments}"`; // rounded to integers
+ 3: @arguments; // OK
+}
+.test-tran {
+ .transitions(opacity 0.3s ease-in 0.3s, max-height 0.6s linear, margin-bottom 0.4s linear;);
+}
diff --git a/test/less/lazy-eval.less b/test/less/lazy-eval.less
new file mode 100644
index 00000000..72b3fd46
--- /dev/null
+++ b/test/less/lazy-eval.less
@@ -0,0 +1,6 @@
+@var: @a;
+@a: 100%;
+
+.lazy-eval {
+ width: @var;
+}
diff --git a/test/less/legacy/legacy.less b/test/less/legacy/legacy.less
new file mode 100644
index 00000000..92d00088
--- /dev/null
+++ b/test/less/legacy/legacy.less
@@ -0,0 +1,7 @@
+@media (-o-min-device-pixel-ratio: 2/1) {
+ .test-math-and-units {
+ font: ignores 0/0 rules;
+ test-division: 4 / 2 + 5em;
+ simple: 1px + 1px;
+ }
+}
\ No newline at end of file
diff --git a/test/less/media.less b/test/less/media.less
new file mode 100644
index 00000000..01a6a020
--- /dev/null
+++ b/test/less/media.less
@@ -0,0 +1,234 @@
+
+// For now, variables can't be declared inside @media blocks.
+
+@var: 42;
+
+@media print {
+ .class {
+ color: blue;
+ .sub {
+ width: @var;
+ }
+ }
+ .top, header > h1 {
+ color: (#222 * 2);
+ }
+}
+
+@media screen {
+ @base: 8;
+ body { max-width: (@base * 60); }
+}
+
+@ratio_large: 16;
+@ratio_small: 9;
+
+@media all and (device-aspect-ratio: @ratio_large / @ratio_small) {
+ body { max-width: 800px; }
+}
+
+@media all and (orientation:portrait) {
+ aside { float: none; }
+}
+
+@media handheld and (min-width: @var), screen and (min-width: 20em) {
+ body {
+ max-width: 480px;
+ }
+}
+
+body {
+ @media print {
+ padding: 20px;
+
+ header {
+ background-color: red;
+ }
+
+ @media (orientation:landscape) {
+ margin-left: 20px;
+ }
+ }
+}
+
+@media screen {
+ .sidebar {
+ width: 300px;
+ @media (orientation: landscape) {
+ width: 500px;
+ }
+ }
+}
+
+@media a {
+ .first {
+ @media b {
+ .second {
+ .third {
+ width: 300px;
+ @media c {
+ width: 500px;
+ }
+ }
+ .fourth {
+ width: 3;
+ }
+ }
+ }
+ }
+}
+
+body {
+ @media a, b and c {
+ width: 95%;
+
+ @media x, y {
+ width: 100%;
+ }
+ }
+}
+
+.mediaMixin(@fallback: 200px) {
+ background: black;
+
+ @media handheld {
+ background: white;
+
+ @media (max-width: @fallback) {
+ background: red;
+ }
+ }
+}
+
+.a {
+ .mediaMixin(100px);
+}
+
+.b {
+ .mediaMixin();
+}
+@smartphone: ~"only screen and (max-width: 200px)";
+@media @smartphone {
+ body {
+ width: 480px;
+ }
+}
+
+@media print {
+ @page :left {
+ margin: 0.5cm;
+ }
+ @page :right {
+ margin: 0.5cm;
+ }
+ @page Test:first {
+ margin: 1cm;
+ }
+ @page :first {
+ size: 8.5in 11in;
+ @top-left {
+ margin: 1cm;
+ }
+ @top-left-corner {
+ margin: 1cm;
+ }
+ @top-center {
+ margin: 1cm;
+ }
+ @top-right {
+ margin: 1cm;
+ }
+ @top-right-corner {
+ margin: 1cm;
+ }
+ @bottom-left {
+ margin: 1cm;
+ }
+ @bottom-left-corner {
+ margin: 1cm;
+ }
+ @bottom-center {
+ margin: 1cm;
+ }
+ @bottom-right {
+ margin: 1cm;
+ }
+ @bottom-right-corner {
+ margin: 1cm;
+ }
+ @left-top {
+ margin: 1cm;
+ }
+ @left-middle {
+ margin: 1cm;
+ }
+ @left-bottom {
+ margin: 1cm;
+ }
+ @right-top {
+ margin: 1cm;
+ }
+ @right-middle {
+ content: "Page " counter(page);
+ }
+ @right-bottom {
+ margin: 1cm;
+ }
+ }
+}
+
+@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 2/1), (min-resolution: 2dppx), (min-resolution: 128dpcm) {
+ .b {
+ background: red;
+ }
+}
+
+.bg() {
+ background: red;
+
+ @media (max-width: 500px) {
+ background: green;
+ }
+}
+
+body {
+ .bg();
+}
+
+@bpMedium: 1000px;
+@media (max-width: @bpMedium) {
+ body {
+ .bg();
+ background: blue;
+ }
+}
+
+@media (max-width: 1200px) {
+ /* a comment */
+
+ @media (max-width: 900px) {
+ body { font-size: 11px; }
+ }
+}
+
+.nav-justified {
+ @media (min-width: 480px) {
+ > li {
+ display: table-cell;
+ }
+ }
+}
+
+.menu
+{
+ @media (min-width: 768px) {
+ .nav-justified();
+ }
+}
+@all: ~"all";
+@tv: ~"tv";
+@media @all and @tv {
+ .all-and-tv-variables {
+ var: all-and-tv;
+ }
+}
\ No newline at end of file
diff --git a/test/less/merge.less b/test/less/merge.less
new file mode 100644
index 00000000..5b5def35
--- /dev/null
+++ b/test/less/merge.less
@@ -0,0 +1,78 @@
+.first-transform() {
+ transform+: rotate(90deg), skew(30deg);
+}
+.second-transform() {
+ transform+: scale(2,4);
+}
+.third-transform() {
+ transform: scaleX(45deg);
+}
+.fourth-transform() {
+ transform+: scaleX(45deg);
+}
+.fifth-transform() {
+ transform+: scale(2,4) !important;
+}
+.first-background() {
+ background+: url(data://img1.png);
+}
+.second-background() {
+ background+: url(data://img2.png);
+}
+
+.test1 {
+ // Can merge values
+ .first-transform();
+ .second-transform();
+}
+.test2 {
+ // Wont merge values without +: merge directive, for backwards compatibility with css
+ .first-transform();
+ .third-transform();
+}
+.test3 {
+ // Wont merge values from two sources with different properties
+ .fourth-transform();
+ .first-background();
+}
+.test4 {
+ // Wont merge values from sources that merked as !important, for backwards compatibility with css
+ .first-transform();
+ .fifth-transform();
+}
+.test5 {
+ // Wont merge values from mixins that merked as !important, for backwards compatibility with css
+ .first-transform();
+ .second-transform() !important;
+}
+.test6 {
+ // Ignores !merge if no peers found
+ .second-transform();
+}
+
+.test-interleaved {
+ transform+: t1;
+ background+: b1;
+ transform+: t2;
+ background+: b2, b3;
+ transform+: t3;
+}
+
+.test-spaced {
+ transform+_: t1;
+ background+_: b1;
+ transform+_: t2;
+ background+_: b2, b3;
+ transform+_: t3;
+}
+
+.test-interleaved-with-spaced {
+ transform+_: t1s;
+ transform+: t2;
+ background+: b1;
+ transform+_: t3s;
+ transform+: t4 t5s;
+ background+_: b2s, b3;
+ transform+_: t6s;
+ background+: b4;
+}
diff --git a/test/less/mixins-args.less b/test/less/mixins-args.less
new file mode 100644
index 00000000..8cdc67df
--- /dev/null
+++ b/test/less/mixins-args.less
@@ -0,0 +1,215 @@
+.mixin (@a: 1px, @b: 50%) {
+ width: (@a * 5);
+ height: (@b - 1%);
+}
+
+.mixina (@style, @width, @color: black) {
+ border: @width @style @color;
+}
+
+.mixiny
+(@a: 0, @b: 0) {
+ margin: @a;
+ padding: @b;
+}
+
+.hidden() {
+ color: transparent; // asd
+}
+
+#hidden {
+ .hidden;
+}
+
+#hidden1 {
+ .hidden();
+}
+
+.two-args {
+ color: blue;
+ .mixin(2px, 100%);
+ .mixina(dotted, 2px);
+}
+
+.one-arg {
+ .mixin(3px);
+}
+
+.no-parens {
+ .mixin;
+}
+
+.no-args {
+ .mixin();
+}
+
+.var-args {
+ @var: 9;
+ .mixin(@var, (@var * 2));
+}
+
+.multi-mix {
+ .mixin(2px, 30%);
+ .mixiny(4, 5);
+}
+
+.maxa(@arg1: 10, @arg2: #f00) {
+ padding: (@arg1 * 2px);
+ color: @arg2;
+}
+
+body {
+ .maxa(15);
+}
+
+@glob: 5;
+.global-mixin(@a:2) {
+ width: (@glob + @a);
+}
+
+.scope-mix {
+ .global-mixin(3);
+}
+
+.nested-ruleset (@width: 200px) {
+ width: @width;
+ .column { margin: @width; }
+}
+.content {
+ .nested-ruleset(600px);
+}
+
+//
+
+.same-var-name2(@radius) {
+ radius: @radius;
+}
+.same-var-name(@radius) {
+ .same-var-name2(@radius);
+}
+#same-var-name {
+ .same-var-name(5px);
+}
+
+//
+
+.var-inside () {
+ @var: 10px;
+ width: @var;
+}
+#var-inside { .var-inside; }
+
+.mixin-arguments (@width: 0px, ...) {
+ border: @arguments;
+ width: @width;
+}
+
+.arguments {
+ .mixin-arguments(1px, solid, black);
+}
+.arguments2 {
+ .mixin-arguments();
+}
+.arguments3 {
+ .mixin-arguments;
+}
+
+.mixin-arguments2 (@width, @rest...) {
+ border: @arguments;
+ rest: @rest;
+ width: @width;
+}
+.arguments4 {
+ .mixin-arguments2(0, 1, 2, 3, 4);
+}
+
+// Edge cases
+
+.edge-case {
+ .mixin-arguments("{");
+}
+
+// Division vs. Literal Slash
+.border-radius(@r: 2px/5px) {
+ border-radius: @r;
+}
+.slash-vs-math {
+ .border-radius();
+ .border-radius(5px/10px);
+ .border-radius((3px * 2));
+}
+// semi-colon vs comma for delimiting
+
+.mixin-takes-one(@a) {
+ one: @a;
+}
+
+.mixin-takes-two(@a; @b) {
+ one: @a;
+ two: @b;
+}
+
+.comma-vs-semi-colon {
+ .mixin-takes-two(@a : a; @b : b, c);
+ .mixin-takes-two(@a : d, e; @b : f);
+ .mixin-takes-one(@a: g);
+ .mixin-takes-one(@a : h;);
+ .mixin-takes-one(i);
+ .mixin-takes-one(j;);
+ .mixin-takes-two(k, l);
+ .mixin-takes-one(m, n;);
+ .mixin-takes-two(o, p; q);
+ .mixin-takes-two(r, s; t;);
+}
+
+.mixin-conflict(@a:defA, @b:defB, @c:defC) {
+ three: @a, @b, @c;
+}
+
+.mixin-conflict(@a:defA, @b:defB, @c:defC, @d:defD) {
+ four: @a, @b, @c, @d;
+}
+
+#named-conflict {
+ .mixin-conflict(11, 12, 13, @a:a);
+ .mixin-conflict(@a:a, 21, 22, 23);
+}
+@a: 3px;
+.mixin-default-arg(@a: 1px, @b: @a, @c: @b) {
+ defaults: 1px 1px 1px;
+ defaults: 2px 2px 2px;
+}
+
+.test-mixin-default-arg {
+ .mixin-default-arg();
+ .mixin-default-arg(2px);
+}
+
+.mixin-comma-default1(@color; @padding; @margin: 2, 2, 2, 2) {
+ margin: @margin;
+}
+.selector {
+ .mixin-comma-default1(#33acfe; 4);
+}
+.mixin-comma-default2(@margin: 2, 2, 2, 2;) {
+ margin: @margin;
+}
+.selector2 {
+ .mixin-comma-default2();
+}
+.mixin-comma-default3(@margin: 2, 2, 2, 2) {
+ margin: @margin;
+}
+.selector3 {
+ .mixin-comma-default3(4,2,2,2);
+}
+
+.test-calling-one-arg-mixin(@a) {
+}
+
+.test-calling-one-arg-mixin(@a, @b, @rest...) {
+}
+
+div {
+ .test-calling-one-arg-mixin(1);
+}
\ No newline at end of file
diff --git a/test/less/mixins-closure.less b/test/less/mixins-closure.less
new file mode 100644
index 00000000..01251d2a
--- /dev/null
+++ b/test/less/mixins-closure.less
@@ -0,0 +1,26 @@
+.scope {
+ @var: 99px;
+ .mixin () {
+ width: @var;
+ }
+}
+
+.class {
+ .scope > .mixin;
+}
+
+.overwrite {
+ @var: 0px;
+ .scope > .mixin;
+}
+
+.nested {
+ @var: 5px;
+ .mixin () {
+ width: @var;
+ }
+ .class {
+ @var: 10px;
+ .mixin;
+ }
+}
diff --git a/test/less/mixins-guards-default-func.less b/test/less/mixins-guards-default-func.less
new file mode 100644
index 00000000..eada9381
--- /dev/null
+++ b/test/less/mixins-guards-default-func.less
@@ -0,0 +1,195 @@
+
+// basics:
+
+guard-default-basic-1 {
+ .m(1) {case: 1}
+ .m(@x) when (default()) {default: @x}
+
+ &-1 {.m(1)}
+ &-2 {.m(2)}
+}
+
+guard-default-basic-2 {
+ .m(1) {case: 1}
+ .m(2) {case: 2}
+ .m(3) {case: 3}
+ .m(@x) when (default()) {default: @x}
+
+ &-0 {.m(0)}
+ &-2 {.m(2)}
+}
+
+guard-default-basic-3 {
+ .m(@x) when (@x = 1) {case: 1}
+ .m(2) {case: 2}
+ .m(@x) when (@x = 3) {case: 3}
+ .m(@x) when (default()) {default: @x}
+
+ &-0 {.m(0)}
+ &-2 {.m(2)}
+ &-3 {.m(3)}
+}
+
+guard-default-definition-order {
+ .m(@x) when (default()) {default: @x}
+ .m(@x) when (@x = 1) {case: 1}
+ .m(2) {case: 2}
+ .m(@x) when (@x = 3) {case: 3}
+
+ &-0 {.m(0)}
+ &-2 {.m(2)}
+ &-2 {.m(3)}
+}
+
+// out of guard:
+
+guard-default-out-of-guard {
+ .m(1) {case-1: 1}
+ .m(@x: default()) when (default()) {default: @x}
+
+ &-0 {
+ case-0: default();
+ .m(1);
+ .m(2);
+ case-2: default();
+ }
+ &-1 {.m(default())}
+ &-2 {.m()}
+}
+
+// expressions:
+
+guard-default-expr-not {
+ .m(1) {case: 1}
+ .m(@x) when not(default()) {default: @x}
+
+ &-1 {.m(1)}
+ &-2 {.m(2)}
+}
+
+guard-default-expr-eq {
+ .m(@x) when (@x = true) {case: @x}
+ .m(@x) when (@x = false) {case: @x}
+ .m(@x) when (@x = default()) {default: @x}
+
+ &-true {.m(true)}
+ &-false {.m(false)}
+}
+
+guard-default-expr-or {
+ .m(1) {case: 1}
+ .m(2) {case: 2}
+ .m(@x) when (default()), (@x = 2) {default: @x}
+
+ &-1 {.m(1)}
+ &-2 {.m(2)}
+ &-3 {.m(3)}
+}
+
+guard-default-expr-and {
+ .m(1) {case: 1}
+ .m(2) {case: 2}
+ .m(@x) when (default()) and (@x = 3) {default: @x}
+
+ &-1 {.m(1)}
+ &-2 {.m(2)}
+ &-3 {.m(3)}
+ &-4 {.m(4)}
+}
+
+guard-default-expr-always {
+ .m(1) {case: 1}
+ .m(@x) when (default()), not(default()) {default: @x} // always match
+
+ &-1 {.m(1)}
+ &-2 {.m(2)}
+}
+
+guard-default-expr-never {
+ .m(1) {case: 1}
+ .m(@x) when (default()) and not(default()) {default: @x} // never match
+
+ &-1 {.m(1)}
+ &-2 {.m(2)}
+}
+
+
+// not conflicting multiple default() uses:
+
+guard-default-multi-1 {
+ .m(0) {case: 0}
+ .m(@x) when (default()) {default-1: @x}
+ .m(2) when (default()) {default-2: @x}
+
+ &-0 {.m(0)}
+ &-1 {.m(1)}
+}
+
+guard-default-multi-2 {
+ .m(1, @x) when (default()) {default-1: @x}
+ .m(2, @x) when (default()) {default-2: @x}
+ .m(@x, yes) when (default()) {default-3: @x}
+
+ &-1 {.m(1, no)}
+ &-2 {.m(2, no)}
+ &-3 {.m(3, yes)}
+}
+
+guard-default-multi-3 {
+ .m(red) {case-1: darkred}
+ .m(blue) {case-2: darkblue}
+ .m(@x) when (iscolor(@x)) and (default()) {default-color: @x}
+ .m('foo') {case-1: I am 'foo'}
+ .m('bar') {case-2: I am 'bar'}
+ .m(@x) when (isstring(@x)) and (default()) {default-string: I am @x}
+
+ &-blue {.m(blue)}
+ &-green {.m(green)}
+ &-foo {.m('foo')}
+ &-baz {.m('baz')}
+}
+
+guard-default-multi-4 {
+ .m(@x) when (default()), not(default()) {always: @x}
+ .m(@x) when (default()) and not(default()) {never: @x}
+ .m(2) {case: 2}
+
+ .m(1);
+ .m(2);
+}
+
+guard-default-not-ambiguos-2 {
+ .m(@x) {case: 1}
+ .m(@x) when (default()) {default: @x}
+ .m(@x) when not(default()) {not-default: @x}
+
+ .m(2);
+}
+
+guard-default-not-ambiguos-3 {
+ .m(@x) {case: 1}
+ .m(@x) when not(default()) {not-default-1: @x}
+ .m(@x) when not(default()) {not-default-2: @x}
+
+ .m(2);
+}
+
+// default & scope
+
+guard-default-scopes {
+ .s1() {.m(@v) {1: no condition}}
+ .s2() {.m(@v) when (@v) {2: when true}}
+ .s3() {.m(@v) when (default()) {3: when default}}
+
+ &-3 {
+ .s2();
+ .s3();
+ .m(false);
+ }
+
+ &-1 {
+ .s1();
+ .s3();
+ .m(false);
+ }
+}
diff --git a/test/less/mixins-guards.less b/test/less/mixins-guards.less
new file mode 100644
index 00000000..5aec2e51
--- /dev/null
+++ b/test/less/mixins-guards.less
@@ -0,0 +1,173 @@
+
+// Stacking, functions..
+
+.light (@a) when (lightness(@a) > 50%) {
+ color: white;
+}
+.light (@a) when (lightness(@a) < 50%) {
+ color: black;
+}
+.light (@a) {
+ margin: 1px;
+}
+
+.light1 { .light(#ddd) }
+.light2 { .light(#444) }
+
+// Arguments against each other
+
+.max (@a, @b) when (@a > @b) {
+ width: @a;
+}
+.max (@a, @b) when (@a < @b) {
+ width: @b;
+}
+
+.max1 { .max(3, 6) }
+.max2 { .max(8, 1) }
+
+// Globals inside guards
+
+@g: auto;
+
+.glob (@a) when (@a = @g) {
+ margin: @a @g;
+}
+.glob1 { .glob(auto) }
+
+// Other operators
+
+.ops (@a) when (@a >= 0) {
+ height: gt-or-eq;
+}
+.ops (@a) when (@a =< 0) {
+ height: lt-or-eq;
+}
+.ops (@a) when (@a <= 0) {
+ height: lt-or-eq-alias;
+}
+.ops (@a) when not(@a = 0) {
+ height: not-eq;
+}
+.ops1 { .ops(0) }
+.ops2 { .ops(1) }
+.ops3 { .ops(-1) }
+
+// Scope and default values
+
+@a: auto;
+
+.default (@a: inherit) when (@a = inherit) {
+ content: default;
+}
+.default1 { .default }
+
+// true & false keywords
+.test (@a) when (@a) {
+ content: "true.";
+}
+.test (@a) when not (@a) {
+ content: "false.";
+}
+
+.test1 { .test(true) }
+.test2 { .test(false) }
+.test3 { .test(1) }
+.test4 { .test(boo) }
+.test5 { .test("true") }
+
+// Boolean expressions
+
+.bool () when (true) and (false) { content: true and false } // FALSE
+.bool () when (true) and (true) { content: true and true } // TRUE
+.bool () when (true) { content: true } // TRUE
+.bool () when (false) and (false) { content: true } // FALSE
+.bool () when (false), (true) { content: false, true } // TRUE
+.bool () when (false) and (true) and (true), (true) { content: false and true and true, true } // TRUE
+.bool () when (true) and (true) and (false), (false) { content: true and true and false, false } // FALSE
+.bool () when (false), (true) and (true) { content: false, true and true } // TRUE
+.bool () when (false), (false), (true) { content: false, false, true } // TRUE
+.bool () when (false), (false) and (true), (false) { content: false, false and true, false } // FALSE
+.bool () when (false), (true) and (true) and (true), (false) { content: false, true and true and true, false } // TRUE
+.bool () when not (false) { content: not false }
+.bool () when not (true) and not (false) { content: not true and not false }
+.bool () when not (true) and not (true) { content: not true and not true }
+.bool () when not (false) and (false), not (false) { content: not false and false, not false }
+
+.bool1 { .bool }
+
+.equality-unit-test(@num) when (@num = 1%) {
+ test: fail;
+}
+.equality-unit-test(@num) when (@num = 2) {
+ test: pass;
+}
+.equality-units {
+ .equality-unit-test(1px);
+ .equality-unit-test(2px);
+}
+
+.colorguard(@col) when (@col = red) { content: is @col; }
+.colorguard(@col) when not (blue = @col) { content: is not blue its @col; }
+.colorguard(@col) {}
+.colorguardtest {
+ .colorguard(red);
+ .colorguard(blue);
+ .colorguard(purple);
+}
+
+.stringguard(@str) when (@str = "theme1") { content: @str is "theme1"; }
+.stringguard(@str) when not ("theme2" = @str) { content: @str is not "theme2"; }
+.stringguard(@str) when (@str = 'theme1') { content: @str is 'theme1'; }
+.stringguard(@str) when not ('theme2' = @str) { content: @str is not 'theme2'; }
+.stringguard(@str) when (~"theme1" = @str) { content: @str is theme1; }
+.stringguard(@str) {}
+.stringguardtest {
+ .stringguard("theme1");
+ .stringguard("theme2");
+ .stringguard('theme1');
+ .stringguard('theme2');
+ .stringguard(theme1);
+}
+
+.mixin(...) {
+ catch:all;
+}
+.mixin(@var) when (@var=4) {
+ declare: 4;
+}
+.mixin(@var) when (@var=4px) {
+ declare: 4px;
+}
+#tryNumberPx {
+ .mixin(4px);
+}
+
+.lock-mixin(@a) {
+ .inner-locked-mixin(@x: @a) when (@a = 1) {
+ a: @a;
+ x: @x;
+ }
+}
+.call-lock-mixin {
+ .lock-mixin(1);
+ .call-inner-lock-mixin {
+ .inner-locked-mixin();
+ }
+}
+.bug-100cm-1m(@a) when (@a = 1) {
+ .failed {
+ one-hundred: not-equal-to-1;
+ }
+}
+.bug-100cm-1m(100cm);
+
+#ns {
+ .mixin-for-root-usage(@a) when (@a > 0) {
+ .mixin-generated-class {
+ a: @a;
+ }
+ }
+}
+
+#ns > .mixin-for-root-usage(1);
diff --git a/test/less/mixins-important.less b/test/less/mixins-important.less
new file mode 100644
index 00000000..c8cc1d5c
--- /dev/null
+++ b/test/less/mixins-important.less
@@ -0,0 +1,25 @@
+.submixin(@a) {
+ border-width: @a;
+}
+.mixin (9) {
+ border: 9 !important;
+}
+.mixin (@a: 0) {
+ border: @a;
+ boxer: @a;
+ .inner {
+ test: @a;
+ }
+ // comment
+ .submixin(@a);
+}
+
+.class {
+ .mixin(1);
+ .mixin(2) !important;
+ .mixin(3);
+ .mixin(4) !important;
+ .mixin(5);
+ .mixin !important;
+ .mixin(9);
+}
diff --git a/test/less/mixins-interpolated.less b/test/less/mixins-interpolated.less
new file mode 100644
index 00000000..2e75e980
--- /dev/null
+++ b/test/less/mixins-interpolated.less
@@ -0,0 +1,69 @@
+
+@a1: foo;
+@a2: ~".foo";
+@a4: ~"#foo";
+
+.@{a1} {
+ a: 1;
+}
+
+@{a2} {
+ a: 2;
+}
+
+#@{a1} {
+ a: 3;
+}
+
+@{a4} {
+ a: 4;
+}
+
+mi-test-a {
+ .foo;
+ #foo;
+}
+
+.b .bb {
+ &.@{a1}-xxx .yyy-@{a1}@{a4} {
+ & @{a2}.bbb {
+ b: 1;
+ }
+ }
+}
+
+mi-test-b {
+ .b.bb.foo-xxx.yyy-foo#foo.foo.bbb;
+}
+
+@c1: @a1;
+@c2: bar;
+@c3: baz;
+
+#@{c1}-foo {
+ > .@{c2} {
+ .@{c3} {
+ c: c;
+ }
+ }
+}
+
+mi-test-c {
+ &-1 {#foo-foo;}
+ &-2 {#foo-foo > .bar;}
+ &-3 {#foo-foo > .bar.baz;}
+}
+
+.Person(@name, @gender_) {
+ .@{name} {
+ @gender: @gender_;
+ .sayGender() {
+ gender: @gender;
+ }
+ }
+}
+
+mi-test-d {
+ .Person(person, "Male");
+ .person.sayGender();
+}
diff --git a/test/less/mixins-named-args.less b/test/less/mixins-named-args.less
new file mode 100644
index 00000000..d79e0f47
--- /dev/null
+++ b/test/less/mixins-named-args.less
@@ -0,0 +1,36 @@
+.mixin (@a: 1px, @b: 50%) {
+ width: (@a * 5);
+ height: (@b - 1%);
+ args: @arguments;
+}
+.mixin (@a: 1px, @b: 50%) when (@b > 75%){
+ text-align: center;
+}
+
+.named-arg {
+ color: blue;
+ .mixin(@b: 100%);
+}
+
+.class {
+ @var: 20%;
+ .mixin(@b: @var);
+}
+
+.all-args-wrong-args {
+ .mixin(@b: 10%, @a: 2px);
+}
+
+.mixin2 (@a: 1px, @b: 50%, @c: 50) {
+ width: (@a * 5);
+ height: (@b - 1%);
+ color: (#000000 + @c);
+}
+
+.named-args2 {
+ .mixin2(3px, @c: 100);
+}
+
+.named-args3 {
+ .mixin2(@b: 30%, @c: #123456);
+}
\ No newline at end of file
diff --git a/test/less/mixins-nested.less b/test/less/mixins-nested.less
new file mode 100644
index 00000000..43443de2
--- /dev/null
+++ b/test/less/mixins-nested.less
@@ -0,0 +1,22 @@
+.mix-inner (@var) {
+ border-width: @var;
+}
+
+.mix (@a: 10) {
+ .inner {
+ height: (@a * 10);
+
+ .innest {
+ width: @a;
+ .mix-inner((@a * 2));
+ }
+ }
+}
+
+.class {
+ .mix(30);
+}
+
+.class2 {
+ .mix(60);
+}
diff --git a/test/less/mixins-pattern.less b/test/less/mixins-pattern.less
new file mode 100644
index 00000000..e769b0cf
--- /dev/null
+++ b/test/less/mixins-pattern.less
@@ -0,0 +1,102 @@
+.mixin (...) {
+ variadic: true;
+}
+.mixin (@a...) {
+ named-variadic: true;
+}
+.mixin () {
+ zero: 0;
+}
+.mixin (@a: 1px) {
+ one: 1;
+}
+.mixin (@a) {
+ one-req: 1;
+}
+.mixin (@a: 1px, @b: 2px) {
+ two: 2;
+}
+
+.mixin (@a, @b, @c) {
+ three-req: 3;
+}
+
+.mixin (@a: 1px, @b: 2px, @c: 3px) {
+ three: 3;
+}
+
+.zero {
+ .mixin();
+}
+
+.one {
+ .mixin(1);
+}
+
+.two {
+ .mixin(1, 2);
+}
+
+.three {
+ .mixin(1, 2, 3);
+}
+
+//
+
+.mixout ('left') {
+ left: 1;
+}
+
+.mixout ('right') {
+ right: 1;
+}
+
+.left {
+ .mixout('left');
+}
+.right {
+ .mixout('right');
+}
+
+//
+
+.border (@side, @width) {
+ color: black;
+ .border-side(@side, @width);
+}
+.border-side (left, @w) {
+ border-left: @w;
+}
+.border-side (right, @w) {
+ border-right: @w;
+}
+
+.border-right {
+ .border(right, 4px);
+}
+.border-left {
+ .border(left, 4px);
+}
+
+//
+
+
+.border-radius (@r) {
+ both: (@r * 10);
+}
+.border-radius (@r, left) {
+ left: @r;
+}
+.border-radius (@r, right) {
+ right: @r;
+}
+
+.only-right {
+ .border-radius(33, right);
+}
+.only-left {
+ .border-radius(33, left);
+}
+.left-right {
+ .border-radius(33);
+}
diff --git a/test/less/mixins.less b/test/less/mixins.less
new file mode 100644
index 00000000..b98836c5
--- /dev/null
+++ b/test/less/mixins.less
@@ -0,0 +1,144 @@
+.mixin { border: 1px solid black; }
+.mixout { border-color: orange; }
+.borders { border-style: dashed; }
+
+#namespace {
+ .borders {
+ border-style: dotted;
+ }
+ .biohazard {
+ content: "death";
+ .man {
+ color: transparent;
+ }
+ }
+}
+#theme {
+ > .mixin {
+ background-color: grey;
+ }
+}
+#container {
+ color: black;
+ .mixin;
+ .mixout;
+ #theme > .mixin;
+}
+
+#header {
+ .milk {
+ color: white;
+ .mixin;
+ #theme > .mixin;
+ }
+ #cookie {
+ .chips {
+ #namespace .borders;
+ .calories {
+ #container;
+ }
+ }
+ .borders;
+ }
+}
+.secure-zone { #namespace .biohazard .man; }
+.direct {
+ #namespace > .borders;
+}
+
+.bo, .bar {
+ width: 100%;
+}
+.bo {
+ border: 1px;
+}
+.ar.bo.ca {
+ color: black;
+}
+.jo.ki {
+ background: none;
+}
+.amp {
+ &.support {
+ color: orange;
+ .higher {
+ top: 0px;
+ }
+ &.deeper {
+ height: auto;
+ }
+ }
+}
+.extended {
+ .bo;
+ .jo.ki;
+ .amp.support;
+ .amp.support.higher;
+ .amp.support.deeper;
+}
+.do .re .mi .fa {
+ .sol .la {
+ .si {
+ color: cyan;
+ }
+ }
+}
+.mutli-selector-parents {
+ .do.re.mi.fa.sol.la.si;
+}
+.foo .bar {
+ .bar;
+}
+.has_parents() {
+ & .underParents {
+ color: red;
+ }
+}
+.has_parents();
+.parent {
+ .has_parents();
+}
+.margin_between(@above, @below) {
+ * + & { margin-top: @above; }
+ legend + & { margin-top: 0; }
+ & + * { margin-top: @below; }
+}
+h1 { .margin_between(25px, 10px); }
+h2 { .margin_between(20px, 8px); }
+h3 { .margin_between(15px, 5px); }
+
+.mixin_def(@url, @position){
+ background-image: @url;
+ background-position: @position;
+}
+.error{
+ @s: "/";
+ .mixin_def( "@{s}a.png", center center);
+}
+.recursion() {
+ color: black;
+}
+.test-rec {
+ .recursion {
+ .recursion();
+ }
+}
+.paddingFloat(@padding) { padding-left: @padding; }
+
+.button {
+ .paddingFloat(((10px + 12) * 2));
+
+ &.large { .paddingFloat(((10em * 2) * 2)); }
+}
+.clearfix() {
+ // ...
+}
+.clearfix {
+ .clearfix();
+}
+.clearfix {
+ .clearfix();
+}
+.foo {
+ .clearfix();
+}
\ No newline at end of file
diff --git a/test/less/modifyVars/extended.json b/test/less/modifyVars/extended.json
new file mode 100644
index 00000000..6bd2a484
--- /dev/null
+++ b/test/less/modifyVars/extended.json
@@ -0,0 +1,5 @@
+{
+ "the-border": "1px",
+ "base-color": "#111",
+ "red": "#842210"
+}
\ No newline at end of file
diff --git a/test/less/modifyVars/extended.less b/test/less/modifyVars/extended.less
new file mode 100644
index 00000000..0badc671
--- /dev/null
+++ b/test/less/modifyVars/extended.less
@@ -0,0 +1,11 @@
+#header {
+ color: (@base-color * 3);
+ border-left: @the-border;
+ border-right: (@the-border * 2);
+}
+#footer {
+ color: (@base-color + #003300);
+ border-color: @red;
+}
+@red: blue; // var is overridden by the modifyVars
+//@base-color: green;
\ No newline at end of file
diff --git a/test/less/no-js-errors/no-js-errors.less b/test/less/no-js-errors/no-js-errors.less
new file mode 100644
index 00000000..15ef8a45
--- /dev/null
+++ b/test/less/no-js-errors/no-js-errors.less
@@ -0,0 +1,3 @@
+.a {
+ a: `1 + 1`;
+}
\ No newline at end of file
diff --git a/test/less/no-js-errors/no-js-errors.txt b/test/less/no-js-errors/no-js-errors.txt
new file mode 100644
index 00000000..d81dd2bd
--- /dev/null
+++ b/test/less/no-js-errors/no-js-errors.txt
@@ -0,0 +1,4 @@
+SyntaxError: You are using JavaScript, which has been disabled. in {path}no-js-errors.less on line 2, column 6:
+1 .a {
+2 a: `1 + 1`;
+3 }
diff --git a/test/less/no-output.less b/test/less/no-output.less
new file mode 100644
index 00000000..b4e6a499
--- /dev/null
+++ b/test/less/no-output.less
@@ -0,0 +1,2 @@
+.mixin() {
+}
\ No newline at end of file
diff --git a/test/less/operations.less b/test/less/operations.less
new file mode 100644
index 00000000..3e483c8b
--- /dev/null
+++ b/test/less/operations.less
@@ -0,0 +1,62 @@
+#operations {
+ color: (#110000 + #000011 + #001100); // #111111
+ height: (10px / 2px + 6px - 1px * 2); // 9px
+ width: (2 * 4 - 5em); // 3em
+ .spacing {
+ height: (10px / 2px+6px-1px*2);
+ width: (2 * 4-5em);
+ }
+ substraction: (20 - 10 - 5 - 5); // 0
+ division: (20 / 5 / 4); // 1
+}
+
+@x: 4;
+@y: 12em;
+
+.with-variables {
+ height: (@x + @y); // 16em
+ width: (12 + @y); // 24em
+ size: (5cm - @x); // 1cm
+}
+
+.with-functions {
+ color: (rgb(200, 200, 200) / 2);
+ color: (2 * hsl(0, 50%, 50%));
+ color: (rgb(10, 10, 10) + hsl(0, 50%, 50%));
+}
+
+@z: -2;
+
+.negative {
+ height: (2px + @z); // 0px
+ width: (2px - @z); // 4px
+}
+
+.shorthands {
+ padding: -1px 2px 0 -4px; //
+}
+
+.rem-dimensions {
+ font-size: (20rem / 5 + 1.5rem); // 5.5rem
+}
+
+.colors {
+ color: #123; // #112233
+ border-color: (#234 + #111111); // #334455
+ background-color: (#222222 - #fff); // #000000
+ .other {
+ color: (2 * #111); // #222222
+ border-color: (#333333 / 3 + #111); // #222222
+ }
+}
+
+.negations {
+ @var: 4px;
+ variable: (-@var); // 4
+ variable1: (-@var + @var); // 0
+ variable2: (@var + -@var); // 0
+ variable3: (@var - -@var); // 8
+ variable4: (-@var - -@var); // 0
+ paren: (-(@var)); // -4px
+ paren2: (-(2 + 2) * -@var); // 16
+}
diff --git a/test/less/parens.less b/test/less/parens.less
new file mode 100644
index 00000000..eeef3448
--- /dev/null
+++ b/test/less/parens.less
@@ -0,0 +1,45 @@
+.parens {
+ @var: 1px;
+ border: (@var * 2) solid black;
+ margin: (@var * 1) (@var + 2) (4 * 4) 3;
+ width: (6 * 6);
+ padding: 2px (6 * 6px);
+}
+
+.more-parens {
+ @var: (2 * 2);
+ padding: (2 * @var) 4 4 (@var * 1px);
+ width-all: ((@var * @var) * 6);
+ width-first: ((@var * @var)) * 6;
+ width-keep: (@var * @var) * 6;
+ height-keep: (7 * 7) + (8 * 8);
+ height-all: ((7 * 7) + (8 * 8));
+ height-parts: ((7 * 7)) + ((8 * 8));
+ margin-keep: (4 * (5 + 5) / 2) - (@var * 2);
+ margin-parts: ((4 * (5 + 5) / 2)) - ((@var * 2));
+ margin-all: ((4 * (5 + 5) / 2) + (-(@var * 2)));
+ border-radius-keep: 4px * (1 + 1) / @var + 3px;
+ border-radius-parts: ((4px * (1 + 1))) / ((@var + 3px));
+ border-radius-all: (4px * (1 + 1) / @var + 3px);
+ //margin: (6 * 6)px;
+}
+
+.negative {
+ @var: 1;
+ neg-var: -@var; // -1 ?
+ neg-var-paren: -(@var); // -(1) ?
+}
+
+.nested-parens {
+ width: 2 * (4 * (2 + (1 + 6))) - 1;
+ height: ((2 + 3) * (2 + 3) / (9 - 4)) + 1;
+}
+
+.mixed-units {
+ margin: 2px 4em 1 5pc;
+ padding: (2px + 4px) 1em 2px 2;
+}
+
+.test-false-negatives {
+ a: ~"(";
+}
diff --git a/test/less/property-name-interp.less b/test/less/property-name-interp.less
new file mode 100644
index 00000000..9886e65f
--- /dev/null
+++ b/test/less/property-name-interp.less
@@ -0,0 +1,53 @@
+
+pi-test {
+ @prefix: ufo-;
+ @a: border;
+ @bb: top;
+ @c_c: left;
+ @d-d4: radius;
+ @-: -;
+
+ @{a}: 0;
+ @{prefix}width: 50%;
+ *-z-@{a} :1px dashed blue;
+ -www-@{a}-@{bb}: 2px;
+ @{d-d4}-is-not-a-@{a}:true;
+ @{a}-@{bb}-@{c_c}-@{d-d4} : 2em;
+ @{a}@{-}@{bb}@{-}red@{-}@{d-d4}-: 3pt;
+
+ .mixin(mixer);
+ .merge(ish, base);
+}
+
+@global: global;
+
+.mixin(@arg) {
+ @local: local;
+ @{global}-@{local}-@{arg}-property: strong;
+}
+
+.merge(@p, @v) {
+ &-merge {
+ @prefix: pre;
+ @suffix: ish;
+ @{prefix}-property-ish+ :high;
+ pre-property-@{suffix} +: middle;
+ @{prefix}-property-@{suffix}+: low;
+ @{prefix}-property-@{p} + : @v;
+
+ @subterfuge: ~'+';
+ pre-property-ish@{subterfuge}: nice try dude;
+ }
+}
+
+pi-indirect-vars {
+ @{p}: @p;
+ @p: @@a;
+ @a: b;
+ @b: auto;
+}
+
+pi-complex-values {
+ @{p}@{p}: none;
+ @p: (1 + 2px) fadeout(#ff0, 50%), pi() /* foo */;
+}
diff --git a/test/less/rulesets.less b/test/less/rulesets.less
new file mode 100644
index 00000000..e81192db
--- /dev/null
+++ b/test/less/rulesets.less
@@ -0,0 +1,30 @@
+#first > .one {
+ > #second .two > #deux {
+ width: 50%;
+ #third {
+ &:focus {
+ color: black;
+ #fifth {
+ > #sixth {
+ .seventh #eighth {
+ + #ninth {
+ color: purple;
+ }
+ }
+ }
+ }
+ }
+ height: 100%;
+ }
+ #fourth, #five, #six {
+ color: #110000;
+ .seven, .eight > #nine {
+ border: 1px solid black;
+ }
+ #ten {
+ color: red;
+ }
+ }
+ }
+ font-size: 2em;
+}
diff --git a/test/less/scope.less b/test/less/scope.less
new file mode 100644
index 00000000..475b1f6d
--- /dev/null
+++ b/test/less/scope.less
@@ -0,0 +1,104 @@
+@x: red;
+@x: blue;
+@z: transparent;
+@mix: none;
+
+.mixin {
+ @mix: #989;
+}
+@mix: blue;
+.tiny-scope {
+ color: @mix; // #989
+ .mixin;
+}
+
+.scope1 {
+ @y: orange;
+ @z: black;
+ color: @x; // blue
+ border-color: @z; // black
+ .hidden {
+ @x: #131313;
+ }
+ .scope2 {
+ @y: red;
+ color: @x; // blue
+ .scope3 {
+ @local: white;
+ color: @y; // red
+ border-color: @z; // black
+ background-color: @local; // white
+ }
+ }
+}
+
+#namespace {
+ .scoped_mixin() {
+ @local-will-be-made-global: green;
+ .scope {
+ scoped-val: @local-will-be-made-global;
+ }
+ }
+}
+
+#namespace > .scoped_mixin();
+
+.setHeight(@h) { @height: 1024px; }
+.useHeightInMixinCall(@h) { .useHeightInMixinCall { mixin-height: @h; } }
+@mainHeight: 50%;
+.setHeight(@mainHeight);
+.heightIsSet { height: @height; }
+.useHeightInMixinCall(@height);
+
+.importRuleset() {
+ .imported {
+ exists: true;
+ }
+}
+.importRuleset();
+.testImported {
+ .imported;
+}
+
+@parameterDefault: 'top level';
+@anotherVariable: 'top level';
+//mixin uses top-level variables
+.mixinNoParam(@parameter: @parameterDefault) when (@parameter = 'top level') {
+ default: @parameter;
+ scope: @anotherVariable;
+ sub-scope-only: @subScopeOnly;
+}
+
+#allAreUsedHere {
+ //redefine top-level variables in different scope
+ @parameterDefault: 'inside';
+ @anotherVariable: 'inside';
+ @subScopeOnly: 'inside';
+ //use the mixin
+ .mixinNoParam();
+}
+#parentSelectorScope {
+ @col: white;
+ & {
+ @col: black;
+ }
+ prop: @col;
+ & {
+ @col: black;
+ }
+}
+.test-empty-mixin() {
+}
+#parentSelectorScopeMixins {
+ & {
+ .test-empty-mixin() {
+ should: never seee 1;
+ }
+ }
+ .test-empty-mixin();
+ & {
+ .test-empty-mixin() {
+ should: never seee 2;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/less/selectors.less b/test/less/selectors.less
new file mode 100644
index 00000000..8b30546f
--- /dev/null
+++ b/test/less/selectors.less
@@ -0,0 +1,156 @@
+h1, h2, h3 {
+ a, p {
+ &:hover {
+ color: red;
+ }
+ }
+}
+
+#all { color: blue; }
+#the { color: blue; }
+#same { color: blue; }
+
+ul, li, div, q, blockquote, textarea {
+ margin: 0;
+}
+
+td {
+ margin: 0;
+ padding: 0;
+}
+
+td, input {
+ line-height: 1em;
+}
+
+a {
+ color: red;
+
+ &:hover { color: blue; }
+
+ div & { color: green; }
+
+ p & span { color: yellow; }
+}
+
+.foo {
+ .bar, .baz {
+ & .qux {
+ display: block;
+ }
+ .qux & {
+ display: inline;
+ }
+ .qux& {
+ display: inline-block;
+ }
+ .qux & .biz {
+ display: none;
+ }
+ }
+}
+
+.b {
+ &.c {
+ .a& {
+ color: red;
+ }
+ }
+}
+
+.b {
+ .c & {
+ &.a {
+ color: red;
+ }
+ }
+}
+
+.p {
+ .foo &.bar {
+ color: red;
+ }
+}
+
+.p {
+ .foo&.bar {
+ color: red;
+ }
+}
+
+.foo {
+ .foo + & {
+ background: amber;
+ }
+ & + & {
+ background: amber;
+ }
+}
+
+.foo, .bar {
+ & + & {
+ background: amber;
+ }
+}
+
+.foo, .bar {
+ a, b {
+ & > & {
+ background: amber;
+ }
+ }
+}
+
+.other ::fnord { color: red }
+.other::fnord { color: red }
+.other {
+ ::bnord {color: red }
+ &::bnord {color: red }
+}
+// selector interpolation
+@theme: blood;
+@selector: ~".@{theme}";
+@{selector} {
+ color:red;
+}
+@{selector}red {
+ color: green;
+}
+.red {
+ #@{theme}.@{theme}&.black {
+ color:black;
+ }
+}
+@num: 3;
+:nth-child(@{num}) {
+ selector: interpolated;
+}
+.test {
+ &:nth-child(odd):not(:nth-child(3)) {
+ color: #ff0000;
+ }
+}
+[prop],
+[prop=10%],
+[prop="value@{num}"],
+[prop*="val@{num}"],
+[|prop~="val@{num}"],
+[*|prop$="val@{num}"],
+[ns|prop^="val@{num}"],
+[@{num}^="val@{num}"],
+[@{num}=@{num}],
+[@{num}] {
+ attributes: yes;
+}
+
+/*
+Large comment means chunk will be emitted after } which means chunk will begin with whitespace...
+blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank
+blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank
+blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank
+blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank
+blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank
+*/
+@{selector} {
+ color: red;
+}
\ No newline at end of file
diff --git a/test/less/sourcemaps/basic.json b/test/less/sourcemaps/basic.json
new file mode 100644
index 00000000..76a63c5a
--- /dev/null
+++ b/test/less/sourcemaps/basic.json
@@ -0,0 +1,3 @@
+{
+ "my-color": "red"
+}
\ No newline at end of file
diff --git a/test/less/sourcemaps/basic.less b/test/less/sourcemaps/basic.less
new file mode 100644
index 00000000..4ee8b4f6
--- /dev/null
+++ b/test/less/sourcemaps/basic.less
@@ -0,0 +1,27 @@
+@var: black;
+
+.a() {
+ color: red;
+}
+
+.b {
+ color: green;
+ .a();
+ color: blue;
+ background: @var;
+}
+
+.a, .b {
+ background: green;
+ .c, .d {
+ background: gray;
+ & + & {
+ color: red;
+ }
+ }
+}
+
+.extend:extend(.a all) {
+ color: pink;
+}
+@import (inline) "imported.css";
\ No newline at end of file
diff --git a/test/less/sourcemaps/imported.css b/test/less/sourcemaps/imported.css
new file mode 100644
index 00000000..2ee35f06
--- /dev/null
+++ b/test/less/sourcemaps/imported.css
@@ -0,0 +1,7 @@
+/*comments*/
+.unused-css {
+ color: white;
+}
+.imported {
+ color: black;
+}
\ No newline at end of file
diff --git a/test/less/static-urls/urls.less b/test/less/static-urls/urls.less
new file mode 100644
index 00000000..b0c7de09
--- /dev/null
+++ b/test/less/static-urls/urls.less
@@ -0,0 +1,33 @@
+@font-face {
+ src: url("/fonts/garamond-pro.ttf");
+ src: local(Futura-Medium),
+ url(fonts.svg#MyGeometricModern) format("svg");
+}
+#shorthands {
+ background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
+}
+#misc {
+ background-image: url(images/image.jpg);
+}
+#data-uri {
+ background: url(data:image/png;charset=utf-8;base64,
+ kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
+ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
+ kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
+ background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
+ background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
+}
+
+#svg-data-uri {
+ background: transparent url('data:image/svg+xml, ');
+}
+
+.comma-delimited {
+ background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
+}
+.values {
+ @a: 'Trebuchet';
+ url: url(@a);
+}
+
+@import "../import/import-and-relative-paths-test";
diff --git a/test/less/strings.less b/test/less/strings.less
new file mode 100644
index 00000000..c43e368d
--- /dev/null
+++ b/test/less/strings.less
@@ -0,0 +1,57 @@
+#strings {
+ background-image: url("http://son-of-a-banana.com");
+ quotes: "~" "~";
+ content: "#*%:&^,)!.(~*})";
+ empty: "";
+ brackets: "{" "}";
+ escapes: "\"hello\" \\world";
+ escapes2: "\"llo";
+}
+#comments {
+ content: "/* hello */ // not-so-secret";
+}
+#single-quote {
+ quotes: "'" "'";
+ content: '""#!&""';
+ empty: '';
+ semi-colon: ';';
+}
+#escaped {
+ filter: ~"DX.Transform.MS.BS.filter(opacity=50)";
+}
+#one-line { image: url(http://tooks.com) }
+#crazy { image: url(http://), "}", url("http://}") }
+#interpolation {
+ @var: '/dev';
+ url: "http://lesscss.org@{var}/image.jpg";
+
+ @var2: 256;
+ url2: "http://lesscss.org/image-@{var2}.jpg";
+
+ @var3: #456;
+ url3: "http://lesscss.org@{var3}";
+
+ @var4: hello;
+ url4: "http://lesscss.org/@{var4}";
+
+ @var5: 54.4px;
+ url5: "http://lesscss.org/@{var5}";
+}
+
+// multiple calls with string interpolation
+
+.mix-mul (@a: green) {
+ color: ~"@{a}";
+}
+.mix-mul-class {
+ .mix-mul(blue);
+ .mix-mul(red);
+ .mix-mul(black);
+ .mix-mul(orange);
+}
+
+@test: Arial, Verdana, San-Serif;
+.watermark {
+ @family: ~"Univers, @{test}";
+ family: @family;
+}
diff --git a/test/less/url-args/urls.less b/test/less/url-args/urls.less
new file mode 100644
index 00000000..2f1bd872
--- /dev/null
+++ b/test/less/url-args/urls.less
@@ -0,0 +1,63 @@
+@font-face {
+ src: url("/fonts/garamond-pro.ttf");
+ src: local(Futura-Medium),
+ url(fonts.svg#MyGeometricModern) format("svg");
+}
+#shorthands {
+ background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
+ background: url("img.jpg") center / 100px;
+ background: #fff url(image.png) center / 1px 100px repeat-x scroll content-box padding-box;
+}
+#misc {
+ background-image: url(images/image.jpg);
+}
+#data-uri {
+ background: url(data:image/png;charset=utf-8;base64,
+ kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
+ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
+ kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
+ background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
+ background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
+ background-image: url("http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700");
+}
+
+#svg-data-uri {
+ background: transparent url('data:image/svg+xml, ');
+}
+
+.comma-delimited {
+ background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
+}
+.values {
+ @a: 'Trebuchet';
+ url: url(@a);
+}
+
+@import "../import/imports/font";
+
+#data-uri {
+ uri: data-uri('image/jpeg;base64', '../../data/image.jpg');
+}
+
+#data-uri-guess {
+ uri: data-uri('../../data/image.jpg');
+}
+
+#data-uri-ascii {
+ uri-1: data-uri('text/html', '../../data/page.html');
+ uri-2: data-uri('../../data/page.html');
+}
+
+#svg-functions {
+ background-image: svg-gradient(to bottom, black, white);
+ background-image: svg-gradient(to bottom, black, orange 3%, white);
+ @green_5: green 5%;
+ @orange_percentage: 3%;
+ @orange_color: orange;
+ background-image: svg-gradient(to bottom, (mix(black, white) + #444) 1%, @orange_color @orange_percentage, ((@green_5)), white 95%);
+}
+
+#data-uri-with-spaces {
+ background-image: url( data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
+ background-image: url( ' data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==');
+}
diff --git a/test/less/urls.less b/test/less/urls.less
new file mode 100644
index 00000000..ca1602e2
--- /dev/null
+++ b/test/less/urls.less
@@ -0,0 +1,72 @@
+@font-face {
+ src: url("/fonts/garamond-pro.ttf");
+ src: local(Futura-Medium),
+ url(fonts.svg#MyGeometricModern) format("svg");
+}
+#shorthands {
+ background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
+ background: url("img.jpg") center / 100px;
+ background: #fff url(image.png) center / 1px 100px repeat-x scroll content-box padding-box;
+}
+#misc {
+ background-image: url(images/image.jpg);
+}
+#data-uri {
+ background: url(data:image/png;charset=utf-8;base64,
+ kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
+ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
+ kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
+ background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
+ background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
+ background-image: url("http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700");
+}
+
+#svg-data-uri {
+ background: transparent url('data:image/svg+xml, ');
+}
+
+.comma-delimited {
+ background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
+}
+.values {
+ @a: 'Trebuchet';
+ url: url(@a);
+}
+
+@import "import/import-and-relative-paths-test";
+
+#relative-url-import {
+ .unquoted-relative-path-bg;
+ .quoted-relative-path-border-image;
+}
+
+#data-uri {
+ uri: data-uri('image/jpeg;base64', '../data/image.jpg');
+}
+
+#data-uri-guess {
+ uri: data-uri('../data/image.jpg');
+}
+
+#data-uri-ascii {
+ uri-1: data-uri('text/html', '../data/page.html');
+ uri-2: data-uri('../data/page.html');
+}
+
+#data-uri-toobig {
+ uri: data-uri('../data/data-uri-fail.png');
+}
+.add_an_import(@file_to_import) {
+@import "@{file_to_import}";
+}
+
+.add_an_import("file.css");
+
+#svg-functions {
+ background-image: svg-gradient(to bottom, black, white);
+ background-image: svg-gradient(to bottom, black, orange 3%, white);
+ @green_5: green 5%;
+ @orange_percentage: 3%;
+ @orange_color: orange;
+ background-image: svg-gradient(to bottom, (mix(black, white) + #444) 1%, @orange_color @orange_percentage, ((@green_5)), white 95%);
+}
diff --git a/test/less/variables-in-at-rules.less b/test/less/variables-in-at-rules.less
new file mode 100644
index 00000000..96d8c611
--- /dev/null
+++ b/test/less/variables-in-at-rules.less
@@ -0,0 +1,20 @@
+
+@Eight: 8;
+@charset "UTF-@{Eight}";
+
+@ns: less;
+@namespace @ns "http://lesscss.org";
+
+@name: enlarger;
+@keyframes @name {
+ from {font-size: 12px;}
+ to {font-size: 15px;}
+}
+
+.m(reducer);
+.m(@name) {
+ @-webkit-keyframes @name {
+ from {font-size: 13px;}
+ to {font-size: 10px;}
+ }
+}
diff --git a/test/less/variables.less b/test/less/variables.less
new file mode 100644
index 00000000..e896f404
--- /dev/null
+++ b/test/less/variables.less
@@ -0,0 +1,83 @@
+@a: 2;
+@x: (@a * @a);
+@y: (@x + 1);
+@z: (@x * 2 + @y);
+@var: -1;
+
+.variables {
+ width: (@z + 1cm); // 14cm
+}
+
+@b: @a * 10;
+@c: #888;
+
+@fonts: "Trebuchet MS", Verdana, sans-serif;
+@f: @fonts;
+
+@quotes: "~" "~";
+@q: @quotes;
+@onePixel: 1px;
+
+.variables {
+ height: (@b + @x + 0px); // 24px
+ color: @c;
+ font-family: @f;
+ quotes: @q;
+}
+
+.redef {
+ @var: 0;
+ .inition {
+ @var: 4;
+ @var: 2;
+ three: @var;
+ @var: 3;
+ }
+ zero: @var;
+}
+
+.values {
+ minus-one: @var;
+ @a: 'Trebuchet';
+ @multi: 'A', B, C;
+ font-family: @a, @a, @a;
+ color: @c !important;
+ multi: something @multi, @a;
+}
+
+.variable-names {
+ @var: 'hello';
+ @name: 'var';
+ name: @@name;
+}
+
+.alpha {
+ @var: 42;
+ filter: alpha(opacity=@var);
+}
+
+.polluteMixin() {
+ @a: 'pollution';
+}
+.testPollution {
+ @a: 'no-pollution';
+ a: @a;
+ .polluteMixin();
+ a: @a;
+}
+
+.units {
+ width: @onePixel;
+ same-unit-as-previously: (@onePixel / @onePixel);
+ square-pixel-divided: (@onePixel * @onePixel / @onePixel);
+ odd-unit: unit((@onePixel * 4em / 2cm));
+ percentage: (10 * 50%);
+ pixels: (50px * 10);
+ conversion-metric-a: (20mm + 1cm);
+ conversion-metric-b: (1cm + 20mm);
+ conversion-imperial: (1in + 72pt + 6pc);
+ custom-unit: (42octocats * 10);
+ custom-unit-cancelling: (8cats * 9dogs / 4cats);
+ mix-units: (1px + 1em);
+ invalid-units: (1px * 1px);
+}
diff --git a/test/less/whitespace.less b/test/less/whitespace.less
new file mode 100644
index 00000000..ab4804da
--- /dev/null
+++ b/test/less/whitespace.less
@@ -0,0 +1,44 @@
+
+
+.whitespace
+ { color: white; }
+
+.whitespace
+{
+ color: white;
+}
+ .whitespace
+{ color: white; }
+
+.whitespace{color:white;}
+.whitespace { color : white ; }
+
+.white,
+.space,
+.mania
+{ color: white; }
+
+.no-semi-column { color: white }
+.no-semi-column {
+ color: white;
+ white-space: pre
+}
+.no-semi-column {border: 2px solid white}
+.newlines {
+ background: the,
+ great,
+ wall;
+ border: 2px
+ solid
+ black;
+}
+.empty {
+
+}
+.sel
+.newline_ws .tab_ws {
+color:
+white;
+background-position: 45
+-23;
+}
diff --git a/test/sourcemaps/basic.json b/test/sourcemaps/basic.json
new file mode 100644
index 00000000..ab73305d
--- /dev/null
+++ b/test/sourcemaps/basic.json
@@ -0,0 +1 @@
+{"version":3,"file":"sourcemaps/basic.css","sources":["testweb/sourcemaps/imported.css","testweb/sourcemaps/basic.less"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;ACAA;EACE,YAAA;EAJA,UAAA;EAWA,iBAAA;EALA,WAAA;EACA,mBAAA;;AAJF,EASE;AATF,EASM;EACF,gBAAA;;AACA,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFA;AAEF,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFA;EAGA,UAAA;;AALN;AAAI;AAUJ;EATE,iBAAA;;AADF,EAEE;AAFE,EAEF;AAFF,EAEM;AAFF,EAEE;AAQN,OARE;AAQF,OARM;EACF,gBAAA;;AACA,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFA;AAEF,EAFF,GAEI,KAFA;AAEF,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFA;AAEF,EAFF,GAEI,KAFA;AAEF,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFA;AAEF,EAFE,GAEA,KAFA;AAEF,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFA;AAEF,EAFE,GAEA,KAFA;AAQN,OARE,GAQF,UARE;AAQF,OARE,GAEI,KAFJ;AAQF,OARE,GAQF,UARM;AAQN,OARE,GAEI,KAFA;AAEF,EAFF,GAQF,UARE;AAEE,EAFF,GAQF,UARM;AAQN,OARM,GAQN,UARE;AAQF,OARM,GAEA,KAFJ;AAQF,OARM,GAQN,UARM;AAQN,OARM,GAEA,KAFA;AAEF,EAFE,GAQN,UARE;AAEE,EAFE,GAQN,UARM;EAGA,UAAA;;AAKN;EACE,WAAA"}
\ No newline at end of file
diff --git a/test/sourcemaps/index.html b/test/sourcemaps/index.html
new file mode 100644
index 00000000..89acca77
--- /dev/null
+++ b/test/sourcemaps/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+