Generate LCOV coverage data and post to coveralls
authorDan Vanderkam <danvdk@gmail.com>
Sat, 21 Mar 2015 22:44:31 +0000 (18:44 -0400)
committerDan Vanderkam <danvdk@gmail.com>
Sun, 22 Mar 2015 21:46:49 +0000 (17:46 -0400)
.travis.yml
auto_tests/karma.conf.js
gulpfile.js
package.json
scripts/transform-coverage.js [new file with mode: 0755]

index 5a4bb52..8425aa8 100644 (file)
@@ -2,8 +2,4 @@ language: node_js
 node_js:
   - "0.10"
 
-before_script:
-  - npm install -g bower
-  - bower install
-
 script: "gulp travis"
index 6b673cd..4349239 100644 (file)
@@ -16,13 +16,16 @@ module.exports = function (config) {
         ],
         autoWatch: false,
         singleRun: true,
-        reporters: ['mocha'], // ['spec', 'coverage'],
+        reporters: ['dots', 'coverage'],  // or 'mocha', 'spec'
         preprocessors: {
             'dist/dygraph-combined.dev.js': ['coverage']
         },
         coverageReporter: {
-            type: 'html',
-            dir: 'dist/coverage'
+            dir: 'dist/coverage',
+            reporters: [
+              { type: 'html', subdir: 'report-html' },
+              { type: 'lcovonly', subdir: 'report-lcov' },
+            ]
         },
         browsers: ['PhantomJS'],
         plugins: [
index 3e38b8d..f842bf7 100644 (file)
@@ -98,10 +98,11 @@ gulp.task('create-loader', function() {
 
 gulp.task('create-dev', function() {
   var dest = 'dist';
-  return gulp.src(mergePaths(src.polyfills, src.main, src.plugins, src.devOptions, src.datahandlers))
-    .pipe(plugins.sourcemaps.init())
+  return gulp.src(mergePaths(src.polyfills, src.main, src.plugins, src.devOptions, src.datahandlers), {base: '.'})
+    .pipe(plugins.sourcemaps.init({debug:true}))
     .pipe(plugins.concat('dygraph-combined.dev.js'))
     .pipe(plugins.header(copyright))
+    .pipe(plugins.sourcemaps.write('.'))  // '.' = external sourcemap
     .pipe(gulp.dest(dest));
 });
 
@@ -156,6 +157,13 @@ gulp.task('test', ['concat', 'create-dev'], function(done) {
   }, done);
 });
 
+gulp.task('coveralls', ['test'], plugins.shell.task([
+  './scripts/transform-coverage.js ' +
+      'dist/dygraph-combined.dev.js.map ' +
+      'dist/coverage/report-lcov/lcov.info ' +
+  '| ./node_modules/.bin/coveralls'
+]));
+
 gulp.task('watch', function() {
   gulp.watch('src/**', ['concat']);
 });
@@ -165,5 +173,5 @@ gulp.task('watch-test', function() {
 });
 
 gulp.task('dist', ['gwt-dist', 'bower-dist']);
-gulp.task('travis', ['test']);
+gulp.task('travis', ['test', 'coveralls']);
 gulp.task('default', ['test', 'dist']);
index 1881b1c..397a5f6 100644 (file)
@@ -35,7 +35,7 @@
     "gulp-load-plugins": "^0.8.0",
     "gulp-rename": "^1.2.0",
     "gulp-replace": "^0.5.0",
-    "gulp-shell": "^0.2.11",
+    "gulp-shell": "^0.4.0",
     "gulp-sourcemaps": "^1.3.0",
     "gulp-uglify": "^1.0.2",
     "jshint": "^2.5.10",
     "karma-phantomjs-launcher": "^0.1.4",
     "karma-spec-reporter": "0.0.16",
     "lazypipe": "^0.2.2",
+    "lcov-parse": "0.0.9",
     "mocha": "^2.1.0",
     "obvious-closure-library": "^20140401.0.2",
+    "parse-data-uri": "^0.2.0",
     "phantomjs": "^1.9.7-8",
+    "source-map": "^0.4.2",
     "uglify-js": "^2"
   },
   "scripts": {
diff --git a/scripts/transform-coverage.js b/scripts/transform-coverage.js
new file mode 100755 (executable)
index 0000000..a492f26
--- /dev/null
@@ -0,0 +1,78 @@
+#!/usr/bin/env node
+/**
+ * This script applies a source map to LCOV data. If you have coverage data for
+ * a concatenated file, plus a source map, this will output LCOV data for your
+ * original source files.
+ *
+ * Usage:
+ *
+ *   transform-coverage.js path/to/soure.map path/to/coverage.lcov > out.lcov
+ */
+
+// TODO: make this a command line argument
+var SOURCE = 'src/';  // only report files under this directory
+
+var assert = require('assert'),
+    fs = require('fs'),
+    lcovParse = require('lcov-parse'),
+    parseDataUri = require('parse-data-uri'),
+    sourcemap = require('source-map');
+
+var sourcemapFile = process.argv[2];
+var lcovFile = process.argv[3];
+
+var sourcemapData = fs.readFileSync(sourcemapFile).toString();
+var sourcemap = new sourcemap.SourceMapConsumer(sourcemapData);
+
+lcovParse(lcovFile, function(err, data) {
+  assert(!err);
+  // TODO: 0 --> the correct file
+  var lines = data[0].lines.details;
+
+  var fileToCov = {};  // filename -> { line num -> hits }
+
+  lines.forEach(function(line) {
+    var pos = sourcemap.originalPositionFor({line: line.line, column: 0});
+    if (pos == null) {
+      return;
+    }
+
+    var filename = pos.source;
+
+    // Test coverage of node_modules is never interesting.
+    if (!filename || filename.indexOf('node_modules') >= 0) {
+      return;
+    }
+
+    // Strip paths down to the source root.
+    var base = filename.indexOf(SOURCE);
+    if (base == -1) return;
+    filename = filename.slice(base);
+
+    if (!fileToCov[filename]) fileToCov[filename] = [];
+    fileToCov[filename][pos.line] = line.hit;
+  });
+
+  // Other LCOV fields to translate:
+  // FN:2454
+  // FNF:465
+  // FNH:410
+  // FNDA:1,(anonymous_1)
+  // LF:4570
+  // LH:4002
+  // BRDA:13,1,0,1
+  // BRF:2213
+  // BRH:1684
+
+  // Convert to LCOV format
+  for (var filename in fileToCov) {
+    var cov = fileToCov[filename]
+    console.log('SF:' + filename);
+    for (var i = 0; i < cov.length; i++) {
+      if (cov[i] != null) {
+        console.log('DA:' + i + ',' + cov[i]);
+      }
+    }
+    console.log('end_of_record');
+  }
+});