| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 | var assert = require('assert'),  fs = require('fs'),  exists = fs.existsSync,  join = require('path').join,  read = fs.readFileSync,  sass = process.env.NODESASS_COV      ? require('../lib-cov')      : require('../lib'),  readYaml = require('read-yaml'),  mergeWith = require('lodash/mergeWith'),  assign = require('lodash/assign'),  glob = require('glob'),  specPath = require('sass-spec').dirname.replace(/\\/g, '/'),  impl = 'libsass',  version = 3.5;var normalize = function(str) {  // This should be /\r\n/g, '\n', but there seems to be some empty line issues  return str.replace(/\s+/g, '');};var inputs = glob.sync(specPath + '/**/input.*');var initialize = function(inputCss, options) {  var testCase = {};  var folders = inputCss.split('/');  var folder = join(inputCss, '..');  testCase.folder = folder;  testCase.name = folders[folders.length - 2];  testCase.inputPath = inputCss;  testCase.expectedPath = join(folder, 'expected_output.css');  testCase.errorPath = join(folder, 'error');  testCase.statusPath = join(folder, 'status');  testCase.optionsPath = join(folder, 'options.yml');  if (exists(testCase.optionsPath)) {    options = mergeWith(assign({}, options), readYaml.sync(testCase.optionsPath), customizer);  }  testCase.includePaths = [    folder,    join(folder, 'sub')  ];  testCase.precision = parseFloat(options[':precision']) || 5;  testCase.outputStyle = options[':output_style'] ? options[':output_style'].replace(':', '') : 'nested';  testCase.todo = options[':todo'] !== undefined && options[':todo'] !== null && options[':todo'].indexOf(impl) !== -1;  testCase.only = options[':only_on'] !== undefined && options[':only_on'] !== null && options[':only_on'];  testCase.warningTodo = options[':warning_todo'] !== undefined && options[':warning_todo'] !== null && options[':warning_todo'].indexOf(impl) !== -1;  testCase.startVersion = parseFloat(options[':start_version']) || 0;  testCase.endVersion = parseFloat(options[':end_version']) || 99;  testCase.options = options;  testCase.result = false;  // Probe filesystem once and cache the results  testCase.shouldFail = exists(testCase.statusPath) && !fs.statSync(testCase.statusPath).isDirectory();  testCase.verifyStderr = exists(testCase.errorPath) && !fs.statSync(testCase.errorPath).isDirectory();  return testCase;};var runTest = function(inputCssPath, options) {  var test = initialize(inputCssPath, options);  it(test.name, function(done) {    if (test.todo || test.warningTodo) {      this.skip('Test marked with TODO');    } else if (test.only && test.only.indexOf(impl) === -1) {      this.skip('Tests marked for only: ' + test.only.join(', '));    } else if (version < test.startVersion) {      this.skip('Tests marked for newer Sass versions only');    } else if (version > test.endVersion) {      this.skip('Tests marked for older Sass versions only');    } else {      var expected = normalize(read(test.expectedPath, 'utf8'));      sass.render({        file: test.inputPath,        includePaths: test.includePaths,        precision: test.precision,        outputStyle: test.outputStyle      }, function(error, result) {        if (test.shouldFail) {          // Replace 1, with parseInt(read(test.statusPath, 'utf8')) pending          // https://github.com/sass/libsass/issues/2162          assert.equal(error.status, 1);        } else if (test.verifyStderr) {          var expectedError = read(test.errorPath, 'utf8');          if (error === null) {            // Probably a warning            assert.ok(expectedError, 'Expected some sort of warning, but found none');          } else {            // The error messages seem to have some differences in areas            // like line numbering, so we'll check the first line for the            // general errror message only            assert.equal(              error.formatted.toString().split('\n')[0],              expectedError.toString().split('\n')[0],              'Should Error.\nOptions' + JSON.stringify(test.options));          }        } else if (expected) {          assert.equal(            normalize(result.css.toString()),            expected,            'Should equal with options ' + JSON.stringify(test.options)          );        }        done();      });    }  });};var specSuite = {  name: specPath.split('/').slice(-1)[0],  folder: specPath,  tests: [],  suites: [],  options: {}};function customizer(objValue, srcValue) {  if (Array.isArray(objValue)) {    return objValue.concat(srcValue);  }}var executeSuite = function(suite, tests) {  var suiteFolderLength = suite.folder.split('/').length;  var optionsFile = join(suite.folder, 'options.yml');  if (exists(optionsFile)) {    suite.options = mergeWith(assign({}, suite.options), readYaml.sync(optionsFile), customizer);  }  // Push tests in the current suite  tests = tests.filter(function(test) {    var testSuiteFolder = test.split('/');    var inputSass = testSuiteFolder[suiteFolderLength + 1];    // Add the test if the specPath matches the testname    if (inputSass === 'input.scss' || inputSass === 'input.sass') {      suite.tests.push(test);    } else {      return test;    }  });  if (tests.length !== 0) {    var prevSuite = tests[0].split('/')[suiteFolderLength];    var suiteName = '';    var prevSuiteStart = 0;    for (var i = 0; i < tests.length; i++) {      var test = tests[i];      suiteName = test.split('/')[suiteFolderLength];      if (suiteName !== prevSuite) {        suite.suites.push(          executeSuite(            {              name: prevSuite,              folder: suite.folder + '/' + prevSuite,              tests: [],              suites: [],              options: assign({}, suite.options),            },            tests.slice(prevSuiteStart, i)          )        );        prevSuite = suiteName;        prevSuiteStart = i;      }    }    suite.suites.push(      executeSuite(        {          name: suiteName,          folder: suite.folder + '/' + suiteName,          tests: [],          suites: [],          options: assign({}, suite.options),        },        tests.slice(prevSuiteStart, tests.length)      )    );  }  return suite;};var allSuites = executeSuite(specSuite, inputs);var runSuites = function(suite) {  describe(suite.name, function(){    suite.tests.forEach(function(test){      runTest(test, suite.options);    });    suite.suites.forEach(function(subsuite) {      runSuites(subsuite);    });  });};runSuites(allSuites);
 |