Line | Hits | Source |
---|---|---|
1 | /*! | |
2 | * jscoverage: index.js | |
3 | * Authors : fish <zhengxinlin@gmail.com> (https://github.com/fishbar) | |
4 | * Create : 2014-04-03 15:20:13 | |
5 | * CopyRight 2014 (c) Fish And Other Contributors | |
6 | * | |
7 | */ | |
8 | var fs = require('xfs'); | |
9 | var path = require('path'); | |
10 | var argv = require('optimist').argv; | |
11 | var patch = require('./lib/patch'); | |
12 | var cmd = argv['$0']; | |
13 | var MODE_MOCHA = false; | |
14 | var FLAG_LOCK = false; | |
15 | if (/mocha/.test(cmd)) { | |
16 | 1 | MODE_MOCHA = true; |
17 | } | |
18 | ||
19 | if (MODE_MOCHA) { | |
20 | 1 | prepareMocha(); |
21 | } | |
22 | /** | |
23 | * prepare env for mocha test | |
24 | * @covignore | |
25 | */ | |
26 | function prepareMocha() { | |
27 | var covIgnore = argv.covignore; | |
28 | var cwd = process.cwd(); | |
29 | var covlevel = argv.coverage; | |
30 | if (covlevel) { | |
31 | var tmp = covlevel.split(','); | |
32 | covlevel = { | |
33 | high: parseFloat(tmp[0], 10), | |
34 | middle: parseFloat(tmp[1], 10), | |
35 | low: parseFloat(tmp[2], 10) | |
36 | }; | |
37 | } else { | |
38 | covlevel = { | |
39 | high: 0.9, | |
40 | middle: 0.7, | |
41 | low: 0.3 | |
42 | }; | |
43 | } | |
44 | /** | |
45 | * add after hook | |
46 | * @return {[type]} [description] | |
47 | */ | |
48 | process.nextTick(function () { | |
49 | try { | |
50 | after(function () { | |
51 | if (FLAG_LOCK) { | |
52 | return; | |
53 | } | |
54 | FLAG_LOCK = true; | |
55 | if (typeof _$jscoverage === 'undefined') { | |
56 | return; | |
57 | } | |
58 | try { | |
59 | if (argv.covout === 'none') { | |
60 | return; | |
61 | } | |
62 | if (!argv.covout) { | |
63 | argv.covout = 'summary'; | |
64 | } | |
65 | var reporter; | |
66 | if (/^\w+$/.test(argv.covout)) { | |
67 | reporter = require('./reporter/' + argv.covout); | |
68 | } else { | |
69 | reporter = require(argv.covout); | |
70 | } | |
71 | reporter.process(_$jscoverage, exports.coverageStats(), covlevel); | |
72 | } catch (e) { | |
73 | console.error('jscoverage reporter error', e); | |
74 | } | |
75 | }); | |
76 | } catch (e) { | |
77 | // do nothing | |
78 | } | |
79 | }); | |
80 | if (argv.covinject) { | |
81 | patch.enableInject(true); | |
82 | } | |
83 | if (!covIgnore) { | |
84 | try { | |
85 | var stat = fs.statSync('.covignore'); | |
86 | stat && (covIgnore = '.covignore'); | |
87 | } catch (e) { | |
88 | return; | |
89 | } | |
90 | } | |
91 | try { | |
92 | covIgnore = fs.readFileSync(covIgnore).toString().split(/\r?\n/g); | |
93 | } catch (e) { | |
94 | throw new Error('jscoverage loading covIgnore file error:' + covIgnore); | |
95 | } | |
96 | covIgnore.forEach(function (v, i, a) { | |
97 | if (v.indexOf('/') === 0) { | |
98 | v = '^' + cwd + v; | |
99 | } | |
100 | a[i] = new RegExp(v.replace(/\./g, '\\.').replace(/\*/g, '.*')); | |
101 | }); | |
102 | ||
103 | patch.setCovIgnore(covIgnore); | |
104 | } | |
105 | ||
106 | var jscoverage = require('./lib/jscoverage'); | |
107 | ||
108 | /** | |
109 | * enableInject description | |
110 | * @param {Boolean} true or false | |
111 | */ | |
112 | exports.enableInject = patch.enableInject; | |
113 | /** | |
114 | * config the inject function names | |
115 | * @param {Object} obj {get, replace, call, reset} | |
116 | * @example | |
117 | * | |
118 | * jsc.config({get:'$get', replace:'$replace'}); | |
119 | * | |
120 | * ===================== | |
121 | * | |
122 | * testMod = require('testmodule'); | |
123 | * testMod.$get('name'); | |
124 | * testMod.$replace('name', obj); | |
125 | */ | |
126 | exports.config = function (obj) { | |
127 | 1 | var inject_functions = patch.getInjectFunctions(); |
128 | for (var i in obj) { | |
129 | 4 | inject_functions[i] = obj[i]; |
130 | } | |
131 | }; | |
132 | /** | |
133 | * process Code, inject the coverage code to the input Code string | |
134 | * @param {String} filename jscoverage file flag | |
135 | * @param {Code} content | |
136 | * @return {Code} instrumented code | |
137 | */ | |
138 | exports.process = jscoverage.process; | |
139 | ||
140 | /** | |
141 | * processFile, instrument singfile | |
142 | * @sync | |
143 | * @param {Path} source absolute Path | |
144 | * @param {Path} dest absolute Path | |
145 | * @param {Object} option [description] | |
146 | */ | |
147 | exports.processFile = function (source, dest, option) { | |
148 | 6 | var content; |
149 | 6 | var stats; |
150 | // test source is file or dir, or not a file | |
151 | try { | |
152 | 6 | stats = fs.statSync(source); |
153 | if (stats.isDirectory()) { | |
154 | 1 | throw new Error('path is dir'); |
155 | } else if (!stats.isFile()) { | |
156 | 1 | throw new Error('path is not a regular file'); |
157 | } | |
158 | } catch (e) { | |
159 | 5 | throw new Error('source file error' + e); |
160 | } | |
161 | ||
162 | 1 | fs.sync().mkdir(path.dirname(dest)); |
163 | ||
164 | 1 | content = fs.readFileSync(source).toString(); |
165 | 1 | content = content.toString(); |
166 | 1 | content = this.process(source, content); |
167 | 1 | fs.writeFileSync(dest, content); |
168 | }; | |
169 | ||
170 | ||
171 | /** | |
172 | * sum the coverage rate | |
173 | * @public | |
174 | */ | |
175 | exports.coverageStats = function () { | |
176 | 1 | var file; |
177 | 1 | var tmp; |
178 | 1 | var total; |
179 | 1 | var touched; |
180 | 1 | var n, len; |
181 | 1 | var stats = {}; |
182 | 1 | var conds, condsMap, cond; |
183 | 1 | var line, start, offset; |
184 | if (typeof _$jscoverage === 'undefined') { | |
185 | 0 | return; |
186 | } | |
187 | for (var i in _$jscoverage) { | |
188 | 11 | file = i; |
189 | 11 | tmp = _$jscoverage[i]; |
190 | if (!tmp.length) { | |
191 | 0 | continue; |
192 | } | |
193 | 11 | total = touched = 0; |
194 | for (n = 0, len = tmp.length; n < len; n++) { | |
195 | if (tmp[n] !== undefined) { | |
196 | 358 | total ++; |
197 | if (tmp[n] > 0) { | |
198 | 335 | touched ++; |
199 | } | |
200 | } | |
201 | } | |
202 | 11 | conds = tmp.condition; |
203 | 11 | condsMap = {}; |
204 | for (n in conds) { | |
205 | if (conds[i] === 0) { | |
206 | 0 | cond = i.split('_'); |
207 | 0 | line = cond[0]; |
208 | 0 | start = cond[1]; |
209 | 0 | offset = cond[2]; |
210 | if (!condsMap[line]) { | |
211 | 0 | condsMap[line] = []; |
212 | } | |
213 | 0 | condsMap[line].push([start, offset]); |
214 | } else { | |
215 | 215 | touched ++; |
216 | } | |
217 | 215 | total ++; |
218 | } | |
219 | 11 | stats[file] = { |
220 | sloc: total, | |
221 | hits: touched, | |
222 | coverage: total ? touched / total : 0, | |
223 | percent: total ? ((touched / total) * 100).toFixed(2) + '%' : '~', | |
224 | condition: condsMap | |
225 | }; | |
226 | } | |
227 | 1 | return stats; |
228 | }; | |
229 | ||
230 | /** | |
231 | * get lcov report | |
232 | * @return {[type]} [description] | |
233 | */ | |
234 | exports.getLCOV = function () { | |
235 | 1 | var tmp; |
236 | 1 | var total; |
237 | 1 | var touched; |
238 | 1 | var n, len; |
239 | 1 | var lcov = ''; |
240 | if (typeof _$jscoverage === 'undefined') { | |
241 | 0 | return; |
242 | } | |
243 | 1 | Object.keys(_$jscoverage).forEach(function (file) { |
244 | 10 | lcov += 'SF:' + file + '\n'; |
245 | 10 | tmp = _$jscoverage[file]; |
246 | if (!tmp.length) { | |
247 | 0 | return; |
248 | } | |
249 | 10 | total = touched = 0; |
250 | for (n = 0, len = tmp.length; n < len; n++) { | |
251 | if (tmp[n] !== undefined) { | |
252 | 330 | lcov += 'DA:' + n + ',' + tmp[n] + '\n'; |
253 | 330 | total ++; |
254 | if (tmp[n] > 0) { | |
255 | 201 | touched++; |
256 | } | |
257 | } | |
258 | } | |
259 | 10 | lcov += 'end_of_record\n'; |
260 | }); | |
261 | 1 | return lcov; |
262 | }; | |
263 |
Line | Hits | Source |
---|---|---|
1 | /*! | |
2 | * jscoverage: lib/instrument.js | |
3 | * Authors : fish <zhengxinlin@gmail.com> (https://github.com/fishbar) | |
4 | * Create : 2014-04-03 15:20:13 | |
5 | * CopyRight 2014 (c) Fish And Other Contributors | |
6 | */ | |
7 | /** | |
8 | * instrument code | |
9 | * @example | |
10 | * var ist = new Instrument(); | |
11 | * var resCode = ist.process(str); | |
12 | */ | |
13 | var Uglify = require('uglify-js'); | |
14 | ||
15 | function Instrument() { | |
16 | /** | |
17 | * filename needed | |
18 | * @type {String} | |
19 | */ | |
20 | 1 | this.filename = null; |
21 | /** | |
22 | * store injected code | |
23 | * @type {String} | |
24 | */ | |
25 | 1 | this.code = null; |
26 | /** | |
27 | * 储存line信息 | |
28 | * @type {Array} | |
29 | */ | |
30 | 1 | this.lines = []; |
31 | /** | |
32 | * 储存condition信息 | |
33 | * @type {Object} | |
34 | */ | |
35 | 1 | this.conds = {}; |
36 | /** | |
37 | * source code in array | |
38 | * @type {Array} | |
39 | */ | |
40 | 1 | this.source = null; |
41 | } | |
42 | ||
43 | Instrument.prototype = { | |
44 | // 行类型 | |
45 | T_LINE: 'line', | |
46 | T_COND: 'cond', | |
47 | /** | |
48 | * process code | |
49 | * @public | |
50 | * @param {String} code source code | |
51 | * @return {String} injected code | |
52 | */ | |
53 | process: function (filename, code) { | |
54 | if (!filename) { | |
55 | 0 | throw new Error('[jscoverage]instrument need filename!'); |
56 | } | |
57 | ||
58 | 1 | var ist = this; |
59 | // parse ast | |
60 | 1 | var ast = Uglify.parse(code); |
61 | ||
62 | 1 | this.filename = filename; |
63 | 1 | this.source = code.split(/\r?\n/); |
64 | ||
65 | // init walker | |
66 | 1 | var walker = new Uglify.TreeWalker(function (node) { |
67 | if (node instanceof Uglify.AST_Toplevel) { | |
68 | 1 | return; |
69 | } | |
70 | if (ist.checkIfIgnore(node, walker.stack)) { | |
71 | 4 | return; |
72 | } | |
73 | ||
74 | if (node instanceof Uglify.AST_Conditional) { // 三元判断 | |
75 | 1 | node.consequent = ist.inject('cond', node.consequent.start.line, node.consequent); |
76 | 1 | node.alternative = ist.inject('cond', node.alternative.start.line, node.alternative); |
77 | } else if (node.TYPE === 'Binary') { | |
78 | if (!(node.left instanceof Uglify.AST_Constant)) { | |
79 | 3 | node.left = ist.inject('cond', node.left.start.line, node.left); |
80 | } | |
81 | if (!(node.right instanceof Uglify.AST_Constant)) { | |
82 | 2 | node.right = ist.inject('cond', node.right.start.line, node.right); |
83 | } | |
84 | } | |
85 | 233 | var len = node.body ? node.body.length : 0; |
86 | if (len) { | |
87 | 6 | var res = []; |
88 | 6 | var subNode; |
89 | for (var i = 0; i < len; i++) { | |
90 | 19 | subNode = node.body[i]; |
91 | if (ist.checkIfIgnore(subNode, walker.stack)) { | |
92 | 1 | res.push(subNode); |
93 | 1 | continue; |
94 | } | |
95 | if (subNode instanceof Uglify.AST_Statement) { | |
96 | if (ist.ifExclude(subNode)) { | |
97 | 4 | res.push(subNode); |
98 | 4 | continue; |
99 | } | |
100 | 14 | res.push(ist.inject('line', subNode.start.line)); |
101 | } else if (subNode instanceof Uglify.AST_Var) { | |
102 | 0 | res.push(ist.inject('line', subNode.start.line)); |
103 | } | |
104 | 14 | res.push(subNode); |
105 | } | |
106 | 6 | node.body = res; |
107 | } | |
108 | }); | |
109 | // figure_out_scope | |
110 | 1 | ast.figure_out_scope(); |
111 | // walk process | |
112 | 1 | ast.walk(walker); |
113 | ||
114 | 1 | var out = Uglify.OutputStream({ |
115 | preserve_line : true, | |
116 | comments: 'all', | |
117 | beautify: true | |
118 | }); | |
119 | // rebuild file | |
120 | 1 | ast.print(out); |
121 | 1 | this.code = out.toString(); |
122 | 1 | return this; |
123 | }, | |
124 | /** | |
125 | * 注入覆盖率查询方法 | |
126 | * @private | |
127 | * @param {String} type inject type, line | conds | |
128 | * @param {Number} line line number | |
129 | * @param {Object} expr any expression, or node, or statement | |
130 | * @return {AST_Func} Object | |
131 | */ | |
132 | inject: function (type, line, expr) { | |
133 | 21 | var args = []; |
134 | if (type === this.T_LINE) { | |
135 | 14 | this.lines.push(line); |
136 | 14 | args = [ |
137 | new Uglify.AST_String({value: this.filename}), | |
138 | new Uglify.AST_String({value: type}), | |
139 | new Uglify.AST_Number({value: line}) | |
140 | ]; | |
141 | } else if (type === this.T_COND) { | |
142 | 7 | var start = expr.start.col; |
143 | 7 | var offset = expr.end.endpos - expr.start.pos; |
144 | 7 | var key = line + '_' + start + '_' + offset; // 编码 |
145 | 7 | this.conds[key] = 0; |
146 | 7 | args = [ |
147 | new Uglify.AST_String({value: this.filename}), | |
148 | new Uglify.AST_String({value: type}), | |
149 | new Uglify.AST_String({value: key}), | |
150 | expr | |
151 | ]; | |
152 | } | |
153 | ||
154 | 21 | var call = new Uglify.AST_Call({ |
155 | expression: new Uglify.AST_SymbolRef({name: '_$jscmd'}), | |
156 | //end: new Uglify.AST_ | |
157 | args: args | |
158 | }); | |
159 | ||
160 | if (type === this.T_LINE) { | |
161 | 14 | return new Uglify.AST_SimpleStatement({ |
162 | body: call, | |
163 | end: new Uglify.AST_Token({value: ';'}) | |
164 | }); | |
165 | } else { | |
166 | 7 | return call; |
167 | } | |
168 | }, | |
169 | /** | |
170 | * check if need inject | |
171 | * @param {AST_Node} node | |
172 | * @return {Boolean} | |
173 | */ | |
174 | ifExclude: function (node) { | |
175 | if (node instanceof Uglify.AST_LoopControl) { | |
176 | 2 | return false; |
177 | } | |
178 | if ( | |
179 | node instanceof Uglify.AST_IterationStatement || | |
180 | node instanceof Uglify.AST_StatementWithBody || | |
181 | node instanceof Uglify.AST_Block | |
182 | ) { | |
183 | 4 | return true; |
184 | } | |
185 | }, | |
186 | checkIfIgnore: function (node, stack) { | |
187 | 256 | var cmt; |
188 | if (node.start && node.start.comments_before.length) { | |
189 | 13 | cmt = node.start.comments_before[node.start.comments_before.length - 1]; |
190 | if (/@covignore/.test(cmt.value)) { | |
191 | 4 | node.__covignore = true; |
192 | } | |
193 | } | |
194 | if (node.__covignore) { | |
195 | 4 | return true; |
196 | } | |
197 | if (stack) { | |
198 | for (var i = stack.length - 1; i > 0; i--) { | |
199 | if (stack[i].__covignore) { | |
200 | 1 | return true; |
201 | } | |
202 | } | |
203 | } | |
204 | 251 | return false; |
205 | } | |
206 | }; | |
207 | ||
208 | module.exports = Instrument; |
Line | Hits | Source |
---|---|---|
1 | /*! | |
2 | * jscoverage: lib/jscoverage.js | |
3 | * Authors : fish <zhengxinlin@gmail.com> (https://github.com/fishbar) | |
4 | * Create : 2014-04-03 15:20:13 | |
5 | * CopyRight 2014 (c) Fish And Other Contributors | |
6 | */ | |
7 | var Instrument = require('./instrument'); | |
8 | ||
9 | /** | |
10 | * do not exec this function | |
11 | * the function body will insert into instrument files | |
12 | * | |
13 | * _$jscoverage = { | |
14 | * filename : { | |
15 | * line1: 0 | |
16 | * line2: 1 | |
17 | * line3: undefined | |
18 | * .... | |
19 | * source: [], | |
20 | * condition: [ | |
21 | * line_start_offset | |
22 | * ] | |
23 | * } | |
24 | * } | |
25 | */ | |
26 | function jscFunctionBody() { | |
27 | // instrument by jscoverage, do not modifly this file | |
28 | 1 | (function (file, lines, conds, source) { |
29 | 1 | var BASE; |
30 | if (typeof global === 'object') { | |
31 | 1 | BASE = global; |
32 | } else if (typeof window === 'object') { | |
33 | 0 | BASE = window; |
34 | } else { | |
35 | 0 | throw new Error('[jscoverage] unknow ENV!'); |
36 | } | |
37 | if (BASE._$jscoverage) { | |
38 | 0 | BASE._$jscmd(file, 'init', lines, conds, source); |
39 | 0 | return; |
40 | } | |
41 | 1 | var cov = {}; |
42 | /** | |
43 | * jsc(file, 'init', lines, condtions) | |
44 | * jsc(file, 'line', lineNum) | |
45 | * jsc(file, 'cond', lineNum, expr, start, offset) | |
46 | */ | |
47 | function jscmd(file, type, line, express, start, offset) { | |
48 | 3 | var storage; |
49 | switch (type) { | |
50 | case 'init': | |
51 | 1 | storage = []; |
52 | for (var i = 0; i < line.length; i ++) { | |
53 | 1 | storage[line[i]] = 0; |
54 | } | |
55 | 1 | var condition = express; |
56 | 1 | var source = start; |
57 | 1 | storage.condition = condition; |
58 | 1 | storage.source = source; |
59 | 1 | cov[file] = storage; |
60 | 1 | break; |
61 | case 'line': | |
62 | 1 | storage = cov[file]; |
63 | 1 | storage[line] ++; |
64 | 1 | break; |
65 | case 'cond': | |
66 | 1 | storage = cov[file]; |
67 | 1 | storage.condition[line] ++; |
68 | 1 | return express; |
69 | } | |
70 | } | |
71 | ||
72 | 1 | BASE._$jscoverage = cov; |
73 | 1 | BASE._$jscmd = jscmd; |
74 | 1 | jscmd(file, 'init', lines, conds, source); |
75 | })('$file$', $lines$, $conds$, $source$); | |
76 | } | |
77 | /** | |
78 | * gen coverage head | |
79 | */ | |
80 | function genCodeCoverage(instrObj) { | |
81 | if (!instrObj) { | |
82 | 0 | return ''; |
83 | } | |
84 | 1 | var code = []; |
85 | 1 | var filename = instrObj.filename; |
86 | // Fix windows path | |
87 | 1 | filename = filename.replace(/\\/g, '/'); |
88 | 1 | var lines = instrObj.lines; |
89 | 1 | var conditions = instrObj.conds; |
90 | 1 | var src = instrObj.source; |
91 | 1 | var jscfArray = jscFunctionBody.toString().split('\n'); |
92 | 1 | jscfArray = jscfArray.slice(1, jscfArray.length - 1); |
93 | 1 | var ff = jscfArray.join('\n').replace(/(^|\n) {2}/g, '\n') |
94 | .replace(/\$(\w+)\$/g, function (m0, m1){ | |
95 | switch (m1) { | |
96 | case 'file': | |
97 | 1 | return filename; |
98 | case 'lines': | |
99 | 1 | return JSON.stringify(lines); |
100 | case 'conds': | |
101 | 1 | return JSON.stringify(conditions); |
102 | case 'source': | |
103 | 1 | return JSON.stringify(src); |
104 | } | |
105 | }); | |
106 | 1 | code.push(ff); |
107 | 1 | code.push(instrObj.code); |
108 | 1 | return code.join('\n'); |
109 | } | |
110 | ||
111 | exports.process = function (filename, content) { | |
112 | if (!filename) { | |
113 | 1 | throw new Error('jscoverage.process(filename, content), filename needed!'); |
114 | } | |
115 | 2 | filename = filename.replace(/\\/g, '/'); |
116 | if (!content) { | |
117 | 1 | return ''; |
118 | } | |
119 | 1 | var instrObj; |
120 | 1 | var ist = new Instrument(); |
121 | 1 | instrObj = ist.process(filename, content); |
122 | 1 | return genCodeCoverage(instrObj); |
123 | }; | |
124 |
Line | Hits | Source |
---|---|---|
1 | /*! | |
2 | * jscoverage: lib/patch.js | |
3 | * Authors : fish <zhengxinlin@gmail.com> (https://github.com/fishbar) | |
4 | * Create : 2014-04-03 15:20:13 | |
5 | * CopyRight 2014 (c) Fish And Other Contributors | |
6 | */ | |
7 | var Module = require('module'); | |
8 | var path = require('path'); | |
9 | var fs = require('fs'); | |
10 | var argv = require('optimist').argv; | |
11 | var jscoverage = require('./jscoverage'); | |
12 | ||
13 | var covInject = false; | |
14 | var covIgnore = []; | |
15 | ||
16 | var injectFunctions = { | |
17 | get : '_get', | |
18 | replace : '_replace', | |
19 | call : '_call', | |
20 | reset : '_reset', | |
21 | test: '_test' | |
22 | }; | |
23 | ||
24 | exports.getInjectFunctions = function () { | |
25 | 1 | return injectFunctions; |
26 | }; | |
27 | ||
28 | exports.enableInject = function (bool) { | |
29 | 1 | covInject = bool; |
30 | }; | |
31 | exports.setCovIgnore = function (ignore) { | |
32 | 2 | covIgnore = ignore; |
33 | }; | |
34 | /** | |
35 | * do mock things here | |
36 | * @covignore | |
37 | */ | |
38 | (function () { | |
39 | if (Module.prototype.__jsc_patch__) { | |
40 | return; | |
41 | } | |
42 | Module.prototype.__jsc_patch__ = true; | |
43 | var origin_require = Module.prototype.require; | |
44 | Module.prototype.require = function (filename) { | |
45 | var needinject = covInject; | |
46 | var ff = filename; | |
47 | filename = Module._resolveFilename(filename, this); | |
48 | var flagjsc = checkModule(filename); | |
49 | if (typeof filename === 'object') { | |
50 | filename = filename[0]; | |
51 | } | |
52 | ||
53 | if (!flagjsc) { | |
54 | return origin_require.call(this, filename); | |
55 | } | |
56 | ||
57 | var cachedModule = Module._cache[filename]; | |
58 | // take care of module cache | |
59 | if (flagjsc && cachedModule && cachedModule.__coveraged__) { | |
60 | return cachedModule.exports; | |
61 | } | |
62 | // console.log('jscoverage:', ff, 'cov', flagjsc, 'inject', needinject); | |
63 | var module = new Module(filename, this); | |
64 | try { | |
65 | module.filename = filename; | |
66 | module.paths = Module._nodeModulePaths(path.dirname(filename)); | |
67 | Module._extensions['.js'](module, filename, { | |
68 | flagjsc : flagjsc, | |
69 | needinject : needinject | |
70 | }); | |
71 | module.__coveraged__ = flagjsc; | |
72 | module.loaded = true; | |
73 | Module._cache[filename] = module; | |
74 | } catch (err) { | |
75 | delete Module._cache[filename]; | |
76 | console.error(err.stack); | |
77 | throw err; | |
78 | } | |
79 | return module.exports; | |
80 | }; | |
81 | function stripBOM(content) { | |
82 | // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) | |
83 | // because the buffer-to-string conversion in `fs.readFileSync()` | |
84 | // translates it to FEFF, the UTF-16 BOM. | |
85 | if (content.charCodeAt(0) === 0xFEFF) { | |
86 | content = content.slice(1); | |
87 | } | |
88 | return content; | |
89 | } | |
90 | Module._extensions['.js'] = function (module, filename, status) { | |
91 | var content = fs.readFileSync(filename, 'utf8'); | |
92 | var tmpFuncBody; | |
93 | var injectFn = exports.getInjectFunctions(); | |
94 | // trim first line when script is a shell script | |
95 | // content = content.replace(/^\#\![^\n]+\n/, ''); | |
96 | if (status && status.flagjsc) { | |
97 | content = jscoverage.process(filename, content); | |
98 | } | |
99 | if (status && status.needinject) { | |
100 | tmpFuncBody = injectFunctionBody.toString().replace(/\$\$(\w+)\$\$/g, function (m0, m1) { | |
101 | return injectFunctions[m1]; | |
102 | }); | |
103 | tmpFuncBody = tmpFuncBody.split(/\n/); | |
104 | content += '\n' + tmpFuncBody.slice(1, tmpFuncBody.length - 1).join('\n'); | |
105 | } | |
106 | module._compile(stripBOM(content), filename); | |
107 | }; | |
108 | })(); | |
109 | ||
110 | function checkModule(module) { | |
111 | ||
112 | // native module | |
113 | if (!/\//.test(module)) { | |
114 | 2 | return false; |
115 | } | |
116 | // modules in node_modules | |
117 | if (/\/node_modules\//.test(module)) { | |
118 | 1 | return false; |
119 | } | |
120 | 2 | var flagIgnore = false; |
121 | 2 | covIgnore.forEach(function (v) { |
122 | if (v.test(module)) { | |
123 | 1 | flagIgnore = true; |
124 | } | |
125 | }); | |
126 | 2 | return !flagIgnore; |
127 | } | |
128 | ||
129 | /** | |
130 | * do not exec this function | |
131 | * @covignore | |
132 | */ | |
133 | function injectFunctionBody() { | |
134 | (function (){ | |
135 | if (module.exports._i_n_j_e_c_t_e_d_) { | |
136 | return; | |
137 | } | |
138 | if (module.exports.$$call$$ || module.exports.$$get$$ || | |
139 | module.exports.$$replace$$ || module.exports.$$reset$$) { | |
140 | throw new Error("[jscoverage] jscoverage can not inject function for this module, because the function is exists! using jsc.config({inject:{}})"); | |
141 | } | |
142 | ||
143 | var __r_e_p_l_a_c_e__ = {}; | |
144 | module.exports.$$replace$$ = function (name, obj) { | |
145 | function stringify(obj) { | |
146 | if (obj === null) { | |
147 | return 'null'; | |
148 | } | |
149 | if (obj === undefined){ | |
150 | return 'undefined'; | |
151 | } | |
152 | if (!obj && isNaN(obj)){ | |
153 | return 'NaN'; | |
154 | } | |
155 | if (typeof obj === 'string') { | |
156 | return '"' + obj.replace(/"/g, '\\"') + '"'; | |
157 | } | |
158 | if (typeof obj === 'number') { | |
159 | return obj; | |
160 | } | |
161 | if (obj.constructor === Date) { | |
162 | return 'new Date(' + obj.getTime() + ')'; | |
163 | } | |
164 | if (obj.constructor === Function) { | |
165 | return obj.toString(); | |
166 | } | |
167 | if (obj.constructor === RegExp) { | |
168 | return obj.toString(); | |
169 | } | |
170 | var is_array = obj.constructor === Array ? true : false; | |
171 | var res, i; | |
172 | if (is_array) { | |
173 | res = ['[']; | |
174 | for (i = 0; i < obj.length; i++) { | |
175 | res.push(stringify(obj[i])); | |
176 | res.push(','); | |
177 | } | |
178 | if (res[res.length - 1] === ',') { | |
179 | res.pop(); | |
180 | } | |
181 | res.push(']'); | |
182 | } else { | |
183 | res = ['{']; | |
184 | for (i in obj) { | |
185 | res.push(i + ':' + stringify(obj[i])); | |
186 | res.push(','); | |
187 | } | |
188 | if (res[res.length - 1] === ',') | |
189 | res.pop(); | |
190 | res.push('}'); | |
191 | } | |
192 | return res.join(''); | |
193 | } | |
194 | if (!__r_e_p_l_a_c_e__.hasOwnProperty(name)) { | |
195 | __r_e_p_l_a_c_e__[name] = eval(name); | |
196 | } | |
197 | eval(name + "=" + stringify(obj)); | |
198 | }; | |
199 | module.exports.$$reset$$ = function (name) { | |
200 | var script; | |
201 | if (name) { | |
202 | script = 'if(__r_e_p_l_a_c_e__.hasOwnProperty("' + name + '"))' + name + ' = __r_e_p_l_a_c_e__["' + name + '"];'; | |
203 | } else { | |
204 | script = 'for(var i in __r_e_p_l_a_c_e__){eval( i + " = __r_e_p_l_a_c_e__[\'" + i + "\'];");}'; | |
205 | } | |
206 | eval(script); | |
207 | }; | |
208 | module.exports.$$call$$ = module.exports.$$test$$ = function (func, args) { | |
209 | var f, o; | |
210 | if (func.match(/\\./)) { | |
211 | func = func.split("."); | |
212 | f = func[func.length - 1]; | |
213 | func.pop(); | |
214 | o = func.join("."); | |
215 | } else { | |
216 | f = func; | |
217 | o = "this"; | |
218 | } | |
219 | return eval(f + ".apply(" + o + "," + JSON.stringify(args) + ")"); | |
220 | }; | |
221 | module.exports.$$get$$ = function (objstr) { | |
222 | return eval(objstr); | |
223 | }; | |
224 | module.exports._i_n_j_e_c_t_e_d_ = true; | |
225 | })(); | |
226 | } | |
227 |
Line | Hits | Source |
---|---|---|
1 | ||
2 | /** | |
3 | * print detail coverage info in console | |
4 | * @param {Object} _$jscoverage [description] | |
5 | * @param {Object} stats [description] | |
6 | * @param {Number} covlevel [description] | |
7 | */ | |
8 | exports.process = function (_$jscoverage, stats, covlevel) { | |
9 | 1 | var file; |
10 | 1 | var tmp; |
11 | 1 | var source; |
12 | 1 | var lines; |
13 | 1 | var allcovered; |
14 | for (var i in _$jscoverage) { | |
15 | 10 | file = i; |
16 | 10 | tmp = _$jscoverage[i]; |
17 | if (typeof tmp === 'function' || tmp.length === undefined) { | |
18 | 0 | continue; |
19 | } | |
20 | 10 | source = tmp.source; |
21 | 10 | allcovered = true; |
22 | //console.log('[JSCOVERAGE]',file); | |
23 | 10 | console.log('[UNCOVERED CODE]', file); |
24 | 10 | lines = []; |
25 | for (var n = 0, len = source.length; n < len ; n++) { | |
26 | if (tmp[n] === 0) { | |
27 | 40 | lines[n] = 1; |
28 | 40 | allcovered = false; |
29 | } else { | |
30 | 1147 | lines[n] = 0; |
31 | } | |
32 | } | |
33 | if (allcovered) { | |
34 | 6 | console.log(colorful('\t100% covered', 'GREEN')); |
35 | } else { | |
36 | 4 | printCoverageDetail(lines, source); |
37 | } | |
38 | } | |
39 | }; | |
40 | ||
41 | function processLinesMask(lines) { | |
42 | function processLeft3(arr, offset) { | |
43 | 34 | var prev1 = offset - 1; |
44 | 34 | var prev2 = offset - 2; |
45 | 34 | var prev3 = offset - 3; |
46 | if (prev1 < 0) { | |
47 | 0 | return; |
48 | } | |
49 | 34 | arr[prev1] = arr[prev1] === 1 ? arr[prev1] : 2; |
50 | if (prev2 < 0) { | |
51 | 0 | return; |
52 | } | |
53 | 34 | arr[prev2] = arr[prev2] === 1 ? arr[prev2] : 2; |
54 | if (prev3 < 0) { | |
55 | 2 | return; |
56 | } | |
57 | 32 | arr[prev3] = arr[prev3] ? arr[prev3] : 3; |
58 | } | |
59 | function processRight3(arr, offset) { | |
60 | 33 | var len = arr.length; |
61 | 33 | var next1 = offset; |
62 | 33 | var next2 = offset + 1; |
63 | 33 | var next3 = offset + 2; |
64 | if (next1 >= len || arr[next1] === 1) { | |
65 | 0 | return; |
66 | } | |
67 | 33 | arr[next1] = arr[next1] ? arr[next1] : 2; |
68 | if (next2 >= len || arr[next2] === 1) { | |
69 | 12 | return; |
70 | } | |
71 | 21 | arr[next2] = arr[next2] ? arr[next2] : 2; |
72 | if (next3 >= len || arr[next3] === 1) { | |
73 | 7 | return; |
74 | } | |
75 | 14 | arr[next3] = arr[next3] ? arr[next3] : 3; |
76 | } | |
77 | 8 | var offset = 0; |
78 | 8 | var now; |
79 | 8 | var prev = 0; |
80 | while (offset < lines.length) { | |
81 | 763 | now = lines[offset]; |
82 | 763 | now = now !== 1 ? 0 : 1; |
83 | if (now !== prev) { | |
84 | if (now === 1) { | |
85 | 34 | processLeft3(lines, offset); |
86 | } else if (now === 0) { | |
87 | 33 | processRight3(lines, offset); |
88 | } | |
89 | } | |
90 | 763 | prev = now; |
91 | 763 | offset ++; |
92 | } | |
93 | 8 | return lines; |
94 | } | |
95 | /** | |
96 | * printCoverageDetail | |
97 | * @param {Array} lines [true] 1 means no coveraged | |
98 | * @return {} | |
99 | */ | |
100 | function printCoverageDetail(lines, source) { | |
101 | 4 | var len = lines.length; |
102 | 4 | lines = processLinesMask(lines); |
103 | //console.log(lines); | |
104 | for (var i = 1; i < len; i++) { | |
105 | if (lines[i] !== 0) { | |
106 | if (lines[i] === 3) { | |
107 | 21 | console.log('......'); |
108 | } else if (lines[i] === 2) { | |
109 | 68 | echo(i, source[i - 1], false); |
110 | } else { | |
111 | 40 | echo(i, source[i - 1], true); |
112 | } | |
113 | } | |
114 | } | |
115 | function echo(lineNum, str, bool) { | |
116 | 108 | console.log(colorful(lineNum, 'LINENUM') + '|' + colorful(str, bool ? 'YELLOW' : 'GREEN')); |
117 | } | |
118 | } | |
119 | /** | |
120 | * colorful display | |
121 | * @param {} str | |
122 | * @param {} type | |
123 | * @return {} | |
124 | */ | |
125 | function colorful(str, type) { | |
126 | 222 | var head = '\x1B[', foot = '\x1B[0m'; |
127 | 222 | var color = { |
128 | LINENUM : 36, | |
129 | GREEN : 32, | |
130 | YELLOW : 33, | |
131 | RED : 31 | |
132 | }; | |
133 | 222 | return head + color[type] + 'm' + str + foot; |
134 | } |
Line | Hits | Source |
---|---|---|
1 | ||
2 | /** | |
3 | * Module dependencies. | |
4 | */ | |
5 | ||
6 | var fs = require('fs'); | |
7 | var jade = require('jade'); | |
8 | ||
9 | /** | |
10 | * Initialize a new `JsCoverage` reporter. | |
11 | * | |
12 | * @param {Runner} runner | |
13 | * @param {Boolean} output | |
14 | * @api public | |
15 | */ | |
16 | ||
17 | exports.process = function (_$jscoverage, stats, covlevel) { | |
18 | 2 | var result = map(_$jscoverage, stats); |
19 | 1 | var file = __dirname + '/templates/coverage.jade'; |
20 | 1 | var str = fs.readFileSync(file, 'utf8'); |
21 | 1 | var fn = jade.compile(str, { filename: file }); |
22 | ||
23 | 1 | var html = fn({ |
24 | cov: result, | |
25 | coverageClass: function (n) { | |
26 | 23 | n = n / 100; |
27 | if (n >= covlevel.high) { | |
28 | 18 | return 'high'; |
29 | } | |
30 | if (n >= covlevel.middle) { | |
31 | 1 | return 'medium'; |
32 | } | |
33 | if (n >= covlevel.low) { | |
34 | 4 | return 'low'; |
35 | } | |
36 | 0 | return 'terrible'; |
37 | } | |
38 | }); | |
39 | ||
40 | 1 | fs.writeFileSync(process.cwd() + '/covreporter.html', html); |
41 | 1 | console.log('[REPORTER]: ', process.cwd() + '/covreporter.html'); |
42 | }; | |
43 | ||
44 | /** | |
45 | * Map jscoverage data to a JSON structure | |
46 | * suitable for reporting. | |
47 | * | |
48 | * @param {Object} cov | |
49 | * @return {Object} | |
50 | * @api private | |
51 | */ | |
52 | ||
53 | function map(cov, stats) { | |
54 | 2 | var ret = { |
55 | instrumentation: 'jscoverage', | |
56 | sloc: 0, | |
57 | hits: 0, | |
58 | misses: 0, | |
59 | coverage: 0, | |
60 | files: [] | |
61 | }; | |
62 | ||
63 | for (var filename in cov) { | |
64 | 22 | var data = coverage(filename, cov[filename], stats[filename]); |
65 | 21 | ret.files.push(data); |
66 | 21 | ret.hits += data.hits; |
67 | 21 | ret.misses += data.misses; |
68 | 21 | ret.sloc += data.sloc; |
69 | } | |
70 | ||
71 | 1 | ret.files.sort(function(a, b) { |
72 | 31 | return a.filename.localeCompare(b.filename); |
73 | }); | |
74 | ||
75 | if (ret.sloc > 0) { | |
76 | 1 | ret.coverage = (ret.hits / ret.sloc) * 100; |
77 | } | |
78 | ||
79 | 1 | return ret; |
80 | }; | |
81 | ||
82 | /** | |
83 | * Map jscoverage data for a single source file | |
84 | * to a JSON structure suitable for reporting. | |
85 | * | |
86 | * @param {String} filename name of the source file | |
87 | * @param {Object} data jscoverage coverage data | |
88 | * @return {Object} | |
89 | * @api private | |
90 | */ | |
91 | ||
92 | function coverage(filename, data, stats) { | |
93 | 22 | var ret = { |
94 | filename: filename, | |
95 | coverage: stats.coverage * 100, | |
96 | hits: stats.hits, | |
97 | misses: stats.sloc - stats.hits, | |
98 | sloc: stats.sloc, | |
99 | source: {} | |
100 | }; | |
101 | ||
102 | 22 | data.source.forEach(function(line, num){ |
103 | 2592 | num++; |
104 | 2593 | ret.source[num] = { |
105 | source: line, | |
106 | coverage: data[num] === undefined ? '' : data[num], | |
107 | condition: stats.condition[num] ? stats.condition[num] : [] | |
108 | }; | |
109 | }); | |
110 | ||
111 | 21 | console.log(ret); |
112 | ||
113 | 21 | return ret; |
114 | } | |
115 |
Line | Hits | Source |
---|---|---|
1 | var cde = require('./cde'); | |
2 | var a = 1; | |
3 | var b = 2; | |
4 | var c = 3; | |
5 | var d; | |
6 | var e = a > 1 ? 1 : 2; | |
7 | ||
8 | var reset = { | |
9 | abc:function () {} | |
10 | }; | |
11 | ||
12 | function abc() { | |
13 | 1 | var tmp = a + b; |
14 | 1 | var t = 1; |
15 | // test require ok | |
16 | 1 | cde.a(); |
17 | // test switch coverage | |
18 | 1 | testSwitch('first'); |
19 | /* @covignore */ | |
20 | testSwitch('second'); | |
21 | 1 | testSwitch(); |
22 | 1 | return tmp + c; |
23 | } | |
24 | ||
25 | function testSwitch(act) { | |
26 | 3 | var res = [ |
27 | 'a', | |
28 | 'b', | |
29 | 'c' | |
30 | ]; | |
31 | 3 | var tmp; |
32 | switch (act) { | |
33 | case 'first' : | |
34 | 1 | tmp = res[0]; |
35 | 1 | break; |
36 | case 'second' : | |
37 | 1 | tmp = res[1]; |
38 | 1 | break; |
39 | default: | |
40 | 1 | tmp = res.join(','); |
41 | } | |
42 | 3 | return tmp; |
43 | } | |
44 | abc(); | |
45 | exports.abc = abc; | |
46 |
Line | Hits | Source |
---|---|---|
1 | function a(){ | |
2 | 3 | var a = 1; |
3 | 3 | var b = 2; |
4 | if (a || b > a) { | |
5 | 3 | console.log(a); |
6 | } | |
7 | 3 | return a+b; |
8 | } | |
9 | exports.a = a; |
Line | Hits | Source |
---|---|---|
1 | /*! | |
2 | * jscoverage: example.js | |
3 | * Authors : fish <zhengxinlin@gmail.com> (https://github.com/fishbar) | |
4 | * Create : 2014-04-03 15:20:13 | |
5 | * CopyRight 2014 (c) Fish And Other Contributors | |
6 | */ | |
7 | var expect = require('expect.js'); | |
8 | ||
9 | exports.testTryCatch = function (a) { | |
10 | try { | |
11 | 2 | return a.run(); |
12 | } catch (e) { | |
13 | 1 | return 'catch error'; |
14 | } | |
15 | }; | |
16 | ||
17 | exports.testIfElse = function (a, b, c, d) { | |
18 | if (a > 0 && b > 0) { | |
19 | 1 | return 'ab'; |
20 | } else if (c || d) { | |
21 | 1 | return 'cd'; |
22 | } else { | |
23 | 1 | return 'unknow'; |
24 | } | |
25 | }; | |
26 | ||
27 | exports.testCondition = function (a, b ,c) { | |
28 | 3 | return a || b > c ? '1' : '2'; |
29 | }; | |
30 | ||
31 | exports.testWhile = function () { | |
32 | 1 | var a = 0; |
33 | 1 | var res = ''; |
34 | while(a < 2) { | |
35 | 2 | res += 'a'; |
36 | 2 | a ++; |
37 | } | |
38 | 1 | var b = 0; |
39 | do { | |
40 | 2 | res += 'b'; |
41 | 2 | b ++; |
42 | } while (b < 2); | |
43 | 1 | return res; |
44 | }; | |
45 | ||
46 | ||
47 | describe('example.js', function () { | |
48 | 1 | it('test try catch', function () { |
49 | 1 | expect(exports.testTryCatch({})).to.be.match(/catch\ error/); |
50 | 2 | expect(exports.testTryCatch({run: function () {return 'run';}})).to.be('run'); |
51 | }); | |
52 | ||
53 | 1 | it('test if else', function () { |
54 | 1 | expect(exports.testIfElse(1, 0)).to.be('unknow'); |
55 | 1 | expect(exports.testIfElse(1, 1)).to.be('ab'); |
56 | 1 | expect(exports.testIfElse(0, 0, 1, 0)).to.be('cd'); |
57 | }); | |
58 | ||
59 | 1 | it('test condition', function () { |
60 | 1 | expect(exports.testCondition(1)).to.be('1'); |
61 | 1 | expect(exports.testCondition(0, 2, 1)).to.be('1'); |
62 | 1 | expect(exports.testCondition(0, 0, 0)).to.be('2'); |
63 | }); | |
64 | ||
65 | 1 | it('test while', function () { |
66 | 1 | expect(exports.testWhile()).to.be('aabb'); |
67 | }); | |
68 | ||
69 | 1 | it('test switch', function () { |
70 | 1 | expect(exports.testSwitch('a')).to.be('a'); |
71 | 1 | expect(exports.testSwitch('b')).to.be('b'); |
72 | 1 | expect(exports.testSwitch('c')).to.be('c'); |
73 | 1 | expect(exports.testSwitch('0')).to.be('d'); |
74 | }); | |
75 | ||
76 | 1 | it('test for', function () { |
77 | 1 | expect(exports.testFor()).to.be(1); |
78 | }); | |
79 | ||
80 | 1 | it('test binary', function () { |
81 | 1 | expect(exports.testBinary('a')).to.be('a'); |
82 | 1 | expect(exports.testBinary(null, 'b')).to.be('b'); |
83 | 1 | expect(exports.testBinary(null, null, null, 'b')).to.be('b'); |
84 | 1 | expect(exports.testBinary(null, null, 'b')).to.be('b'); |
85 | }); | |
86 | }); | |
87 | ||
88 | exports.testSwitch = function (a) { | |
89 | 4 | var res = null; |
90 | switch (a) { | |
91 | case 'a': | |
92 | 1 | return 'a'; |
93 | case 'b': | |
94 | 1 | return 'b'; |
95 | case 'c': | |
96 | 1 | res = 'c'; |
97 | 1 | break; |
98 | default: | |
99 | 1 | res = 'd'; |
100 | } | |
101 | 2 | return res; |
102 | }; | |
103 | ||
104 | exports.testFor = function () { | |
105 | 1 | var a = 0; |
106 | for (var i = 0; i < 3; i++) { | |
107 | if (i > 1) { | |
108 | 1 | a ++; |
109 | } | |
110 | } | |
111 | 1 | return a; |
112 | }; | |
113 | exports.testBinary = function (a, b, c, d) { | |
114 | 4 | return a || b || c || d; |
115 | }; | |
116 | // anonymous function | |
117 | (function(){ | |
118 | 1 | var a = 1; |
119 | 1 | console.log('this line should covered'); |
120 | })(); |
Line | Hits | Source |
---|---|---|
1 | var patch = require('../lib/patch'); | |
2 | var expect = require('expect.js'); | |
3 | var checkModule = patch._get('checkModule'); | |
4 | ||
5 | describe('patch.js', function () { | |
6 | 1 | describe('checkModule()', function () { |
7 | 1 | it('should return false when native module', function () { |
8 | 1 | expect(checkModule('fs')).to.be(false); |
9 | }); | |
10 | 1 | it('should return false when /node_modules/ module', function () { |
11 | 1 | expect(checkModule('/abc/node_modules/fs')).to.be(false); |
12 | }); | |
13 | 1 | it('should return false when native module', function () { |
14 | 1 | expect(checkModule('fs')).to.be(false); |
15 | }); | |
16 | 1 | it('should return true when ignore no match', function () { |
17 | 1 | expect(checkModule('/abc/def')).to.be(true); |
18 | }); | |
19 | 1 | it('should return true when ignore no match', function () { |
20 | 1 | patch.setCovIgnore([/\/tet\/a.js/]); |
21 | 1 | expect(checkModule('/tet/a.js')).to.be(false); |
22 | }); | |
23 | }); | |
24 | }); |
Line | Hits | Source |
---|---|---|
1 | var expect = require('expect.js'); | |
2 | var testMod = require('../reporter/detail'); | |
3 | describe('exports.processLinesMask', function () { | |
4 | 1 | it('should be ok when test1', function () { |
5 | 1 | var process = testMod._get('processLinesMask'); |
6 | 1 | var input = [0, 0, 0, 1, 1, 0, 0, 1, 0, 0]; |
7 | 1 | var result = [3, 2, 2, 1, 1, 2, 2, 1, 2, 2]; |
8 | 1 | expect(process(input)).to.be.eql(result); |
9 | }); | |
10 | 1 | it('should be ok when test2', function () { |
11 | 1 | var process = testMod._get('processLinesMask'); |
12 | 1 | var input = [0, 0, 1, 1, 0, 0, 1, 0, 1]; |
13 | 1 | var result = [2, 2, 1, 1, 2, 2, 1, 2, 1]; |
14 | 1 | expect(process(input)).to.be.eql(result); |
15 | }); | |
16 | 1 | it('should be ok when test3', function () { |
17 | 1 | var process = testMod._get('processLinesMask'); |
18 | 1 | var input = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]; |
19 | 1 | var result = [2, 2, 1, 2, 2, 3, 0, 0, 0, 3, 2, 2, 1, 2]; |
20 | 1 | expect(process(input)).to.be.eql(result); |
21 | }); | |
22 | 1 | it('should be ok when test4', function () { |
23 | 1 | var process = testMod._get('processLinesMask'); |
24 | 1 | var input = [0]; |
25 | 1 | var result = [0]; |
26 | 1 | expect(process(input)).to.be.eql(result); |
27 | }); | |
28 | ||
29 | 1 | it('should be ok', function () { |
30 | 1 | testMod.process(_$jscoverage, {}, {high: 90, middle: 70, low: 20}); |
31 | }); | |
32 | }); |