Bug:Fix file validation issue
[vnfsdk/refrepo.git] / vnfmarket / src / main / webapp / vnfmarket / node_modules / istanbul / lib / object-utils.js
1 /*
2  Copyright (c) 2012, Yahoo! Inc.  All rights reserved.
3  Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
4  */
5
6 /**
7  * utility methods to process coverage objects. A coverage object has the following
8  * format.
9  *
10  *      {
11  *          "/path/to/file1.js": { file1 coverage },
12  *          "/path/to/file2.js": { file2 coverage }
13  *      }
14  *
15  *  The internals of the file coverage object are intentionally not documented since
16  *  it is not a public interface.
17  *
18  *  *Note:* When a method of this module has the word `File` in it, it will accept
19  *  one of the sub-objects of the main coverage object as an argument. Other
20  *  methods accept the higher level coverage object with multiple keys.
21  *
22  * Works on `node` as well as the browser.
23  *
24  * Usage on nodejs
25  * ---------------
26  *
27  *      var objectUtils = require('istanbul').utils;
28  *
29  * Usage in a browser
30  * ------------------
31  *
32  * Load this file using a `script` tag or other means. This will set `window.coverageUtils`
33  * to this module's exports.
34  *
35  * @class ObjectUtils
36  * @module main
37  * @static
38  */
39 (function (isNode) {
40     /**
41      * adds line coverage information to a file coverage object, reverse-engineering
42      * it from statement coverage. The object passed in is updated in place.
43      *
44      * Note that if line coverage information is already present in the object,
45      * it is not recomputed.
46      *
47      * @method addDerivedInfoForFile
48      * @static
49      * @param {Object} fileCoverage the coverage object for a single file
50      */
51     function addDerivedInfoForFile(fileCoverage) {
52         var statementMap = fileCoverage.statementMap,
53             statements = fileCoverage.s,
54             lineMap;
55
56         if (!fileCoverage.l) {
57             fileCoverage.l = lineMap = {};
58             Object.keys(statements).forEach(function (st) {
59                 var line = statementMap[st].start.line,
60                     count = statements[st],
61                     prevVal = lineMap[line];
62                 if (count === 0 && statementMap[st].skip) { count = 1; }
63                 if (typeof prevVal === 'undefined' || prevVal < count) {
64                     lineMap[line] = count;
65                 }
66             });
67         }
68     }
69     /**
70      * adds line coverage information to all file coverage objects.
71      *
72      * @method addDerivedInfo
73      * @static
74      * @param {Object} coverage the coverage object
75      */
76     function addDerivedInfo(coverage) {
77         Object.keys(coverage).forEach(function (k) {
78             addDerivedInfoForFile(coverage[k]);
79         });
80     }
81     /**
82      * removes line coverage information from all file coverage objects
83      * @method removeDerivedInfo
84      * @static
85      * @param {Object} coverage the coverage object
86      */
87     function removeDerivedInfo(coverage) {
88         Object.keys(coverage).forEach(function (k) {
89             delete coverage[k].l;
90         });
91     }
92
93     function percent(covered, total) {
94         var tmp;
95         if (total > 0) {
96             tmp = 1000 * 100 * covered / total + 5;
97             return Math.floor(tmp / 10) / 100;
98         } else {
99             return 100.00;
100         }
101     }
102
103     function computeSimpleTotals(fileCoverage, property, mapProperty) {
104         var stats = fileCoverage[property],
105             map = mapProperty ? fileCoverage[mapProperty] : null,
106             ret = { total: 0, covered: 0, skipped: 0 };
107
108         Object.keys(stats).forEach(function (key) {
109             var covered = !!stats[key],
110                 skipped = map && map[key].skip;
111             ret.total += 1;
112             if (covered || skipped) {
113                 ret.covered += 1;
114             }
115             if (!covered && skipped) {
116                 ret.skipped += 1;
117             }
118         });
119         ret.pct = percent(ret.covered, ret.total);
120         return ret;
121     }
122
123     function computeBranchTotals(fileCoverage) {
124         var stats = fileCoverage.b,
125             branchMap = fileCoverage.branchMap,
126             ret = { total: 0, covered: 0, skipped: 0 };
127
128         Object.keys(stats).forEach(function (key) {
129             var branches = stats[key],
130                 map = branchMap[key],
131                 covered,
132                 skipped,
133                 i;
134             for (i = 0; i < branches.length; i += 1) {
135                 covered = branches[i] > 0;
136                 skipped = map.locations && map.locations[i] && map.locations[i].skip;
137                 if (covered || skipped) {
138                     ret.covered += 1;
139                 }
140                 if (!covered && skipped) {
141                     ret.skipped += 1;
142                 }
143             }
144             ret.total += branches.length;
145         });
146         ret.pct = percent(ret.covered, ret.total);
147         return ret;
148     }
149     /**
150      * returns a blank summary metrics object. A metrics object has the following
151      * format.
152      *
153      *      {
154      *          lines: lineMetrics,
155      *          statements: statementMetrics,
156      *          functions: functionMetrics,
157      *          branches: branchMetrics
158      *          linesCovered: lineCoveredCount
159      *      }
160      *
161      *  Each individual metric object looks as follows:
162      *
163      *      {
164      *          total: n,
165      *          covered: m,
166      *          pct: percent
167      *      }
168      *
169      * @method blankSummary
170      * @static
171      * @return {Object} a blank metrics object
172      */
173     function blankSummary() {
174         return {
175             lines: {
176                 total: 0,
177                 covered: 0,
178                 skipped: 0,
179                 pct: 'Unknown'
180             },
181             statements: {
182                 total: 0,
183                 covered: 0,
184                 skipped: 0,
185                 pct: 'Unknown'
186             },
187             functions: {
188                 total: 0,
189                 covered: 0,
190                 skipped: 0,
191                 pct: 'Unknown'
192             },
193             branches: {
194                 total: 0,
195                 covered: 0,
196                 skipped: 0,
197                 pct: 'Unknown'
198             },
199             linesCovered: {}
200         };
201     }
202     /**
203      * returns the summary metrics given the coverage object for a single file. See `blankSummary()`
204      * to understand the format of the returned object.
205      *
206      * @method summarizeFileCoverage
207      * @static
208      * @param {Object} fileCoverage the coverage object for a single file.
209      * @return {Object} the summary metrics for the file
210      */
211     function summarizeFileCoverage(fileCoverage) {
212         var ret = blankSummary();
213         addDerivedInfoForFile(fileCoverage);
214         ret.lines = computeSimpleTotals(fileCoverage, 'l');
215         ret.functions = computeSimpleTotals(fileCoverage, 'f', 'fnMap');
216         ret.statements = computeSimpleTotals(fileCoverage, 's', 'statementMap');
217         ret.branches = computeBranchTotals(fileCoverage);
218         ret.linesCovered = fileCoverage.l;
219         return ret;
220     }
221     /**
222      * merges two instances of file coverage objects *for the same file*
223      * such that the execution counts are correct.
224      *
225      * @method mergeFileCoverage
226      * @static
227      * @param {Object} first the first file coverage object for a given file
228      * @param {Object} second the second file coverage object for the same file
229      * @return {Object} an object that is a result of merging the two. Note that
230      *      the input objects are not changed in any way.
231      */
232     function mergeFileCoverage(first, second) {
233         var ret = JSON.parse(JSON.stringify(first)),
234             i;
235
236         delete ret.l; //remove derived info
237
238         Object.keys(second.s).forEach(function (k) {
239             ret.s[k] += second.s[k];
240         });
241         Object.keys(second.f).forEach(function (k) {
242             ret.f[k] += second.f[k];
243         });
244         Object.keys(second.b).forEach(function (k) {
245             var retArray = ret.b[k],
246                 secondArray = second.b[k];
247             for (i = 0; i < retArray.length; i += 1) {
248                 retArray[i] += secondArray[i];
249             }
250         });
251
252         return ret;
253     }
254     /**
255      * merges multiple summary metrics objects by summing up the `totals` and
256      * `covered` fields and recomputing the percentages. This function is generic
257      * and can accept any number of arguments.
258      *
259      * @method mergeSummaryObjects
260      * @static
261      * @param {Object} summary... multiple summary metrics objects
262      * @return {Object} the merged summary metrics
263      */
264     function mergeSummaryObjects() {
265         var ret = blankSummary(),
266             args = Array.prototype.slice.call(arguments),
267             keys = ['lines', 'statements', 'branches', 'functions'],
268             increment = function (obj) {
269                 if (obj) {
270                     keys.forEach(function (key) {
271                         ret[key].total += obj[key].total;
272                         ret[key].covered += obj[key].covered;
273                         ret[key].skipped += obj[key].skipped;
274                     });
275
276                     // keep track of all lines we have coverage for.
277                     Object.keys(obj.linesCovered).forEach(function (key) {
278                         if (!ret.linesCovered[key]) {
279                             ret.linesCovered[key] = obj.linesCovered[key];
280                         } else {
281                             ret.linesCovered[key] += obj.linesCovered[key];
282                         }
283                     });
284                 }
285             };
286         args.forEach(function (arg) {
287             increment(arg);
288         });
289         keys.forEach(function (key) {
290             ret[key].pct = percent(ret[key].covered, ret[key].total);
291         });
292
293         return ret;
294     }
295     /**
296      * returns the coverage summary for a single coverage object. This is
297      * wrapper over `summarizeFileCoverage` and `mergeSummaryObjects` for
298      * the common case of a single coverage object
299      * @method summarizeCoverage
300      * @static
301      * @param {Object} coverage  the coverage object
302      * @return {Object} summary coverage metrics across all files in the coverage object
303      */
304     function summarizeCoverage(coverage) {
305         var fileSummary = [];
306         Object.keys(coverage).forEach(function (key) {
307             fileSummary.push(summarizeFileCoverage(coverage[key]));
308         });
309         return mergeSummaryObjects.apply(null, fileSummary);
310     }
311
312     /**
313      * makes the coverage object generated by this library yuitest_coverage compatible.
314      * Note that this transformation is lossy since the returned object will not have
315      * statement and branch coverage.
316      *
317      * @method toYUICoverage
318      * @static
319      * @param {Object} coverage The `istanbul` coverage object
320      * @return {Object} a coverage object in `yuitest_coverage` format.
321      */
322     function toYUICoverage(coverage) {
323         var ret = {};
324
325         addDerivedInfo(coverage);
326
327         Object.keys(coverage).forEach(function (k) {
328             var fileCoverage = coverage[k],
329                 lines = fileCoverage.l,
330                 functions = fileCoverage.f,
331                 fnMap = fileCoverage.fnMap,
332                 o;
333
334             o = ret[k] = {
335                 lines: {},
336                 calledLines: 0,
337                 coveredLines: 0,
338                 functions: {},
339                 calledFunctions: 0,
340                 coveredFunctions: 0
341             };
342             Object.keys(lines).forEach(function (k) {
343                 o.lines[k] = lines[k];
344                 o.coveredLines += 1;
345                 if (lines[k] > 0) {
346                     o.calledLines += 1;
347                 }
348             });
349             Object.keys(functions).forEach(function (k) {
350                 var name = fnMap[k].name + ':' + fnMap[k].line;
351                 o.functions[name] = functions[k];
352                 o.coveredFunctions += 1;
353                 if (functions[k] > 0) {
354                     o.calledFunctions += 1;
355                 }
356             });
357         });
358         return ret;
359     }
360
361     /**
362      * Creates new file coverage object with incremented hits count
363      * on skipped statements, branches and functions
364      *
365      * @method incrementIgnoredTotals
366      * @static
367      * @param {Object} cov File coverage object
368      * @return {Object} New file coverage object
369      */
370     function incrementIgnoredTotals(cov) {
371         //TODO: This may be slow in the browser and may break in older browsers
372         //      Look into using a library that works in Node and the browser
373         var fileCoverage = JSON.parse(JSON.stringify(cov));
374
375         [
376             {mapKey: 'statementMap', hitsKey: 's'},
377             {mapKey: 'branchMap', hitsKey: 'b'},
378             {mapKey: 'fnMap', hitsKey: 'f'}
379         ].forEach(function (keys) {
380             Object.keys(fileCoverage[keys.mapKey])
381                 .forEach(function (key) {
382                     var map = fileCoverage[keys.mapKey][key];
383                     var hits = fileCoverage[keys.hitsKey];
384
385                     if (keys.mapKey === 'branchMap') {
386                         var locations = map.locations;
387
388                         locations.forEach(function (location, index) {
389                             if (hits[key][index] === 0 && location.skip) {
390                                 hits[key][index] = 1;
391                             }
392                         });
393
394                         return;
395                     }
396
397                     if (hits[key] === 0 && map.skip) {
398                         hits[key] = 1;
399                     }
400                 });
401             });
402
403         return fileCoverage;
404     }
405
406     var exportables = {
407         addDerivedInfo: addDerivedInfo,
408         addDerivedInfoForFile: addDerivedInfoForFile,
409         removeDerivedInfo: removeDerivedInfo,
410         blankSummary: blankSummary,
411         summarizeFileCoverage: summarizeFileCoverage,
412         summarizeCoverage: summarizeCoverage,
413         mergeFileCoverage: mergeFileCoverage,
414         mergeSummaryObjects: mergeSummaryObjects,
415         toYUICoverage: toYUICoverage,
416         incrementIgnoredTotals: incrementIgnoredTotals
417     };
418
419     /* istanbul ignore else: windows */
420     if (isNode) {
421         module.exports = exportables;
422     } else {
423         window.coverageUtils = exportables;
424     }
425 }(typeof module !== 'undefined' && typeof module.exports !== 'undefined' && typeof exports !== 'undefined'));