Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds --all functionality #158

Merged
merged 7 commits into from Nov 28, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -3,3 +3,4 @@ node_modules
.nyc_output
coverage
tmp
.idea
3 changes: 2 additions & 1 deletion lib/commands/report.js
Expand Up @@ -19,7 +19,8 @@ exports.outputReport = async function (argv) {
watermarks: argv.watermarks,
resolve: argv.resolve,
omitRelative: argv.omitRelative,
wrapperLength: argv.wrapperLength
wrapperLength: argv.wrapperLength,
all: argv.all
})
await report.run()
if (argv.checkCoverage) checkCoverages(argv, report)
Expand Down
6 changes: 6 additions & 0 deletions lib/parse-args.js
Expand Up @@ -83,6 +83,12 @@ function buildYargs (withCommands = false) {
type: 'boolean',
describe: 'should temp files be deleted before script execution'
})
.options('all', {
default: false,
type: 'boolean',
describe: 'supplying --all will cause c8 to consider all src files in the current working directory ' +
'when the determining coverage. Respects include/exclude.'
})
.pkgConf('c8')
.config(config)
.demandCommand(1)
Expand Down
76 changes: 69 additions & 7 deletions lib/report.js
Expand Up @@ -3,8 +3,8 @@ const furi = require('furi')
const libCoverage = require('istanbul-lib-coverage')
const libReport = require('istanbul-lib-report')
const reports = require('istanbul-reports')
const { readdirSync, readFileSync } = require('fs')
const { isAbsolute, resolve } = require('path')
const { readdirSync, readFileSync, statSync } = require('fs')
const { isAbsolute, resolve, join, relative, extname, dirname } = require('path')
// TODO: switch back to @c88/v8-coverage once patch is landed.
const v8toIstanbul = require('v8-to-istanbul')
const isCjsEsmBridgeCov = require('./is-cjs-esm-bridge')
Expand All @@ -19,7 +19,8 @@ class Report {
watermarks,
omitRelative,
wrapperLength,
resolve: resolvePaths
resolve: resolvePaths,
all
}) {
this.reporter = reporter
this.reportsDirectory = reportsDirectory
Expand All @@ -33,6 +34,8 @@ class Report {
this.omitRelative = omitRelative
this.sourceMapCache = {}
this.wrapperLength = wrapperLength
this.all = all
this.src = process.cwd()
}

async run () {
Expand All @@ -56,8 +59,8 @@ class Report {
// use-case.
if (this._allCoverageFiles) return this._allCoverageFiles

const map = libCoverage.createCoverageMap()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lost the {} here. Not sure if that is an issue.

const v8ProcessCov = this._getMergedProcessCov()
const map = libCoverage.createCoverageMap({})
const resultCountPerPath = new Map()
const possibleCjsEsmBridges = new Map()

Expand Down Expand Up @@ -94,7 +97,6 @@ class Report {
map.merge(converter.toIstanbul())
}
}

this._allCoverageFiles = map
return this._allCoverageFiles
}
Expand Down Expand Up @@ -127,6 +129,29 @@ class Report {
return sources
}

/**
* //TODO: use https://www.npmjs.com/package/convert-source-map
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm perfectly comfortable with us floating our own version of this method, since we're currently only using one bit of the library (I'd rather not add an additional library).

Did we get this code directly from convert-source-map, because I think we should pull this into a lib/ folder, carrying over the license header from that project.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is okay. The code isn't from covert-source-map, but after I wrote it I noticed we had convert-source-map in the dependency tree of v8-to-istanbul and were using it. So I thought we would be better served by using a function from there, but I don't feel strongly about it. I'll remove the TODO.

* // no need to roll this ourselves this is already in the dep tree
* https://sourcemaps.info/spec.html
* @param {String} compilation target file
* @returns {String} full path to source map file
* @private
*/
_getSourceMapFromFile (file) {
const fileBody = readFileSync(file).toString()
const sourceMapLineRE = /\/\/[#@] ?sourceMappingURL=([^\s'"]+)\s*$/mg
const results = fileBody.match(sourceMapLineRE)
if (results !== null) {
const sourceMap = results[results.length - 1].split('=')[1]
if (isAbsolute(sourceMap)) {
return sourceMap
} else {
const base = dirname(file)
return join(base, sourceMap)
}
}
}

/**
* Returns the merged V8 process coverage.
*
Expand All @@ -139,14 +164,50 @@ class Report {
_getMergedProcessCov () {
const { mergeProcessCovs } = require('@bcoe/v8-coverage')
const v8ProcessCovs = []
const fileIndex = new Map() // Map<string, bool>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scrutinizing this a bit now - this should be a Set

for (const v8ProcessCov of this._loadReports()) {
if (this._isCoverageObject(v8ProcessCov)) {
if (v8ProcessCov['source-map-cache']) {
Object.assign(this.sourceMapCache, v8ProcessCov['source-map-cache'])
}
v8ProcessCovs.push(this._normalizeProcessCov(v8ProcessCov))
v8ProcessCovs.push(this._normalizeProcessCov(v8ProcessCov, fileIndex))
}
}

if (this.all) {
const emptyReports = []
v8ProcessCovs.unshift({
result: emptyReports
})
const workingDir = process.cwd()
this.exclude.globSync(workingDir).forEach((f) => {
const fullPath = resolve(workingDir, f)
if (!fileIndex.has(fullPath)) {
const ext = extname(f)
if (ext === '.js' || ext === '.ts' || ext === '.mjs') {
const stat = statSync(f)
const sourceMap = this._getSourceMapFromFile(f)
if (sourceMap !== undefined) {
this.sourceMapCache[`file://${fullPath}`] = { data: JSON.parse(readFileSync(sourceMap).toString()) }
}
emptyReports.push({
scriptId: 0,
url: resolve(f),
functions: [{
functionName: '(empty-report)',
ranges: [{
startOffset: 0,
endOffset: stat.size,
count: 0
}],
isBlockCoverage: true
}]
})
}
}
})
}

return mergeProcessCovs(v8ProcessCovs)
}

Expand Down Expand Up @@ -196,12 +257,13 @@ class Report {
* @return {v8ProcessCov} Normalized V8 process coverage.
* @private
*/
_normalizeProcessCov (v8ProcessCov) {
_normalizeProcessCov (v8ProcessCov, fileIndex) {
const result = []
for (const v8ScriptCov of v8ProcessCov.result) {
if (/^file:\/\//.test(v8ScriptCov.url)) {
try {
v8ScriptCov.url = furi.toSysPath(v8ScriptCov.url)
fileIndex.set(v8ScriptCov.url, true)
} catch (err) {
console.warn(err)
continue
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -61,4 +61,4 @@
"bin",
"LICENSE"
]
}
}
8 changes: 8 additions & 0 deletions test/fixtures/all/ts-compiled/dir/unloaded.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions test/fixtures/all/ts-compiled/dir/unloaded.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions test/fixtures/all/ts-compiled/dir/unloaded.ts
@@ -0,0 +1,5 @@
export default function Unloaded(){
return 'Never loaded :('
}

console.log("This file shouldn't have been evaluated")
23 changes: 23 additions & 0 deletions test/fixtures/all/ts-compiled/loaded.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions test/fixtures/all/ts-compiled/loaded.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions test/fixtures/all/ts-compiled/loaded.ts
@@ -0,0 +1,19 @@
export default function getString(i){
if (typeof i === 'number'){
if (isNaN(i)){
return 'NaN'
}
else if (i === 0){
return 'zero'
}
else if (i > 0){
return 'positive'
}
else {
return 'negative'
}
}
else {
return 'wat?'
}
}
7 changes: 7 additions & 0 deletions test/fixtures/all/ts-compiled/main.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions test/fixtures/all/ts-compiled/main.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions test/fixtures/all/ts-compiled/main.ts
@@ -0,0 +1,4 @@
import getString from "./loaded"
console.log(getString(0))
console.log(getString(1))
console.log(getString(-1))
5 changes: 5 additions & 0 deletions test/fixtures/all/ts-only/dir/unloaded.ts
@@ -0,0 +1,5 @@
export default function Unloaded(){
return 'Never loaded :('
}

console.log("This file shouldn't have been evaluated")
19 changes: 19 additions & 0 deletions test/fixtures/all/ts-only/loaded.ts
@@ -0,0 +1,19 @@
export default function getString(i){
if (typeof i === 'number'){
if (isNaN(i)){
return 'NaN'
}
else if (i === 0){
return 'zero'
}
else if (i > 0){
return 'positive'
}
else {
return 'negative'
}
}
else {
return 'wat?'
}
}
4 changes: 4 additions & 0 deletions test/fixtures/all/ts-only/main.ts
@@ -0,0 +1,4 @@
import getString from "./loaded"
console.log(getString(0))
console.log(getString(1))
console.log(getString(-1))
5 changes: 5 additions & 0 deletions test/fixtures/all/vanilla/dir/unloaded.js
@@ -0,0 +1,5 @@
module.exports = function Unloaded(){
return 'Never loaded :('
}

console.log("This file shouldn't have been evaluated")
19 changes: 19 additions & 0 deletions test/fixtures/all/vanilla/loaded.js
@@ -0,0 +1,19 @@
module.exports = function getString(i){
if (typeof i === 'number'){
if (isNaN(i)){
return 'NaN'
}
else if (i === 0){
return 'zero'
bcoe marked this conversation as resolved.
Show resolved Hide resolved
}
else if (i > 0){
return 'positive'
}
else {
return 'negative'
}
}
else {
return 'wat?'
}
}
4 changes: 4 additions & 0 deletions test/fixtures/all/vanilla/main.js
@@ -0,0 +1,4 @@
const loaded = require('./loaded.js');
console.log(loaded(0))
console.log(loaded(1))
console.log(loaded(-1))
43 changes: 43 additions & 0 deletions test/integration.js
Expand Up @@ -327,4 +327,47 @@ describe('c8', () => {
output.toString('utf8').should.matchSnapshot()
})
})
describe('--all', () => {
it('reports coverage for unloaded js files as 0 for line, branch and function', () => {
const { output } = spawnSync(nodePath, [
c8Path,
'--temp-directory=tmp/vanilla-all',
'--clean=false',
'--all=true',
'--include=test/fixtures/all/vanilla/**/*.js',
'--exclude=**/*.ts', // add an exclude to avoid default excludes of test/**
nodePath,
require.resolve('./fixtures/all/vanilla/main')
])
output.toString('utf8').should.matchSnapshot()
})

it('reports coverage for unloaded transpiled ts files as 0 for line, branch and function', () => {
const { output } = spawnSync(nodePath, [
c8Path,
'--temp-directory=tmp/all-ts',
'--clean=false',
'--all=true',
'--include=test/fixtures/all/ts-compiled/**/*.ts',
'--exclude="test/*.js"', // add an exclude to avoid default excludes of test/**
nodePath,
require.resolve('./fixtures/all/ts-compiled/main')
])
output.toString('utf8').should.matchSnapshot()
})

it('reports coverage for unloaded ts files as 0 for line, branch and function when using ts-node', () => {
const { output } = spawnSync(nodePath, [
c8Path,
'--temp-directory=tmp/all-ts-node',
'--clean=false',
'--all=true',
'--include=test/fixtures/all/ts-only/**/*.ts',
'--exclude="test/*.js"', // add an exclude to avoid default excludes of test/**
'./node_modules/.bin/ts-node',
require.resolve('./fixtures/all/ts-only/main.ts')
])
output.toString('utf8').should.matchSnapshot()
})
})
})