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 |
|
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 |
|
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 |
|
80 |
|
81 | assert.equal(error.status, 1);
|
82 | } else if (test.verifyStderr) {
|
83 | var expectedError = read(test.errorPath, 'utf8');
|
84 | if (error === null) {
|
85 |
|
86 | assert.ok(expectedError, 'Expected some sort of warning, but found none');
|
87 | } else {
|
88 |
|
89 |
|
90 |
|
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 |
|
131 | tests = tests.filter(function(test) {
|
132 | var testSuiteFolder = test.split('/');
|
133 | var inputSass = testSuiteFolder[suiteFolderLength + 1];
|
134 |
|
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);
|