This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
7.9 KiB
224 lines
7.9 KiB
/* |
|
Copyright 2012-2015, Yahoo Inc. |
|
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. |
|
*/ |
|
var path = require('path'), |
|
fs = require('fs'), |
|
mkdirp = require('mkdirp'), |
|
compareVersions = require('compare-versions'), |
|
matcherFor = require('./file-matcher').matcherFor, |
|
libInstrument = require('istanbul-lib-instrument'), |
|
libCoverage = require('istanbul-lib-coverage'), |
|
libSourceMaps = require('istanbul-lib-source-maps'), |
|
hook = require('istanbul-lib-hook'), |
|
Reporter = require('./reporter'); |
|
|
|
function getCoverFunctions(config, includes, callback) { |
|
|
|
if (!callback && typeof includes === 'function') { |
|
callback = includes; |
|
includes = null; |
|
} |
|
|
|
var includePid = config.instrumentation.includePid(), |
|
reportingDir = path.resolve(config.reporting.dir()), |
|
reporter = new Reporter(config), |
|
excludes = config.instrumentation.excludes(true), |
|
// The coverage variable below should have different value than |
|
// that of the coverage variable actually used by the instrumenter (in this case: __coverage__). |
|
// Otherwise if you run nyc to provide coverage on these files, |
|
// both the actual instrumenter and this file will write to the global coverage variable, |
|
// and provide unexpected coverage result. |
|
coverageVar = '$$coverage$$', |
|
instOpts = config.instrumentation.getInstrumenterOpts(), |
|
sourceMapStore = libSourceMaps.createSourceMapStore({}), |
|
instrumenter, |
|
transformer, |
|
runInContextTransformer, |
|
runInThisContextTransformer, |
|
fakeRequire, |
|
requireTransformer, |
|
reportInitFn, |
|
hookFn, |
|
unhookFn, |
|
coverageFinderFn, |
|
coverageSetterFn, |
|
beforeReportFn, |
|
exitFn; |
|
|
|
instOpts.coverageVariable = coverageVar; |
|
instOpts.sourceMapUrlCallback = function (file, url) { |
|
sourceMapStore.registerURL(file, url); |
|
}; |
|
coverageFinderFn = function () { |
|
return global[coverageVar]; |
|
}; |
|
instrumenter = libInstrument.createInstrumenter(instOpts); |
|
transformer = function (code, options) { |
|
var filename = typeof options === 'string' ? options : options.filename; |
|
return instrumenter.instrumentSync(code, filename); |
|
}; |
|
runInContextTransformer = function (code, options) { |
|
return transformer(code, options); |
|
}; |
|
runInThisContextTransformer = function (code, options) { |
|
return transformer(code, options); |
|
}; |
|
requireTransformer = function (code, options) { |
|
var cov, |
|
ret = transformer(code, options), |
|
filename = typeof options === 'string' ? options : options.filename; |
|
if (fakeRequire) { |
|
cov = coverageFinderFn(); |
|
cov[filename] = instrumenter.lastFileCoverage(); |
|
return 'function x() {}'; |
|
} |
|
return ret; |
|
}; |
|
|
|
coverageSetterFn = function (cov) { |
|
global[coverageVar] = cov; |
|
}; |
|
|
|
reportInitFn = function () { |
|
// set up reporter |
|
mkdirp.sync(reportingDir); //ensure we fail early if we cannot do this |
|
reporter.addAll(config.reporting.reports()); |
|
if (config.reporting.print() !== 'none') { |
|
switch (config.reporting.print()) { |
|
case 'detail': |
|
reporter.add('text'); |
|
break; |
|
case 'both': |
|
reporter.add('text'); |
|
reporter.add('text-summary'); |
|
break; |
|
default: |
|
reporter.add('text-summary'); |
|
break; |
|
} |
|
} |
|
}; |
|
|
|
var disabler; |
|
hookFn = function (matchFn) { |
|
var hookOpts = { |
|
verbose: config.verbose, |
|
extensions: config.instrumentation.extensions(), |
|
coverageVariable: coverageVar |
|
}; |
|
|
|
//initialize the global variable |
|
coverageSetterFn({}); |
|
reportInitFn(); |
|
|
|
if (config.hooks.hookRunInContext()) { |
|
hook.hookRunInContext(matchFn, runInContextTransformer, hookOpts); |
|
} |
|
if (config.hooks.hookRunInThisContext()) { |
|
hook.hookRunInThisContext(matchFn, runInThisContextTransformer, hookOpts); |
|
if(compareVersions(process.versions.node, "6.0.0") === -1) { |
|
disabler = hook.hookRequire(matchFn, requireTransformer, hookOpts); |
|
} |
|
} else { |
|
disabler = hook.hookRequire(matchFn, requireTransformer, hookOpts); |
|
} |
|
}; |
|
|
|
unhookFn = function (matchFn) { |
|
if (disabler) { |
|
disabler(); |
|
} |
|
hook.unhookRunInThisContext(); |
|
hook.unhookRunInContext(); |
|
hook.unloadRequireCache(matchFn); |
|
}; |
|
|
|
beforeReportFn = function (matchFn, cov) { |
|
var pidExt = includePid ? ('-' + process.pid) : '', |
|
file = path.resolve(reportingDir, 'coverage' + pidExt + '.raw.json'), |
|
missingFiles, |
|
finalCoverage = cov; |
|
|
|
if (config.instrumentation.includeAllSources()) { |
|
if (config.verbose) { |
|
console.error("Including all sources not require'd by tests"); |
|
} |
|
missingFiles = []; |
|
// Files that are not touched by code ran by the test runner is manually instrumented, to |
|
// illustrate the missing coverage. |
|
matchFn.files.forEach(function (file) { |
|
if (!cov[file]) { |
|
missingFiles.push(file); |
|
} |
|
}); |
|
|
|
fakeRequire = true; |
|
missingFiles.forEach(function (file) { |
|
try { |
|
require(file); |
|
} catch (ex) { |
|
console.error('Unable to post-instrument: ' + file); |
|
} |
|
}); |
|
} |
|
if (Object.keys(finalCoverage).length >0) { |
|
if (config.verbose) { |
|
console.error('============================================================================='); |
|
console.error('Writing coverage object [' + file + ']'); |
|
console.error('Writing coverage reports at [' + reportingDir + ']'); |
|
console.error('============================================================================='); |
|
} |
|
fs.writeFileSync(file, JSON.stringify(finalCoverage), 'utf8'); |
|
} |
|
return finalCoverage; |
|
}; |
|
|
|
exitFn = function (matchFn, reporterOpts) { |
|
var cov, |
|
coverageMap, |
|
transformed; |
|
|
|
cov = coverageFinderFn() || {}; |
|
cov = beforeReportFn(matchFn, cov); |
|
coverageSetterFn(cov); |
|
|
|
if (!(cov && typeof cov === 'object') || Object.keys(cov).length === 0) { |
|
console.error('No coverage information was collected, exit without writing coverage information'); |
|
return; |
|
} |
|
|
|
coverageMap = libCoverage.createCoverageMap(cov); |
|
transformed = sourceMapStore.transformCoverage(coverageMap); |
|
reporterOpts.sourceFinder = transformed.sourceFinder; |
|
reporter.write(transformed.map, reporterOpts); |
|
sourceMapStore.dispose(); |
|
}; |
|
|
|
excludes.push(path.relative(process.cwd(), path.join(reportingDir, '**', '*'))); |
|
includes = includes || config.instrumentation.extensions().map(function (ext) { |
|
return '**/*' + ext; |
|
}); |
|
var matchConfig = { |
|
root: config.instrumentation.root() || /* istanbul ignore next: untestable */ process.cwd(), |
|
includes: includes, |
|
excludes: excludes |
|
}; |
|
matcherFor(matchConfig, function (err, matchFn) { |
|
/* istanbul ignore if: untestable */ |
|
if (err) { |
|
return callback(err); |
|
} |
|
return callback(null, { |
|
coverageFn: coverageFinderFn, |
|
hookFn: hookFn.bind(null, matchFn), |
|
exitFn: exitFn.bind(null, matchFn, {}), // XXX: reporter opts |
|
unhookFn: unhookFn.bind(null, matchFn) |
|
}); |
|
}); |
|
} |
|
|
|
module.exports = { |
|
getCoverFunctions: getCoverFunctions |
|
}; |
|
|
|
|