Initial commit
[yaffs-website] / node_modules / node-sass / test / spec.js
1 var assert = require('assert'),
2   fs = require('fs'),
3   exists = fs.existsSync,
4   join = require('path').join,
5   read = fs.readFileSync,
6   sass = process.env.NODESASS_COV
7       ? require('../lib-cov')
8       : require('../lib'),
9   readYaml = require('read-yaml'),
10   mergeWith = require('lodash.mergewith'),
11   assign = require('lodash.assign'),
12   glob = require('glob'),
13   specPath = require('sass-spec').dirname.replace(/\\/g, '/'),
14   impl = 'libsass',
15   version = 3.5;
16
17 var normalize = function(str) {
18   // This should be /\r\n/g, '\n', but there seems to be some empty line issues
19   return str.replace(/\s+/g, '');
20 };
21
22 var inputs = glob.sync(specPath + '/**/input.*');
23
24 var initialize = function(inputCss, options) {
25   var testCase = {};
26   var folders = inputCss.split('/');
27   var folder = join(inputCss, '..');
28   testCase.folder = folder;
29   testCase.name = folders[folders.length - 2];
30   testCase.inputPath = inputCss;
31   testCase.expectedPath = join(folder, 'expected_output.css');
32   testCase.errorPath = join(folder, 'error');
33   testCase.statusPath = join(folder, 'status');
34   testCase.optionsPath = join(folder, 'options.yml');
35   if (exists(testCase.optionsPath)) {
36     options = mergeWith(assign({}, options), readYaml.sync(testCase.optionsPath), customizer);
37   }
38   testCase.includePaths = [
39     folder,
40     join(folder, 'sub')
41   ];
42   testCase.precision = parseFloat(options[':precision']) || 5;
43   testCase.outputStyle = options[':output_style'] ? options[':output_style'].replace(':', '') : 'nested';
44   testCase.todo = options[':todo'] !== undefined && options[':todo'] !== null && options[':todo'].indexOf(impl) !== -1;
45   testCase.only = options[':only_on'] !== undefined && options[':only_on'] !== null && options[':only_on'];
46   testCase.warningTodo = options[':warning_todo'] !== undefined && options[':warning_todo'] !== null && options[':warning_todo'].indexOf(impl) !== -1;
47   testCase.startVersion = parseFloat(options[':start_version']) || 0;
48   testCase.endVersion = parseFloat(options[':end_version']) || 99;
49   testCase.options = options;
50   testCase.result = false;
51
52   // Probe filesystem once and cache the results
53   testCase.shouldFail = exists(testCase.statusPath) && !fs.statSync(testCase.statusPath).isDirectory();
54   testCase.verifyStderr = exists(testCase.errorPath) && !fs.statSync(testCase.errorPath).isDirectory();
55   return testCase;
56 };
57
58 var runTest = function(inputCssPath, options) {
59   var test = initialize(inputCssPath, options);
60
61   it(test.name, function(done) {
62     if (test.todo || test.warningTodo) {
63       this.skip('Test marked with TODO');
64     } else if (test.only && test.only.indexOf(impl) === -1) {
65       this.skip('Tests marked for only: ' + test.only.join(', '));
66     } else if (version < test.startVersion) {
67       this.skip('Tests marked for newer Sass versions only');
68     } else if (version > test.endVersion) {
69       this.skip('Tests marked for older Sass versions only');
70     } else {
71       var expected = normalize(read(test.expectedPath, 'utf8'));
72       sass.render({
73         file: test.inputPath,
74         includePaths: test.includePaths,
75         precision: test.precision,
76         outputStyle: test.outputStyle
77       }, function(error, result) {
78         if (test.shouldFail) {
79           // Replace 1, with parseInt(read(test.statusPath, 'utf8')) pending
80           // https://github.com/sass/libsass/issues/2162
81           assert.equal(error.status, 1);
82         } else if (test.verifyStderr) {
83           var expectedError = read(test.errorPath, 'utf8');
84           if (error === null) {
85             // Probably a warning
86             assert.ok(expectedError, 'Expected some sort of warning, but found none');
87           } else {
88             // The error messages seem to have some differences in areas
89             // like line numbering, so we'll check the first line for the
90             // general errror message only
91             assert.equal(
92               error.formatted.toString().split('\n')[0],
93               expectedError.toString().split('\n')[0],
94               'Should Error.\nOptions' + JSON.stringify(test.options));
95           }
96         } else if (expected) {
97           assert.equal(
98             normalize(result.css.toString()),
99             expected,
100             'Should equal with options ' + JSON.stringify(test.options)
101           );
102         }
103         done();
104       });
105     }
106   });
107 };
108
109 var specSuite = {
110   name: specPath.split('/').slice(-1)[0],
111   folder: specPath,
112   tests: [],
113   suites: [],
114   options: {}
115 };
116
117 function customizer(objValue, srcValue) {
118   if (Array.isArray(objValue)) {
119     return objValue.concat(srcValue);
120   }
121 }
122
123 var executeSuite = function(suite, tests) {
124   var suiteFolderLength = suite.folder.split('/').length;
125   var optionsFile = join(suite.folder, 'options.yml');
126   if (exists(optionsFile)) {
127     suite.options = mergeWith(assign({}, suite.options), readYaml.sync(optionsFile), customizer);
128   }
129
130   // Push tests in the current suite
131   tests = tests.filter(function(test) {
132     var testSuiteFolder = test.split('/');
133     var inputSass = testSuiteFolder[suiteFolderLength + 1];
134     // Add the test if the specPath matches the testname
135     if (inputSass === 'input.scss' || inputSass === 'input.sass') {
136       suite.tests.push(test);
137     } else {
138       return test;
139     }
140   });
141
142   if (tests.length !== 0) {
143     var prevSuite = tests[0].split('/')[suiteFolderLength];
144     var suiteName = '';
145     var prevSuiteStart = 0;
146     for (var i = 0; i < tests.length; i++) {
147       var test = tests[i];
148       suiteName = test.split('/')[suiteFolderLength];
149       if (suiteName !== prevSuite) {
150         suite.suites.push(
151           executeSuite(
152             {
153               name: prevSuite,
154               folder: suite.folder + '/' + prevSuite,
155               tests: [],
156               suites: [],
157               options: assign({}, suite.options),
158             },
159             tests.slice(prevSuiteStart, i)
160           )
161         );
162         prevSuite = suiteName;
163         prevSuiteStart = i;
164       }
165     }
166     suite.suites.push(
167       executeSuite(
168         {
169           name: suiteName,
170           folder: suite.folder + '/' + suiteName,
171           tests: [],
172           suites: [],
173           options: assign({}, suite.options),
174         },
175         tests.slice(prevSuiteStart, tests.length)
176       )
177     );
178   }
179   return suite;
180 };
181 var allSuites = executeSuite(specSuite, inputs);
182 var runSuites = function(suite) {
183   describe(suite.name, function(){
184     suite.tests.forEach(function(test){
185       runTest(test, suite.options);
186     });
187     suite.suites.forEach(function(subsuite) {
188       runSuites(subsuite);
189     });
190   });
191 };
192 runSuites(allSuites);