1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 | var util = require('util');
|
25 | var fs = require('fs');
|
26 | var path = require('path');
|
27 | var EventEmitter = require('events').EventEmitter;
|
28 |
|
29 | var sprintf = require('sprintf').sprintf;
|
30 | var async = require('async');
|
31 |
|
32 | var constants = require('./constants');
|
33 | var errors = require('./errors');
|
34 |
|
35 | var printMsg = function(msg, verbosity, minVerbosity) {
|
36 | if (verbosity >= minVerbosity) {
|
37 | util.puts(msg);
|
38 | }
|
39 | };
|
40 |
|
41 | var isNullOrUndefined = function(value) {
|
42 | if (value === null || ((typeof value === 'string') && value === 'null') ||
|
43 | value === undefined || ((typeof value === 'string') &&
|
44 | value === 'undefined')) {
|
45 | return true;
|
46 | }
|
47 |
|
48 | return false;
|
49 | };
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | var callIgnoringError = function(func, context, args, callback) {
|
60 | try {
|
61 | func.apply(context, args);
|
62 | }
|
63 | catch (err) {}
|
64 |
|
65 | if (callback) {
|
66 | callback();
|
67 | }
|
68 | };
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 | var getUnixTimestamp = function() {
|
76 | return (new Date().getTime() / 1000);
|
77 | };
|
78 |
|
79 | var addCharacters = function(string, width, character) {
|
80 | var width_ = width || 80;
|
81 | var character_ = character || ' ';
|
82 | var stringLen = string.length;
|
83 | var left = (width_ - stringLen);
|
84 |
|
85 | if (left <= 0) {
|
86 | return string;
|
87 | }
|
88 |
|
89 | while (left--) {
|
90 | string += character_;
|
91 | }
|
92 |
|
93 | return string;
|
94 | };
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 | function lpad(str, width) {
|
104 | str = String(str);
|
105 | var n = width - str.length;
|
106 | if (n < 1) return str;
|
107 | while (n--) str = ' ' + str;
|
108 | return str;
|
109 | }
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 | function rpad(str, width) {
|
119 | str = String(str);
|
120 | var n = width - str.length;
|
121 | if (n < 1) return str;
|
122 | while (n--) str = str + ' ';
|
123 | return str;
|
124 | }
|
125 |
|
126 | function LineProcessor(initialData) {
|
127 | this._buffer = initialData || '';
|
128 | }
|
129 |
|
130 | util.inherits(LineProcessor, EventEmitter);
|
131 |
|
132 | LineProcessor.prototype.appendData = function(data) {
|
133 | this._buffer += data;
|
134 | this._processData();
|
135 | };
|
136 |
|
137 | LineProcessor.prototype._processData = function() {
|
138 | var newLineMarkerIndex, line;
|
139 |
|
140 | newLineMarkerIndex = this._buffer.indexOf('\n');
|
141 | while (newLineMarkerIndex !== -1) {
|
142 | line = this._buffer.substring(0, newLineMarkerIndex);
|
143 | this._buffer = this._buffer.substring(newLineMarkerIndex + 1);
|
144 | newLineMarkerIndex = this._buffer.indexOf('\n');
|
145 |
|
146 | this.emit('line', line);
|
147 | }
|
148 | };
|
149 |
|
150 | function parseResultLine(line) {
|
151 |
|
152 | var startMarkerIndex, endMarkerIndex, testFileEndMarkerIndex;
|
153 | var coverageEndMarker, split, fileName, resultObj;
|
154 |
|
155 | testFileEndMarkerIndex = line.indexOf(constants.TEST_FILE_END_MARKER);
|
156 | coverageEndMarker = line.indexOf(constants.COVERAGE_END_MARKER);
|
157 | startMarkerIndex = line.indexOf(constants.TEST_START_MARKER);
|
158 | endMarkerIndex = line.indexOf(constants.TEST_END_MARKER);
|
159 |
|
160 | if (testFileEndMarkerIndex !== -1) {
|
161 |
|
162 | fileName = line.substring(0, testFileEndMarkerIndex);
|
163 | return [ true, fileName, null ];
|
164 | }
|
165 | else if (coverageEndMarker !== -1) {
|
166 |
|
167 | split = line.split(constants.DELIMITER);
|
168 | resultObj = {
|
169 | 'coverage': split[1].replace(constants.COVERAGE_END_MARKER, '')
|
170 | };
|
171 |
|
172 | return [ false, split[0], resultObj ];
|
173 | }
|
174 | else {
|
175 |
|
176 | line = line.replace(constants.TEST_START_MARKER, '')
|
177 | .replace(constants.TEST_END_MARKER, '');
|
178 | split = line.split(constants.DELIMITER);
|
179 | resultObj = JSON.parse(split[1]);
|
180 |
|
181 | return [ null, split[0], resultObj ];
|
182 | }
|
183 | }
|
184 |
|
185 | function isTestFile(filePath) {
|
186 | var exportedValues, key, value;
|
187 |
|
188 | try {
|
189 | exportedValues = require(filePath);
|
190 | }
|
191 | catch (err) {
|
192 | return false;
|
193 | }
|
194 |
|
195 | for (key in exportedValues) {
|
196 | if (exportedValues.hasOwnProperty(key)) {
|
197 | value = exportedValues[key];
|
198 | if (key.indexOf('test') === 0 && (typeof value === 'function')) {
|
199 | return true;
|
200 | }
|
201 | }
|
202 | }
|
203 |
|
204 | return false;
|
205 | }
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 | function getMatchingFiles(directory, matchPattern, options, callback) {
|
217 | options = options || {};
|
218 | var matchedFiles = [],
|
219 | recurse = options.recurse || false;
|
220 |
|
221 | fs.readdir(directory, function(err, files) {
|
222 | if (err) {
|
223 | callback(null, matchedFiles);
|
224 | return;
|
225 | }
|
226 |
|
227 | async.forEach(files, function(file, callback) {
|
228 | var filePath = path.join(directory, file);
|
229 | fs.stat(filePath, function(err, stats) {
|
230 | if (err) {
|
231 | callback();
|
232 | }
|
233 | else if (stats.isDirectory() && recurse) {
|
234 | getMatchingFiles(filePath, matchPattern, options, callback);
|
235 | }
|
236 | else if (matchPattern.test(file)) {
|
237 | matchedFiles.push(filePath);
|
238 | callback();
|
239 | }
|
240 | else {
|
241 | callback();
|
242 | }
|
243 | });
|
244 | },
|
245 |
|
246 | function(err) {
|
247 | callback(err, matchedFiles);
|
248 | });
|
249 | });
|
250 | };
|
251 |
|
252 | function findTestFiles(basePath, callback) {
|
253 | getMatchingFiles(basePath, /\.js/, {'recurse': true}, callback);
|
254 | }
|
255 |
|
256 | function parseArguments(rules, args) {
|
257 | var key, value, rule;
|
258 | var result = {};
|
259 |
|
260 | for (key in rules) {
|
261 | if (rules.hasOwnProperty(key)) {
|
262 | rule = rules[key];
|
263 | value = args[rule['pos']];
|
264 |
|
265 | if (isNullOrUndefined(value)) {
|
266 | value = null;
|
267 | }
|
268 | else if (rule['type'] === 'number') {
|
269 | value = parseInt(value, 10);
|
270 | }
|
271 |
|
272 | result[key] = value;
|
273 | }
|
274 | }
|
275 |
|
276 | return result;
|
277 | }
|
278 |
|
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 | function fireOnce(fn) {
|
286 | var fired = false;
|
287 | return function wrapped() {
|
288 | if (!fired) {
|
289 | fired = true;
|
290 | fn.apply(null, arguments);
|
291 | }
|
292 | };
|
293 | };
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 |
|
301 |
|
302 |
|
303 |
|
304 |
|
305 | function merge(a, b) {
|
306 | var c = {};
|
307 | var attrname;
|
308 | for (attrname in a) {
|
309 | if (a.hasOwnProperty(attrname)) {
|
310 | c[attrname] = a[attrname];
|
311 | }
|
312 | }
|
313 | for (attrname in b) {
|
314 | if (b.hasOwnProperty(attrname)) {
|
315 | c[attrname] = b[attrname];
|
316 | }
|
317 | }
|
318 | return c;
|
319 | }
|
320 |
|
321 | exports.printMsg = printMsg;
|
322 | exports.isNullOrUndefined = isNullOrUndefined;
|
323 |
|
324 | exports.getUnixTimestamp = getUnixTimestamp;
|
325 | exports.addCharacters = addCharacters;
|
326 |
|
327 | exports.rpad = rpad;
|
328 | exports.lpad = lpad;
|
329 |
|
330 | exports.LineProcessor = LineProcessor;
|
331 | exports.parseResultLine = parseResultLine;
|
332 | exports.getMatchingFiles = getMatchingFiles;
|
333 | exports.findTestFiles = findTestFiles;
|
334 | exports.parseArguments = parseArguments;
|
335 | exports.fireOnce = fireOnce;
|
336 | exports.merge = merge;
|