diff --git a/package.json b/package.json index 19235a829..6818080ff 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "devDependencies": { "chai": "^3.0.0", "sinon": "^1.15.3", - "source-map-fixtures": "^0.1.0", + "source-map-fixtures": "^0.2.0", "standard": "^5.2.1", "tap": "^1.3.4" }, diff --git a/test/fixtures/_generateCoverage.js b/test/fixtures/_generateCoverage.js index b154169b4..d9ef349e4 100644 --- a/test/fixtures/_generateCoverage.js +++ b/test/fixtures/_generateCoverage.js @@ -8,20 +8,20 @@ var path = require('path') var _ = require('lodash') var rimraf = require('rimraf') +var sourceMapFixtures = require('source-map-fixtures') var NYC = require('../../') -// Load the 'branching' source map fixture. -var fixture = require('source-map-fixtures').inline('branching') - -// Prevent pollution from earlier nyc runs. -var tempDirectory = path.join(__dirname, '.nyc_output') -rimraf.sync(tempDirectory) +// Load source map fixtures. +var fixtures = { + bundle: sourceMapFixtures.inline('bundle'), + inline: sourceMapFixtures.inline('branching'), + none: sourceMapFixtures.none('branching') +} // Inject nyc into this process. var nyc = (new NYC({ - cwd: path.join(__dirname, '..', '..'), - tempDirectory: tempDirectory + cwd: path.join(__dirname, '..', '..') })).wrap() // Override the exclude option, source-map-fixtures is inside node_modules but // should not be excluded when generating the coverage report. @@ -29,20 +29,31 @@ nyc.exclude = [] // Require the fixture so nyc can instrument it, then run it so there's code // coverage. -fixture.require().run() - -// Write the coverage file so reports can be loaded. -nyc.writeCoverageFile() +fixtures.bundle.require().branching() +fixtures.inline.require().run() +fixtures.none.require().run() + +// Copy NYC#writeCoverageFile() behavior to get the coverage object, before +// source maps have been applied. +var coverage = global.__coverage__ +if (typeof __coverage__ === 'object') coverage = __coverage__ +if (!coverage) { + console.error('No coverage.') + process.exit(1) +} -var reports = _.values(nyc._loadReports()[0]) -if (reports.length !== 1) { - console.error('Expected 1 report to be generated, got ' + reports.length) +var reports = _.values(coverage) +if (reports.length !== 3) { + console.error('Expected 3 reports to be generated, got ' + reports.length) process.exit(1) } -var coverage = reports[0] -fs.writeFileSync( - path.join(__dirname, 'coverage.js'), - '// Generated using node test/fixtures/_generateCoverage.js\n' + - 'exports[' + JSON.stringify(coverage.path) + '] = ' + JSON.stringify(coverage, null, 2) + '\n') -console.log('Written coverage report.') +var out = fs.createWriteStream(path.join(__dirname, 'coverage.js')) +out.write('// Generated using node test/fixtures/_generateCoverage.js\n') +reports.forEach(function (coverage) { + out.write('exports[' + JSON.stringify(coverage.path) + '] = ' + JSON.stringify(coverage, null, 2) + '\n') +}) +out.end() +out.on('finish', function () { + console.log('Written coverage report.') +}) diff --git a/test/fixtures/coverage.js b/test/fixtures/coverage.js index c8f8ab9ad..d2d653feb 100644 --- a/test/fixtures/coverage.js +++ b/test/fixtures/coverage.js @@ -1,4 +1,215 @@ // Generated using node test/fixtures/_generateCoverage.js +exports["./node_modules/source-map-fixtures/fixtures/bundle-inline.js"] = { + "path": "./node_modules/source-map-fixtures/fixtures/bundle-inline.js", + "s": { + "1": 1, + "2": 1, + "3": 0, + "4": 1, + "5": 0, + "6": 1, + "7": 1, + "8": 0, + "9": 1, + "10": 1, + "11": 1 + }, + "b": { + "1": [ + 0, + 1 + ] + }, + "f": { + "1": 0, + "2": 0, + "3": 1 + }, + "fnMap": { + "1": { + "name": "(anonymous_1)", + "line": 6, + "loc": { + "start": { + "line": 6, + "column": 8 + }, + "end": { + "line": 6, + "column": 20 + } + } + }, + "2": { + "name": "(anonymous_2)", + "line": 10, + "loc": { + "start": { + "line": 10, + "column": 8 + }, + "end": { + "line": 10, + "column": 20 + } + } + }, + "3": { + "name": "(anonymous_3)", + "line": 14, + "loc": { + "start": { + "line": 14, + "column": 8 + }, + "end": { + "line": 14, + "column": 21 + } + } + } + }, + "statementMap": { + "1": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 5, + "column": 3 + } + }, + "2": { + "start": { + "line": 6, + "column": 0 + }, + "end": { + "line": 8, + "column": 2 + } + }, + "3": { + "start": { + "line": 7, + "column": 2 + }, + "end": { + "line": 7, + "column": 51 + } + }, + "4": { + "start": { + "line": 10, + "column": 0 + }, + "end": { + "line": 12, + "column": 2 + } + }, + "5": { + "start": { + "line": 11, + "column": 2 + }, + "end": { + "line": 11, + "column": 12 + } + }, + "6": { + "start": { + "line": 14, + "column": 0 + }, + "end": { + "line": 18, + "column": 2 + } + }, + "7": { + "start": { + "line": 15, + "column": 2 + }, + "end": { + "line": 17, + "column": 3 + } + }, + "8": { + "start": { + "line": 16, + "column": 4 + }, + "end": { + "line": 16, + "column": 16 + } + }, + "9": { + "start": { + "line": 20, + "column": 0 + }, + "end": { + "line": 20, + "column": 22 + } + }, + "10": { + "start": { + "line": 21, + "column": 0 + }, + "end": { + "line": 21, + "column": 19 + } + }, + "11": { + "start": { + "line": 22, + "column": 0 + }, + "end": { + "line": 22, + "column": 19 + } + } + }, + "branchMap": { + "1": { + "line": 15, + "type": "if", + "locations": [ + { + "start": { + "line": 15, + "column": 2 + }, + "end": { + "line": 15, + "column": 2 + } + }, + { + "start": { + "line": 15, + "column": 2 + }, + "end": { + "line": 15, + "column": 2 + } + } + ] + } + } +} exports["./node_modules/source-map-fixtures/fixtures/branching-inline.js"] = { "path": "./node_modules/source-map-fixtures/fixtures/branching-inline.js", "s": { @@ -114,3 +325,118 @@ exports["./node_modules/source-map-fixtures/fixtures/branching-inline.js"] = { } } } +exports["./node_modules/source-map-fixtures/fixtures/branching-none.js"] = { + "path": "./node_modules/source-map-fixtures/fixtures/branching-none.js", + "s": { + "1": 1, + "2": 1, + "3": 1, + "4": 0, + "5": 1 + }, + "b": { + "1": [ + 0, + 1 + ] + }, + "f": { + "1": 1 + }, + "fnMap": { + "1": { + "name": "(anonymous_1)", + "line": 6, + "loc": { + "start": { + "line": 6, + "column": 8 + }, + "end": { + "line": 6, + "column": 21 + } + } + } + }, + "statementMap": { + "1": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 5, + "column": 3 + } + }, + "2": { + "start": { + "line": 6, + "column": 0 + }, + "end": { + "line": 10, + "column": 2 + } + }, + "3": { + "start": { + "line": 7, + "column": 2 + }, + "end": { + "line": 9, + "column": 3 + } + }, + "4": { + "start": { + "line": 8, + "column": 4 + }, + "end": { + "line": 8, + "column": 16 + } + }, + "5": { + "start": { + "line": 11, + "column": 0 + }, + "end": { + "line": 11, + "column": 16 + } + } + }, + "branchMap": { + "1": { + "line": 7, + "type": "if", + "locations": [ + { + "start": { + "line": 7, + "column": 2 + }, + "end": { + "line": 7, + "column": 2 + } + }, + { + "start": { + "line": 7, + "column": 2 + }, + "end": { + "line": 7, + "column": 2 + } + } + ] + } + } +} diff --git a/test/source-map-cache.js b/test/source-map-cache.js index 7e63feb35..5bfc96b46 100644 --- a/test/source-map-cache.js +++ b/test/source-map-cache.js @@ -3,80 +3,111 @@ var _ = require('lodash') var path = require('path') -var fixture = require('source-map-fixtures').inline('branching') -// Coverage for the fixture is stored relative to the root directory. Here -// compute the path to the fixture file relative to the root directory. -var relpath = './' + path.relative(path.join(__dirname, '..'), fixture.file) -// the sourcemap itself remaps the path. -var mappedPath = './' + path.join(path.dirname(relpath), '../src/branching.js') -// Compute the number of lines in the original source, excluding any line break -// at the end of the file. -var maxLine = fixture.sourceContentSync().trimRight().split(/\r?\n/).length +var sourceMapFixtures = require('source-map-fixtures') + +// Load source map fixtures. +var covered = _.mapValues({ + bundle: sourceMapFixtures.inline('bundle'), + inline: sourceMapFixtures.inline('branching'), + none: sourceMapFixtures.none('branching') +}, function (fixture) { + return _.assign({ + // Coverage for the fixture is stored relative to the root directory. Here + // compute the path to the fixture file relative to the root directory. + relpath: './' + path.relative(path.join(__dirname, '..'), fixture.file), + // the sourcemap itself remaps the path. + mappedPath: './' + path.relative(path.join(__dirname, '..'), fixture.sourceFile), + // Compute the number of lines in the original source, excluding any line + // break at the end of the file. + maxLine: fixture.sourceContentSync().trimRight().split(/\r?\n/).length + }, fixture) +}) var SourceMapCache = require('../lib/source-map-cache') var sourceMapCache = new SourceMapCache() -sourceMapCache.add(relpath, fixture.contentSync()) +_.forOwn(covered, function (fixture) { + sourceMapCache.add(fixture.relpath, fixture.contentSync()) +}) var coverage = require('./fixtures/coverage') +var fixture = covered.inline require('chai').should() require('tap').mochaGlobals() describe('source-map-cache', function () { + it('does not rewrite if there is no source map', function () { + var mappedCoverage = sourceMapCache.applySourceMaps(coverage) + mappedCoverage[covered.none.relpath].should.eql(coverage[covered.none.relpath]) + }) + + describe('path', function () { + it('does not rewrite path if the source map has more than one source', function () { + var mappedCoverage = sourceMapCache.applySourceMaps(coverage) + mappedCoverage.should.have.property(covered.bundle.relpath) + mappedCoverage[covered.bundle.relpath].should.not.eql(coverage[covered.bundle.relpath]) + }) + + it('rewrites path if the source map exactly one source', function () { + var mappedCoverage = sourceMapCache.applySourceMaps(_.pick(coverage, fixture.relpath)) + mappedCoverage.should.have.property(fixture.mappedPath) + }) + }) + describe('statements', function () { it('drops statements that have no mapping back to the original source code', function () { var mappedCoverage = sourceMapCache.applySourceMaps(coverage) - Object.keys(mappedCoverage[mappedPath].s) - .should.be.lt(coverage[relpath].s) - Object.keys(mappedCoverage[mappedPath].statementMap).length - .should.equal(Object.keys(mappedCoverage[mappedPath].s).length) + Object.keys(mappedCoverage[fixture.mappedPath].s) + .should.be.lt(coverage[fixture.relpath].s) + Object.keys(mappedCoverage[fixture.mappedPath].statementMap).length + .should.equal(Object.keys(mappedCoverage[fixture.mappedPath].s).length) }) it('maps all statements back to their original loc', function () { var mappedCoverage = sourceMapCache.applySourceMaps(coverage) - var statements = _.values(mappedCoverage[mappedPath].statementMap) + var statements = _.values(mappedCoverage[fixture.mappedPath].statementMap) var maxStatement = _.max(statements, function (s) { return Math.max(s.start.line, s.end.line) }) - Math.max(maxStatement.start.line, maxStatement.end.line).should.be.lte(maxLine) + Math.max(maxStatement.start.line, maxStatement.end.line).should.be.lte(fixture.maxLine) }) }) describe('functions', function () { it('drops functions that have no mapping back to the original source code', function () { var mappedCoverage = sourceMapCache.applySourceMaps(coverage) - Object.keys(mappedCoverage[mappedPath].f) - .should.be.lt(coverage[relpath].f) - Object.keys(mappedCoverage[mappedPath].fnMap).length - .should.equal(Object.keys(mappedCoverage[mappedPath].f).length) + Object.keys(mappedCoverage[fixture.mappedPath].f) + .should.be.lt(coverage[fixture.relpath].f) + Object.keys(mappedCoverage[fixture.mappedPath].fnMap).length + .should.equal(Object.keys(mappedCoverage[fixture.mappedPath].f).length) }) it('maps all functions back to their original loc', function () { var mappedCoverage = sourceMapCache.applySourceMaps(coverage) - var functions = _.values(mappedCoverage[mappedPath].fnMap) + var functions = _.values(mappedCoverage[fixture.mappedPath].fnMap) var maxFunction = _.max(functions, function (f) { return f.line }) - Math.max(maxFunction.line).should.be.lte(maxLine) + Math.max(maxFunction.line).should.be.lte(fixture.maxLine) }) }) describe('branches', function () { it('drops branches that have no mapping back to the original source code', function () { var mappedCoverage = sourceMapCache.applySourceMaps(coverage) - Object.keys(mappedCoverage[mappedPath].b) - .should.be.lt(coverage[relpath].b) - Object.keys(mappedCoverage[mappedPath].branchMap).length - .should.equal(Object.keys(mappedCoverage[mappedPath].b).length) + Object.keys(mappedCoverage[fixture.mappedPath].b) + .should.be.lt(coverage[fixture.relpath].b) + Object.keys(mappedCoverage[fixture.mappedPath].branchMap).length + .should.equal(Object.keys(mappedCoverage[fixture.mappedPath].b).length) }) it('maps all branches back to their original loc', function () { var mappedCoverage = sourceMapCache.applySourceMaps(coverage) - var branches = _.values(mappedCoverage[mappedPath].branchMap) + var branches = _.values(mappedCoverage[fixture.mappedPath].branchMap) var maxBranch = _.max(branches, function (b) { return b.line }) - Math.max(maxBranch.line).should.be.lte(maxLine) + Math.max(maxBranch.line).should.be.lte(fixture.maxLine) }) }) })